如何在iOS 10中使用推送通知
简介
虽然经常被过度使用,但是推送通知确实是一种有效的吸引用户注意力的方式,例如通知他们更新软件或需要采取相应的措施,等等。当前,新的iOS 10系统在推送通知方面也提供了新的支持,例如新消息、优惠和时间表变化等。
在本教程中,你将学习如何在你的iOS应用程序中使用推送通知,同时还向你展示iOS 10的一些新功能。为了开发iOS 10推送通知,你需要使用Xcode 8Beta版本。
起步
启用推送通知在Xcode中是很容易的,请遵循如下几个步骤:
1.启动Xcode创建一个新项目,给它一个唯一的名称和相应的捆绑标识符。
2.创建项目后,转到【Project Settings】界面,选择【Capabilities】选项卡。然后,启动推送通知功能,如下图所示。
【注意】如果你是苹果开发者计划的一位付费会员,你只会看到【Push Notifications】(推送通知)功能项。
接下来,请转到【Developer Account】部分并检查Xcode自动作出的更改。从左边的菜单中选择【Certificates, IDs & Profiles】,然后在【Identifiers】部分选择【App IDs】。找到刚才创建的应用程序名称并选中,以便显示相应的服务列表。
【注意】在【Push Notifications】附近有两个可配置状态。
先不要关闭此屏幕,你将很快返回到这个界面的。
发送通知
在本文中,我将使用Pusher技术(https://github.com/noodlewerk/NWPusher/releases/tag/0.7.0)发送推式通知。其实,你还可以使用其他解决方案,如Houston技术(https://github.com/nomad/houston)。无论采取哪种方式,想发送通知你都需要使用证书。
为了创建一个证书,你需要打开【Keychain Access】访问权限并选择“Keychain Access -> Certificate Assistant -> Request a Certificate from a Certificate Authority”菜单项。
填写如下图所示的表格并单击【Continue】按钮。请确保你刚才的选项保存到磁盘上。
现在,再返回到【Developer Account】屏幕,你可以在【App IDs】处生成用于开发或部署的证书了。选择对应的应用程序后,在底部单击【Edit】命令。然后,在【Push Notifications】部分,单击【Create Certificate for development】。
必要时,你需要上传由钥匙串(Keychain)生成的证书请求,然后点击【Continue】按钮。请参考下图。
你现在已经创建了证书,并可以下载它。为了安装它,请打开下载的文件。
现在,你可以下载并运行Pusher。
【注意】在窗口顶部的组合框中要求选择一个推送证书(Push Certificate)。因为它位于你的钥匙串中,OS X将询问是否允许访问该证书。
上面图的第二个字段(注意那个内容显灰色的下拉列表框控件)需要你输入一个设备令牌,你会在下一步中得到这个数据的。
获取通知
从现在开始,你需要编写代码了。将接收通知的设备必须注册到苹果推送通知服务(Apple Push Notification Service,简称“APNS”)。为此,你需要发送一个在应用程序启动时生成的唯一的令牌。
接下来,请打开文件AppDelegate.swift,然后添加下面的方法。
【注意】此代码包括中使用了最新的Swift 3.0语法;因此,有些语法可能不同于你以前熟悉的2.0格式。
func registerPushNotifications() { DispatchQueue.main.async { let settings = UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil) UIApplication.shared().registerUserNotificationSettings(settings) } }
在这里的设置中,你需要指定应用程序将接收的类型(稍后会介绍)。在应用程序启动时调用此方法。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { registerPushNotifications() return true }
此时,应用程序将自动显示一个弹出窗口,要求用户通过相应的权限来发送通知。
只有在用户同意它时,才能注册并发送该通知。其中,UIApplicationDelegate方法负责处理响应的问题。
func application(_ application: UIApplication, didRegister notificationSettings: UIUserNotificationSettings) { if notificationSettings.types != UIUserNotificationType() { application.registerForRemoteNotifications() } }
在上述代码中,首先检查用户是否已授予权限,然后调用方法来注册远程通知。当请求完成时,后者将调用另一个委托方法。注意到,响应消息中包含一个设备令牌(你可以在调试阶段输出有关内容)。当发送推式通知来标识设备时,你将需要此令牌。
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { let chars = UnsafePointer<CChar>((deviceToken as NSData).bytes) var token = "" for i in 0..<deviceToken.count { token += String(format: "%02.2hhx", arguments: [chars[i]]) } print("Registration succeeded!") print("Token: ", token) }
如果出现了错误,则调用下面的方法。
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) { print("Registration failed!") }
【注意】在启动应用程序时调用registerUserNotificationSettings方法是很重要的,因为用户有可能更改其设置的权限。此外,RegisterForRemoteNotifications方法也很重要,因为有些情况下设备令牌可以更改并且将不再发送通知。
到目前为止,你的上述设置足以能够接收一个简单的通知了。
通知有效载荷
一个应用程序可以通过若干种不同方法来接收通知。这只需要在通知的有效载荷部分指定即可,其中包含应用程序如何通知用户以及你可以使用通知发送的自定义数据。
通知实际上是发送给用户的一个JSON字典,它本身又包含了一个带有aps键的字典。在这第二个词典中,你可以指定有效载荷部分的键/值对。
最常见的数据有:
向用户显示的通知消息。这可以是一个简单的字符串或一个带有如标题、正文等键的字典。
设备收到通知时将播放的声音。它可以是应用程序自定义的声音或系统声音。
应用程序在其图标附近将用作徽章的一个数字。将此设置为0将会删除徽章。
content-available:值为1时将一个无声通知发送给用户。此时,不会播放任何声音或设置任何徽章数字,但它会唤醒应用程序以便可以与服务器通信。
本教程的其余部分中将使用的通知内容如下:
{ "aps": { "alert": { "title":"Hello! :)", "body":"App closed..." }, "badge":1, "sound":"default" } }
应用程序生命周期
把Xcode控制台中显示的设备令牌复制到Pusher。然后,将上一小节中的JSON对象复制到有效载荷文本字段(即下图最下面的文本框)。
现在,你可以试着推送第一次通知。如果设备的屏幕被锁定,应当看起来如下面这样。但是,当用户选择视图时什么也没有。
为了处理通知,你还需要添加另外几个新的方法,有关代码如下:
private func getAlert(notification: [NSObject:AnyObject]) -> (String, String) { let aps = notification["aps"] as? [String:AnyObject] let alert = aps?["alert"] as? [String:AnyObject] let title = alert?["title"] as? String let body = alert?["body"] as? String return (title ?? "-", body ?? "-") }
如果结构是相同的,这段代码将返回收到的通知中的标题和正文内容。
func notificationReceived(notification: [NSObject:AnyObject]) { let viewController = window?.rootViewController let view = viewController as? ViewController view?.addNotification( title: getAlert(notification: notification).0, body: getAlert(notification: notification).1) }
此方法会将一个新行添加到应用程序主视图(参见项目完整的ViewController代码)中的UITableView中。
我通过如下三种情形测试了推送通知的使用情况。
当应用程序关闭时
如果用户从通知中打开应用程序,那么将调用经修改的如下所示的 didFinishLaunchingWithOptions方法:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { // Override point for customization after application launch. application.applicationIconBadgeNumber = 0; // Clear badge when app launches // Check if launched from notification if let notification = launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? [String: AnyObject] { window?.rootViewController?.present(ViewController(), animated: true, completion: nil) notificationReceived(notification: notification) } else { registerPushNotifications() } return true }
上面代码中,在假设用户已经看到通知的情况下清除徽章。然后,检查应用程序是通过图标还是使用通知方式打开的。在第一种情况下,调用registerPushNotifications()方法并继续遵循以前的流程进行。如果是通过通知方式运行的应用程序,那么将调用自定义的notificationReceived方法并添加一个新行。
当应用程序处于前台时
如果用户在使用应用程序,即应用程序正处在前台,那么可以使用下列方法来处理通知。此方法将把通知添加到tableView视图中:
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) { notificationReceived(notification: userInfo) }
【注意】在这种情况下,通知是不会播放声音。
当应用程序处于后台时
在这种情况下,我添加了一个方法来清除徽章编号。通知的处理方式与应用程序处于前台时一样。
func applicationWillEnterForeground(_ application: UIApplication) { application.applicationIconBadgeNumber = 0; // Clear badge when app is or resumed }
最后,表格中将显示对应于所有通知信息的一共三行内容;请参考下面的图形。