為了接收用戶反饋,很多iOS應用都會在設置頁面中,加入發送郵件功能——尤其當應用是由個人開發者開發時。當然iOS中郵件的發送方式有很多種,有體驗相對較差openURL
跳轉方式,也有調用其他第三方庫等辦法。
不過較常用且方便的,還是如下圖(應用為潮汐),調用系統的MFMailComposeViewController
視圖在應用內完成郵件發送,并返回應用。
下面就詳解下這種方式的實現步驟。
一、建立靜態列表
首先,拖一個Table View Controller
到main.storyboard
中,并選中Table View
在右側屬性面板中將其設置為靜態列表Static Cells
。
為了演示方便這里就先創建一個Section
,其中有兩行Cell
。兩個Cell
的Style都設置為Basic,并將Title
修改如下。
下一步是建立這個Table View
的Controller
。新建一個Cocoa Touch Class
文件,并選擇Subclass of UITableViewController
。
接著在右邊工具欄面板中為其設置好Custom Class。由于這里暫時用不到這個UITableViewController
類里的內容,可以把他們都注釋掉或刪掉。接著在其中重寫一個tableView
點選的函數:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath){
if indexPath.section == 0 && indexPath.row == 0 {
print("給應用評分")
}
if indexPath.section == 0 && indexPath.row == 1 {
print("意見反饋")
}
}
在模擬器中運行,點按Cell,檢查output區中print
的內容是否正常,然后就可以進入下一步。
二、MFMailComposeViewController
處理完UITableViewController
以后,就可以開始調用郵件視圖了。不過先不急著寫代碼,首先需要導入框架MessageUI.framework
。在項目設置Build Phases的Link Binary With Libraries中添加MessageUI.framework
。
然后在Controller里導入頭文件import MessageUI
。并給Controller加上MFMailComposeViewControllerDelegate
協議。
上述步驟搞定后,就可以愉快地寫代碼了。首先先寫個函數,來配置發郵件的視窗。
func configuredMailComposeViewController() -> MFMailComposeViewController {
let mailComposeVC = MFMailComposeViewController()
mailComposeVC.mailComposeDelegate = self
//設置郵件地址、主題及正文
mailComposeVC.setToRecipients(["<你的郵箱地址>"])
mailComposeVC.setSubject("<郵件主題>")
mailComposeVC.setMessageBody("<郵件正文>", isHTML: false)
return mailComposeVC
}
鑒于這種發送郵件的方式,要求用戶已經在設備上至少添加有一個郵箱,所以對沒有設置郵箱的用戶,還應予以提示。因此這里再寫一個函數,來配置針對未設置郵箱用戶的彈窗提醒。
func showSendMailErrorAlert() {
let sendMailErrorAlert = UIAlertController(title: "無法發送郵件", message: "您的設備尚未設置郵箱,請在“郵件”應用中設置后再嘗試發送。", preferredStyle: .Alert)
sendMailErrorAlert.addAction(UIAlertAction(title: "確定", style: .Default) { _ in })
self.presentViewController(sendMailErrorAlert, animated: true){}
}
搞定這倆函數后,就可以在之前的tableView
函數中調用兩者了。
if indexPath.section == 0 && indexPath.row == 1 {
print("意見反饋")
if MFMailComposeViewController.canSendMail() {
//注意這個實例要寫在if block里,否則無法發送郵件時會出現兩次提示彈窗(一次是系統的)
let mailComposeViewController = configuredMailComposeViewController()
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
} else {
self.showSendMailErrorAlert()
}
}
最后,寫上dismiss
郵件視窗的函數,就大功告成了。
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
switch result.rawValue {
case MFMailComposeResultCancelled.rawValue:
print("取消發送")
case MFMailComposeResultSent.rawValue:
print("發送成功")
default:
break
}
self.dismissViewControllerAnimated(true, completion: nil)
}
三、加入設備及應用信息
為了獲得更加準確的反饋信息,可以在郵件正文里加入反饋者的設備及應用信息。那怎樣使用swift獲得設備信息呢?可以如下通過UIDevice
取得。
//獲取設備名稱
let deviceName = UIDevice.currentDevice().name
//獲取系統版本號
let systemVersion = UIDevice.currentDevice().systemVersion
//獲取設備的型號
let deviceModel = UIDevice.currentDevice().model
//獲取設備唯一標識符
let deviceUUID = UIDevice.currentDevice().identifierForVendor?.UUIDString
這里的設備型號deviceModel
只能獲知設備的簡單區分(如是iPhone還是iPad),如果需要詳細的iOS設備信息,還需要寫一個UIDevice
的擴展。
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
}
}
}
//調用
let modelName = UIDevice.currentDevice().modelName
獲取這些設備信息后,就可以在郵件正文中加入它們了,比如:
mailComposeVC.setMessageBody("\\\\n\\\\n\\\\n系統版本:\\\\(systemVersion)\\\\n設備型號:\\\\(modelName)", isHTML: false)
同理,也可以獲得應用的相關信息。
let infoDic = NSBundle.mainBundle().infoDictionary
// 獲取App的版本號
let appVersion = infoDic?["CFBundleShortVersionString"]
// 獲取App的build版本
let appBuildVersion = infoDic?["CFBundleVersion"]
// 獲取App的名稱
let appName = infoDic?["CFBundleDisplayName"]
到這里,一個調用MFMailComposeViewController
的iOS郵件反饋就基本寫完了。運行的時候,要注意用虛擬器的話可能會報錯,測試需要真機環境。效果如下。