iOS 10 UserNotifications 框架解析
Posted ZH952016281
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS 10 UserNotifications 框架解析相关的知识,希望对你有一定的参考价值。
ios 10 中以前杂乱的和通知相关的 API 都被统一了,现在开发者可以使用独立的 UserNotifications.framework 来集中管理和使用 iOS 系统中通知的功能。在此基础上,Apple 还增加了撤回单条通知,更新已展示通知,中途修改通知内容,在通知中展示图片视频,自定义通知 UI 等一系列新功能,非常强大。
对于开发者来说,相较于之前版本,iOS 10 提供了一套非常易用的通知处理接口,是 SDK 的一次重大重构。而之前的绝大部分通知相关 API 都已经被标为弃用 (deprecated)。
这篇文章将首先回顾一下 Notification 的发展历史和现状,然后通过一些例子来展示 iOS 10 SDK 中相应的使用方式,来说明新 SDK 中通知可以做的事情以及它们的使用方式。
您可以在 WWDC 16 的 Introduction to Notifications 和 Advanced Notifications 这两个 Session 中找到详细信息;另外也不要忘了参照 UserNotifications 的官方文档以及本文的实例项目 UserNotificationDemo。
Notification 历史和现状
碎片化时间是移动设备用户在使用应用时的一大特点,用户希望随时拿起手机就能查看资讯,处理事务,而通知可以在重要的事件和信息发生时提醒用户。完美的通知展示可以很好地帮助用户使用应用,体现出应用的价值,进而有很大可能将用户带回应用,提高活跃度。正因如此,不论是 Apple 还是第三方开发者们,都很重视通知相关的开发工作,而通知也成为了很多应用的必备功能,开发者们都希望通知能带来更好地体验和更多的用户。
但是理想的丰满并不能弥补现实的骨感。自从在 iOS 3 引入 Push Notification 后,之后几乎每个版本 Apple 都在加强这方面的功能。我们可以回顾一下整个历程和相关的主要 API:
-
iOS 3 - 引入推送通知 UIApplication 的 registerForRemoteNotificationTypes 与 UIApplicationDelegate 的 application(_:didRegisterForRemoteNotificationsWithDeviceToken:),application(_:didReceiveRemoteNotification:)
-
iOS 4 - 引入本地通知 scheduleLocalNotification,presentLocalNotificationNow:, application(_:didReceive:)
-
iOS 5 - 加入通知中心页面
-
iOS 6 - 通知中心页面与 iCloud 同步
-
iOS 7 - 后台静默推送 application(_:didReceiveRemoteNotification:fetchCompletionHandle:)
-
iOS 8 - 重新设计 notification 权限请求,Actionable 通知 registerUserNotificationSettings(_:),UIUserNotificationAction 与 UIUserNotificationCategory,application(_:handleActionWithIdentifier:forRemoteNotification:completionHandler:) 等
-
iOS 9 - Text Input action,基于 HTTP/2 的推送请求 UIUserNotificationActionBehavior,全新的 Provider API 等
有点晕,不是么?一个开发者很难在不借助于文档的帮助下区分 application(_:didReceiveRemoteNotification:) 和 application(_:didReceiveRemoteNotification:fetchCompletionHandle:),新入行的开发者也不可能明白 registerForRemoteNotificationTypes 和 registerUserNotificationSettings(_:) 之间是不是有什么关系,Remote 和 Local Notification 除了在初始化方式之外那些细微的区别也让人抓狂,而很多 API 都被随意地放在了 UIApplication 或者 UIApplicationDelegate 中。除此之外,应用已经在前台时,远程推送是无法直接显示的,要先捕获到远程来的通知,然后再发起一个本地通知才能完成显示。更让人郁闷的是,应用在运行时和非运行时捕获通知的路径还不一致。虽然这些种种问题都是由一定历史原因造成的,但不可否认,正是混乱的组织方式和之前版本的考虑不周,使得 iOS 通知方面的开发一直称不上“让人愉悦”,甚至有不少“坏代码”的味道。
另一方面,现在的通知功能相对还是简单,我们能做的只是本地或者远程发起通知,然后显示给用户。虽然 iOS 8 和 9 中添加了按钮和文本来进行交互,但是已发出的通知不能更新,通知的内容也只是在发起时唯一确定,而这些内容也只能是简单的文本。 想要在现有基础上扩展通知的功能,势必会让原本就盘根错节的 API 更加难以理解。
在 iOS 10 中新加入 UserNotifications 框架,可以说是 iOS SDK 发展到现在的最大规模的一次重构。新版本里通知的相关功能被提取到了单独的框架,通知也不再区分类型,而有了更统一的行为。我们接下来就将由浅入深地解析这个重构后的框架的使用方式。
UserNotifications 框架解析
基本流程
iOS 10 中通知相关的操作遵循下面的流程:
首先你需要向用户请求推送权限,然后发送通知。对于发送出的通知,如果你的应用位于后台或者没有运行的话,系统将通过用户允许的方式 (弹窗,横幅,或者是在通知中心) 进行显示。如果你的应用已经位于前台正在运行,你可以自行决定要不要显示这个通知。最后,如果你希望用户点击通知能有打开应用以外的额外功能的话,你也需要进行处理。
权限申请
通用权限
iOS 8 之前,本地推送 (UILocalNotification) 和远程推送 (Remote Notification) 是区分对待的,应用只需要在进行远程推送时获取用户同意。iOS 8 对这一行为进行了规范,因为无论是本地推送还是远程推送,其实在用户看来表现是一致的,都是打断用户的行为。因此从 iOS 8 开始,这两种通知都需要申请权限。iOS 10 里进一步消除了本地通知和推送通知的区别。向用户申请通知权限非常简单:
1 2 3 4 5 6 |
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge])
granted, error
in
if
granted
// 用户允许进行通知
|
当然,在使用 UN 开头的 API 的时候,不要忘记导入 UserNotifications 框架:
1 |
import UserNotifications
|
第一次调用这个方法时,会弹出一个系统弹窗。
要注意的是,一旦用户拒绝了这个请求,再次调用该方法也不会再进行弹窗,想要应用有机会接收到通知的话,用户必须自行前往系统的设置中为你的应用打开通知,如果不是杀手级应用,想让用户主动去在茫茫多 app 中找到你的那个并专门为你开启通知,往往是不可能的。因此,在合适的时候弹出请求窗,在请求权限前预先进行说明,以此增加通过的概率应该是开发者和策划人员的必修课。相比与直接简单粗暴地在启动的时候就进行弹窗,耐心诱导会是更明智的选择。
远程推送
一旦用户同意后,你就可以在应用中发送本地通知了。不过如果你通过服务器发送远程通知的话,还需要多一个获取用户 token 的操作。你的服务器可以使用这个 token 将用向 Apple Push Notification 的服务器提交请求,然后 APNs 通过 token 识别设备和应用,将通知推给用户。
提交 token 请求和获得 token 的回调是现在“唯二”不在新框架中的 API。我们使用 UIApplication 的 registerForRemoteNotifications 来注册远程通知,在 AppDelegate 的 application(_:didRegisterForRemoteNotificationsWithDeviceToken) 中获取用户 token:
1 2 3 4 5 6 7 |
// 向 APNs 请求 token:
UIApplication.shared.registerForRemoteNotifications()
// AppDelegate.swift
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
let tokenString = deviceToken.hexString
print(
"Get Push token: \\(tokenString)"
)
|
获取得到的 deviceToken 是一个 Data 类型,为了方便使用和传递,我们一般会选择将它转换为一个字符串。Swift 3 中可以使用下面的 Data 扩展来构造出适合传递给 Apple 的字符串:
1 2 3 4 5 6 7 8 |
extension Data
var
hexString: String
return
withUnsafeBytes (bytes: UnsafePointer) -> String
in
let buffer = UnsafeBufferPointer(start: bytes, count: count)
return
buffer.map String(format:
"hhx"
, $0).reduce(
""
, $0 + $1 )
|
权限设置
用户可以在系统设置中修改你的应用的通知权限,除了打开和关闭全部通知权限外,用户也可以限制你的应用只能进行某种形式的通知显示,比如只允许横幅而不允许弹窗及通知中心显示等。一般来说你不应该对用户的选择进行干涉,但是如果你的应用确实需要某种特定场景的推送的话,你可以对当前用户进行的设置进行检查:
1 2 3 4 5 6 |
UNUserNotificationCenter.current().getNotificationSettings
settings
in
print(settings.authorizationStatus)
// .authorized | .denied | .notDetermined
print(settings.badgeSetting)
UserNotifications ios10 通知使用
|