為了接收用戶反饋,很多iOS應(yīng)用都會(huì)在設(shè)置頁(yè)面中,加入發(fā)送郵件功能——尤其當(dāng)應(yīng)用是由個(gè)人開發(fā)者開發(fā)時(shí)。當(dāng)然iOS中郵件的發(fā)送方式有很多種,有體驗(yàn)相對(duì)較差openURL
跳轉(zhuǎn)方式,也有調(diào)用其他第三方庫(kù)等辦法。
不過(guò)較常用且方便的,還是如下圖(應(yīng)用為潮汐),調(diào)用系統(tǒng)的MFMailComposeViewController
視圖在應(yīng)用內(nèi)完成郵件發(fā)送,并返回應(yīng)用。
下面就詳解下這種方式的實(shí)現(xiàn)步驟。
一、建立靜態(tài)列表
首先,拖一個(gè)Table View Controller
到main.storyboard
中,并選中Table View
在右側(cè)屬性面板中將其設(shè)置為靜態(tài)列表Static Cells
。
為了演示方便這里就先創(chuàng)建一個(gè)Section
,其中有兩行Cell
。兩個(gè)Cell
的Style都設(shè)置為Basic,并將Title
修改如下。
下一步是建立這個(gè)Table View
的Controller
。新建一個(gè)Cocoa Touch Class
文件,并選擇Subclass of UITableViewController
。
接著在右邊工具欄面板中為其設(shè)置好Custom Class。由于這里暫時(shí)用不到這個(gè)UITableViewController
類里的內(nèi)容,可以把他們都注釋掉或刪掉。接著在其中重寫一個(gè)tableView
點(diǎn)選的函數(shù):
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
if indexPath.section == 0 && indexPath.row == 0 {
print("給應(yīng)用評(píng)分")
}
if indexPath.section == 0 && indexPath.row == 1 {
print("意見反饋")
}
}
在模擬器中運(yùn)行,點(diǎn)按Cell,檢查output區(qū)中print
的內(nèi)容是否正常,然后就可以進(jìn)入下一步。
二、MFMailComposeViewController
處理完UITableViewController
以后,就可以開始調(diào)用郵件視圖了。不過(guò)先不急著寫代碼,首先需要導(dǎo)入框架MessageUI.framework
。在項(xiàng)目設(shè)置Build Phases的Link Binary With Libraries中添加MessageUI.framework
。
然后在Controller里導(dǎo)入頭文件import MessageUI
。并給Controller加上MFMailComposeViewControllerDelegate
協(xié)議。
上述步驟搞定后,就可以愉快地寫代碼了。首先先寫個(gè)函數(shù),來(lái)配置發(fā)郵件的視窗。
func configuredMailComposeViewController() -> MFMailComposeViewController {
let mailComposeVC = MFMailComposeViewController()
mailComposeVC.mailComposeDelegate = self
//設(shè)置郵件地址、主題及正文
mailComposeVC.setToRecipients(["<你的郵箱地址>"])
mailComposeVC.setSubject("<郵件主題>")
mailComposeVC.setMessageBody("<郵件正文>", isHTML: false)
return mailComposeVC
}
鑒于這種發(fā)送郵件的方式,要求用戶已經(jīng)在設(shè)備上至少添加有一個(gè)郵箱,所以對(duì)沒有設(shè)置郵箱的用戶,還應(yīng)予以提示。因此這里再寫一個(gè)函數(shù),來(lái)配置針對(duì)未設(shè)置郵箱用戶的彈窗提醒。
func showSendMailErrorAlert() {
let sendMailErrorAlert = UIAlertController(title: "無(wú)法發(fā)送郵件", message: "您的設(shè)備尚未設(shè)置郵箱,請(qǐng)?jiān)凇班]件”應(yīng)用中設(shè)置后再嘗試發(fā)送。", preferredStyle: .Alert)
sendMailErrorAlert.addAction(UIAlertAction(title: "確定", style: .Default) { _ in })
self.presentViewController(sendMailErrorAlert, animated: true){}
}
搞定這倆函數(shù)后,就可以在之前的tableView
函數(shù)中調(diào)用兩者了。
if indexPath.section == 0 && indexPath.row == 1 {
print("意見反饋")
if MFMailComposeViewController.canSendMail() {
//注意這個(gè)實(shí)例要寫在if block里,否則無(wú)法發(fā)送郵件時(shí)會(huì)出現(xiàn)兩次提示彈窗(一次是系統(tǒng)的)
let mailComposeViewController = configuredMailComposeViewController()
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
} else {
self.showSendMailErrorAlert()
}
}
最后,寫上dismiss
郵件視窗的函數(shù),就大功告成了。
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
switch result.rawValue {
case MFMailComposeResultCancelled.rawValue:
print("取消發(fā)送")
case MFMailComposeResultSent.rawValue:
print("發(fā)送成功")
default:
break
}
self.dismissViewControllerAnimated(true, completion: nil)
}
三、加入設(shè)備及應(yīng)用信息
為了獲得更加準(zhǔn)確的反饋信息,可以在郵件正文里加入反饋者的設(shè)備及應(yīng)用信息。那怎樣使用swift獲得設(shè)備信息呢?可以如下通過(guò)UIDevice
取得。
//獲取設(shè)備名稱
let deviceName = UIDevice.currentDevice().name
//獲取系統(tǒng)版本號(hào)
let systemVersion = UIDevice.currentDevice().systemVersion
//獲取設(shè)備的型號(hào)
let deviceModel = UIDevice.currentDevice().model
//獲取設(shè)備唯一標(biāo)識(shí)符
let deviceUUID = UIDevice.currentDevice().identifierForVendor?.UUIDString
這里的設(shè)備型號(hào)deviceModel
只能獲知設(shè)備的簡(jiǎn)單區(qū)分(如是iPhone還是iPad),如果需要詳細(xì)的iOS設(shè)備信息,還需要寫一個(gè)UIDevice
的擴(kuò)展。
public extension UIDevice {
var modelName: String {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
let identifier = machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8 where value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
switch identifier {
case "iPod5,1": return "iPod Touch 5"
case "iPod7,1": return "iPod Touch 6"
case "iPhone3,1", "iPhone3,2", "iPhone3,3": return "iPhone 4"
case "iPhone4,1": return "iPhone 4s"
case "iPhone5,1", "iPhone5,2": return "iPhone 5"
case "iPhone5,3", "iPhone5,4": return "iPhone 5c"
case "iPhone6,1", "iPhone6,2": return "iPhone 5s"
case "iPhone7,2": return "iPhone 6"
case "iPhone7,1": return "iPhone 6 Plus"
case "iPhone8,1": return "iPhone 6s"
case "iPhone8,2": return "iPhone 6s Plus"
case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return "iPad 2"
case "iPad3,1", "iPad3,2", "iPad3,3": return "iPad 3"
case "iPad3,4", "iPad3,5", "iPad3,6": return "iPad 4"
case "iPad4,1", "iPad4,2", "iPad4,3": return "iPad Air"
case "iPad5,3", "iPad5,4": return "iPad Air 2"
case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad Mini"
case "iPad4,4", "iPad4,5", "iPad4,6": return "iPad Mini 2"
case "iPad4,7", "iPad4,8", "iPad4,9": return "iPad Mini 3"
case "iPad5,1", "iPad5,2": return "iPad Mini 4"
case "iPad6,7", "iPad6,8": return "iPad Pro"
case "AppleTV5,3": return "Apple TV"
case "i386", "x86_64": return "Simulator"
default: return identifier
}
}
}
//調(diào)用
let modelName = UIDevice.currentDevice().modelName
獲取這些設(shè)備信息后,就可以在郵件正文中加入它們了,比如:
mailComposeVC.setMessageBody("\\\\n\\\\n\\\\n系統(tǒng)版本:\\\\(systemVersion)\\\\n設(shè)備型號(hào):\\\\(modelName)", isHTML: false)
同理,也可以獲得應(yīng)用的相關(guān)信息。
let infoDic = NSBundle.mainBundle().infoDictionary
// 獲取App的版本號(hào)
let appVersion = infoDic?["CFBundleShortVersionString"]
// 獲取App的build版本
let appBuildVersion = infoDic?["CFBundleVersion"]
// 獲取App的名稱
let appName = infoDic?["CFBundleDisplayName"]
到這里,一個(gè)調(diào)用MFMailComposeViewController
的iOS郵件反饋就基本寫完了。運(yùn)行的時(shí)候,要注意用虛擬器的話可能會(huì)報(bào)錯(cuò),測(cè)試需要真機(jī)環(huán)境。效果如下。