iOS常用功能(打电话、发短信、发邮件)

在App开发中,一般都会用到给联系人打电话、发短信、发邮件等小功能,比如,在一个企业内部的app中,要找到某个部门的同事,可以直接找到联系方式。在用户点击手机号码时候就自动拨号,或者发短信。公司工作交流一般都是接收邮件的方式,那么就可以直接发送邮件。

打电话

打电话功能目前可以使用的有三种方式。

UIWebView

使用UIWebView方式拨打电话时,会提示一个Alert方式提示你是否呼
叫。

  • 创建一个UIWebView
  • 添加到UIView中
  • 请求一个URL
1
2
3
let webView = UIWebView()
self.view.addSubview(webView)
webView.loadRequest(NSURLRequest(URL: NSURL(string: "tel://\(phone)")!))

这里使用了Swift字符串拼接。phone 就是你所需要拨打的电话号码。

UIWebView的优缺点

优点

拨打电话结束后,仍然会停留在App中。

缺点

UIWebView 很容易就造成内存泄露。

WKWebView

苹果推出了一个新的类WKWebView替换UIWebView
想当然的以为UIWebView能支持打电话,那么WKWebView,也可以支持的。
但在iphone6s 手机中测试 不支持打电话。

UIApplication

可以使用UIApplicationfunc openURL(url: NSURL) -> Bool方法进行打电话

tel

  • 使用tel 协议方式拨打电话时,直接就进行呼叫了。
  • 在iPhone6s plus iOS9.3.4 中测试发现电话结束后,会回到App中。
1
UIApplication.sharedApplication().openURL(NSURL(string: "tel://\(phone)")!)

判断是否支持打电话

1
2
3
4
5
6
7
guard let url = NSURL(string: "tel://\(phone)") else {
return
}
if UIApplication.sharedApplication().canOpenURL(url) {
UIApplication.sharedApplication().openURL(url)
}

模拟器会提示:This app is not allowed to query for scheme tel

telprompt

  • telprompt 协议方式拨打电话时,会提示一个Alert方式提示你是否呼叫。
  • 但是telprompt是一个私有协议,如果需要上AppStore那么就可能被拒绝。
1
UIApplication.sharedApplication().openURL(NSURL(string: "telprompt://\(phone)")!)

判断是否支持打电话

1
2
3
4
5
6
7
guard let url = NSURL(string: "telprompt://\(phone)") else {
return
}
if UIApplication.sharedApplication().canOpenURL(url) {
UIApplication.sharedApplication().openURL(url)
}

模拟器会提示:This app is not allowed to query for scheme telprompt

结论

当使用tel协议会回到App中,那么使用这种方式就是最佳实践。

发邮件

UIApplication

使用URLSchema 协议mailto时,会直接跳转到发送邮件的app去。所以发送结束后,不会停留在原来的app中。
iOS9右上角加入了返回到上一个app中,可以放回之前的app中。

1
UIApplication.sharedApplication().openURL(NSURL(string: "mailto://\(email)")!)

判断是否支持发送邮件

先对NSURL进行处理,然后再判断能否打开邮件。

1
2
3
4
5
6
7
guard let url = NSURL(string: "mailto://\(email)") else {
return
}
if UIApplication.sharedApplication().canOpenURL(url) {
UIApplication.sharedApplication().openURL(url)
}

模拟器会提示:This app is not allowed to query for scheme mailto

MFMailComposeViewController

要让使用MFMailComposeViewController发送邮件,稍微麻烦一点。

  • 导入MessageUI
  • 创建MFMailComposeViewController
  • 显示MFMailComposeViewController
1
2
3
4
5
6
7
8
if !MFMailComposeViewController.canSendMail() {
return
}
let mailComposeViewController = MFMailComposeViewController()
mailComposeViewController.mailComposeDelegate = self
mailComposeViewController.setToRecipients([email])
self.presentViewController(mailComposeViewController, animated: true, completion: nil)

判断是否支持发送邮件

因为发送邮件是调用的系统邮件app。 可能用户并没有使用过系统邮件app。

1
class func canSendMail() -> Bool

设置代理

设置代理就可以对邮件发送的结果进行相应的处理、以及退出发送邮件界面,回到刚才的界面。

1
mailComposeViewController.mailComposeDelegate = self

需要实现该协议。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
extension ProfileViewController: MFMailComposeViewControllerDelegate {
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
controller.dismissViewControllerAnimated(true) {
switch result {
case MFMailComposeResultCancelled:
self.alert("邮件发送取消.")
break
case MFMailComposeResultSent:
self.alert("邮件发送成功.")
break
case MFMailComposeResultFailed:
self.alert("邮件发送失败.")
break
case MFMailComposeResultSaved:
self.alert("邮件已保存草稿")
break
default:
break
}
}
}
}

alert方法

因为多个地方都用到了弹框,所以抽取出来方法。

1
2
3
4
5
private func alert(message: String) {
let alertController = UIAlertController(title: "提示", message: message, preferredStyle: .Alert)
alertController.addAction(UIAlertAction(title: "好的", style: .Cancel, handler: nil))
self.presentViewController(alertController, animated: true, completion: nil)
}

更多

也支持收件人、抄送人、主题、内容、附件等功能,详情请看MFMailComposeViewController

1
2
3
4
5
6
7
8
9
10
// 主题
func setSubject(subject: String)
// 抄送人
func setCcRecipients(ccRecipients: [String]?)
// 内容
func setMessageBody(body: String, isHTML: Bool)
// 附件
func addAttachmentData(attachment: NSData, mimeType: String, fileName filename: String)

发短信

UIApplication

使用URLSchema 协议sms时,会直接跳转到发送短信的app去。所以发送结束后,不会停留在原来的app中。
iOS9右上角加入了返回到上一个app中。

1
UIApplication.sharedApplication().openURL(NSURL(string: "sms://\(phone)")!)

判断是否支持发送短信

1
2
3
4
5
6
7
guard let url = NSURL(string: "sms://\(phone)") else {
return
}
if UIApplication.sharedApplication().canOpenURL(url) {
UIApplication.sharedApplication().openURL(url)
}

模拟器会提示:
This app is not allowed to query for scheme sms

MFMessageComposeViewController

要让使用MFMessageComposeViewController发送短信。跟发送邮件一样,也稍微麻烦一点。

  • 导入MessageUI
  • 创建MFMessageComposeViewController
  • 显示MFMessageComposeViewController
1
2
3
4
5
6
7
if !MFMessageComposeViewController.canSendText() {
return
}
let messageComposeViewController = MFMessageComposeViewController()
messageComposeViewController.messageComposeDelegate = self
messageComposeViewController.recipients = [phone]
self.presentViewController(messageComposeViewController, animated: true, completion: nil)

判断是否支持发送短信

是否class func canSendText() -> Bool进行判断是否可以发送短信。

设置短信接收者

recipients 是一个字符串数组对象,可以设置多个。

1
messageComposeViewController.recipients = [phone]

设置代理

设置代理就可以对短信发送的结果进行相应的处理、以及退出发送短信界面,回到刚才的界面。

1
mailComposeViewController.mailComposeDelegate = self

需要实现该协议。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
extension ProfileViewController: MFMessageComposeViewControllerDelegate {
func messageComposeViewController(controller: MFMessageComposeViewController, didFinishWithResult result: MessageComposeResult) {
controller.dismissViewControllerAnimated(true) {
switch result {
case MessageComposeResultCancelled:
self.alert("短信发送取消.")
break
case MessageComposeResultFailed:
self.alert("短信发送失败.")
break
case MessageComposeResultSent:
self.alert("消息发送成功.")
break
default:
break
}
}
}
}

更多

还支持主题、内容、附件等功能。详细可以查看MFMessageComposeViewController类。

1
2
3
4
5
6
7
8
// 主题
public var subject: String?
// 内容
public var body: String?
// 附件
var attachments: [[NSObject : AnyObject]]? { get }

代码优化

抽取方法

会发现文中多处出现了UIApplication的使用仅仅是一个NSURLString不相同而已。所以可以重构抽取出一个方法。

  • 新增方法private func openApp(URLSchema: String)
1
2
3
4
5
6
7
8
9
private func openApp(URLSchema: String) {
guard let url = NSURL(string: URLSchema) else {
return
}
if UIApplication.sharedApplication().canOpenURL(url) {
UIApplication.sharedApplication().openURL(url)
}
}
  • 重构打电话
1
2
self.openApp("tel://\(phone)")
self.openApp("telprompt://\(phone)")
  • 重构发邮件
1
self.openApp("mailto://\(email)")
  • 重构发短信
1
self.openApp("sms://\(phone)")

更进一步

传递URLSchema时候很容易就拼写出错了。那么这个时候就可以定义一些常量。

新增URLSchema结构体

1
2
3
4
5
6
struct URLSchema {
static let sms = "sms://"
static let tel = "tel://"
static let telprompt = "telprompt://"
static let mailto = "mailto://"
}
1
2
3
4
5
6
7
8
9
// 打电话
self.openApp(URLSchema.tel + phone)
self.openApp(URLSchema.telprompt + phone)
// 发短信
self.openApp(URLSchema.sms + phone)
// 发邮件
self.openApp(URLSchema.mailto + email)

导航栏样式

TODO

MessageUI

实际上在MessageUI库中就只有两个类MFMailComposeViewControllerMFMessageComposeViewController

环境

  • iOS 8+
  • Xcode7.3
  • Swift2.2

在使用Xcode8 beta时 不能再iPhone6s plus 9.3.4上面运行,所以又回到了Xcode7.3。
等9月份Xcode8 正式版本推出在升级到Swift3。

源码

源码地址:
LucasLee

Demo界面:
Demo界面

坚持原创技术分享,您的支持将鼓励我继续创作!