概述
语言: swift, 版本:4.2,XCode:10.1
写作时间:2018-12-14
说明Push的作用
Push的作用是提醒用户,你要用俺开发的APP啦,提升日活和使用频率的神器。无论APP是在后台,还是进程已经被结束了,只要用户手机联网即可。比如你要少用微信,关掉微信的推送试试(当然卸载更绝)。
Push的工作流程如下:
Provider Server是发送Payload内容 (其实是Json,包含device、APP、内容信息)到APNs (Apple负责推送消息的服务器),只要你的iPhone在线,那么就一直跟APNs保持长连接。所以一有消息过来,iPhone就会显示推送消息。
带着下面的问题往下看:
- Provider怎么知道给那台设备推送?
Push显示给用户的形态
iOS 12,Push notifications可以做以下事情:
- 显示简短文字.
- 播放推送声音.
- 显示消息数字在icon上面.
- 在消息上提供交互,不需要打开APP. 比如点赞、回复.
- 显示媒体附件,比如图片,GIF.
- 静默推送,后台刷新APP的内容,前提是APP进程存在.
- 消息分组.
- 编辑或者移除推送.
- 在展示消息前,内容可以被编辑.
- 消息显示定制化UI.
此教程例子必要的条件
完成教程,需要下面的条件方能测试:
- 真机iPhone、iPad、iTouch等移动端设备,Push notifications 不能在模拟器上面使用.
- 开通Apple开发者账号,需要配置证书、Profile,生成Provider需要的秘钥等. (总不能允许任何人都可以给自己的APP发消息吧?)
- 下载Mac客户端模拟Provider的角色,发送payload到APNs.
Push的工作流程
Provider发送,APP接收push notifications, 你只要完成下面三件事:
- Push配置:配置证书,Project配置,注册Device到Apple Push Notification service (APNs).
- Provider Server发送一条push notification 到APNs, APNs自动发送push notification给设备.
- APP消费掉push notification的内容,一般是在delegate里面回调(callback).
Push的证书配置
证书配置是为了保证用户下载的是正版的APP,Push证书是为了保证Provider是对应自己APP的才有权限推送。
为了便于理解,从零开始演示配置的信息,网页打开开发者首页https://developer.apple.com,–》Account, --》 Certificates, Identifiers & Profiles
-
先配置App IDs, 新建
-
推送不能用通配符,点击最下面的Continue按钮,下一页点击最下面Register按钮,下一页点击最下面的Done按钮。
-
点击Certificates, IDs & Profiles -> Identifiers -> App IDs 选择刚刚建立的id -->
com.zgpeace.demo
,
-
你可以看到服务列表Application Services available, 其中 Push Notifications显示的是可配置的configurable:
-
点击最下面的Edit按钮,找到Push Notification,左边打勾。
-
这里创建Development SSL Certificate --》 点击Create Certificate. (Production SSL Certificate的创建是类似的). --》 打勾 Apple Push Notification service SSL(Sandbox) --> 点击Continue
-
选择创建的App ID
com.zgpeace.demo
, 点击Continue。这里会明确说明,不能用通配符的App ID才能创建Apple Push Notification service SSL certificate.
-
创建Certificate Signing Request(CSR). 这个界面是显示如何创建CSR的步骤。下面会一步一步创建CSR,这个时候要开小差了,不着急点Continue哦。(下面以8.?表示分步骤,待到9.才是点Continue下来的。)
8.1. 打开Keychain Access软件,路径为 Application folder --> Utilities folder --> 打开 Keychain Access. 或者用快键键CMD + Space打开Spotlight,输入Keychain Access。
8.2. 点击Keychain左上角的下拉按钮, 选择 Keychain Access > Certificate Assistant > Request a Certificate from a Certificate Authority.
注意:这里有个尿点,很多人采坑,注意Category 一定要选择Certificates,否则出各种诡异的错误。
8.3. 在Certificate Information窗口, 填写下面的信息:
- User Email Address field填写你的邮箱.
- Common Name field填写一个私钥的名字 (e.g., John Doe Dev Key).
- CA Email Address field要留空.
- “Request is” 分组, 选择"Saved to disk" .
- 点击Continue,完成CSR生成, 保存到本地,这个马上要用,保存到可以找到的地方.
-
点击8的Continue,选择8.3生成CSR文件,点击Continue
-
如果一切顺利,将会得到证书页面。下载证书,安装。
-
安装成功以后,可以在Keychain Access找到证书信息。
-
恭喜你!这个步骤很长,但是值得。查看App ID的Development证书状态,已经变为Enabled,路径为 Certificates, IDs & Profiles -> Identifiers -> App IDs Push Notifications :
-
上面生成的证书是给Provider Server用的。 因为是新创建的App ID, project需要运行的话,需要先建立客户端的Development证书(CSR可以用之前的),接在在设备里面加入iPhone的DeviceId,证书跟DeviceId一起创建Profile。
证书实际上是包含公钥跟私钥,加密以及身份验证用的;Device Id表明哪些设备可以用于调试; Profile表示档案,最终打包上传App Store,Apple根据这些信息校验App是否是正版。
因为已经跑题,罗列了一下结果图。
Development Certificate 创建结果图, 下载并安装证书 :
Device Id添加结果图:
Profile生成后,点击下载,双机安装,就装到XCode里面去了。
Push的demo工程启动
下载demo工程https://github.com/zgpeace/WenderCast-Starter,运行结果图
Push的project配置
修改Bundle Identifier为新建com.zgpeace.demo
, WenderCast target > General > change Bundle Identifier
开启Push Notification, WenderCast target > the Capabilities tab > Push Notifications 选择ON:
Push的权限
iPhone的体验很好,做任何事情都要经过用户同意才能处理。
推送也一样,第一步先征得用户是否需要推送这个功能。
- 打开文件 AppDelegate.swift 在文件的最上面加上:
import UserNotifications
- 加下面的方法在
AppDelegate
的最下面:
func registerForPushNotifications() {
UNUserNotificationCenter.current() // 1
.requestAuthorization(options: [.alert, .sound, .badge]) { // 2
granted, error in
print("Permission granted: (granted)") // 3
}
}
分析上面代码:
- UNUserNotificationCenter 处理了APP所有推送相关的事件.
- requestAuthorization(options:completionHandler:) 请求授权用推送的权限. options 表示推送可以展示的情况 – 例子里设置了 alert, sound and badge.
- 授权结果通过Bool得知.
注解: options 参数 requestAuthorization(options:completionHandler:) 可以是下面的任何组合 UNAuthorizationOptions:
.badge: 显示推送书在 app’s icon.
.sound: 播放声音.
.alert: 显示文字.
.carPlay: 显示推送在车载系统.
.provisional: 发布不会被拒绝的推送. 比如静默推送.
.providesAppNotificationSettings: 表示App有自己的推送设置UI.
.criticalAlert: 忽略静音,并且不会被打断。你需要向Apple申请者特殊的权利, 并说明这是必要的. .
- 在方法application(_:didFinishLaunchingWithOptions:)的末尾,在
return
之前加入以下代码:
registerForPushNotifications()
构建 > 运行。当APP运行起来后,弹框问用户是否允许发推送。
- 用户点击允许,App可以显示推送了。真棒!但是,要是用户拒绝了呢?加下面的方法在
AppDelegate
:
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { settings in
print("Notification settings: (settings)")
}
}
- 在 registerForPushNotifications, 用下面替换掉方法 requestAuthorization(options:completionHandler:) :
UNUserNotificationCenter.current()
.requestAuthorization(options: [.alert, .sound, .badge]) {
[weak self] granted, error in
print("Permission granted: (granted)")
guard granted else { return }
self?.getNotificationSettings()
}
Push的token获取
用户授权成功后,接下来获取Push的token,需要发送给Provider Server,存入数据库。
- 在getNotificationSettings(), 在closure的里面print的下面,加以下代码:
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
- 获取token成功print出来,后面会用到。出错,打印出错信息。
以下方法为成功、失败的delegate。
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
let token = tokenParts.joined()
print("Device Token: (token)")
}
func application(
_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register: (error)")
}
token例子:
Push Server的配置
- 创建Authentication Key,你只要创建一个key,你所用应用都可以用。
网页打开开发者首页https://developer.apple.com,–》Account, --》 Certificates, Identifiers & Profiles --》Keys ▸ All。在右上角, 点击 加号+按钮 .
取个名字, 比如 Push Notification Key. 在 Key Services 下面, 勾选 Apple Push Notifications service (APNs).
点击 Continue ,接着 Confirm 在下个页面,点击下载. 文件名字类似于 AuthKey_4SVKWF966R.p8. 保存好该文件,你需要用它来发推送! 4SVKWF966R 文件名字的一部分是Key ID. 你也需要它.
你最后需要的是your Team ID. 点击链接跳转到Membership Details 页面,你就会找到.
唷!配置的道路好长,接下来就可以发送推送信息了。
Push Server发送payload推送
点击链接下载 PushNotifications .
打开 PushNotifications,并配置下面的信息:
- 在 Authentication下面, 选择 Token.
- 点击按钮 Select P8 ,选择 文件 ** .p8** 在前面的有讲解.
- 输入 Key ID 和 Team ID.
- Body下面, 输入app的 Bundle ID 和 device token.
- 把request body的内容改为如下:
{
"aps": {
"alert": "Breaking News!",
"sound": "default",
"link_url": "https://raywenderlich.com"
}
}
- app退到background,或者锁屏.
- 点击按钮Send button在 PushNotifications.
你可以获取到自己的第一个推送:
Payload JSON说明
payload就是JSON,必须包含的key是 aps
, 它也是个字典 dictionary.
apt
预置了7对keys,以下是具体说明:
alert
: 可以试字符串string, 也可以是字典dictionary. 作为 dictionary, 它可以国际化文字或者改变通知的样子,类似于CSS(猜的,不确定对不对).badge
: 显示推送书在icon的右上角. 去掉数字显示,设置为0即可.sound
: 声音预置在app里面. 定制的声音要小于30秒,还有一些限制(细节要看官方文档了).thread-id
: 对推送消息分组.category
: 给推送消息分类, 用于定制化相应推送. 接下来有栗子?.content-available
: 设置这项为1, 推送就是静默推送. 在下面你将学到静默推送.mutable-content
: 设置这项为1, app可以先显示之前修改内容.
除了上面预置的keys, 你可以加其它字段,只要payload小于 4,096 bytes.
APP处理,Server发过来的push
处理推送通知都在UIApplicationDelegate
类的delegate里面,根据APP所处的状态分为两类:
- 如果APP进程已经结束,当点击推送消息,相应方法是
application(_:didFinishLaunchingWithOptions:)
. - 如果APP运行在前台或者后台,系统回调的方法是
application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
. 如果用户点击推送消息,iOS会再次调用该方法, 你可以更新UI和显示相关信息.
- 第一种情况(进程已经结束),
WenderCast
会建立新的消息子项, 并打开News tab. 在方法application(_:didFinishLaunchingWithOptions:)
的末尾在return
之前加上一下代码:
// Check if launched from notification
let notificationOption = launchOptions?[.remoteNotification]
// 1
if let notification = notificationOption as? [String: AnyObject],
let aps = notification["aps"] as? [String: AnyObject] {
// 2
NewsItem.makeNewsItem(aps)
// 3
(window?.rootViewController as? UITabBarController)?.selectedIndex = 1
}
上面代码说明:
- 检查
UIApplication.LaunchOptionsKey.remoteNotification
是否存在. 如果存在,则说明APP是点击推送唤醒的. 这就是payload的内容. - 如果是推送,则捕获
aps
dictionary,并创建NewsItem. - 切换tab到News栏目.
调试APP进程不存在的情况,需要修改Scheme:
点击WenderCast
scheme并选择编辑 Edit Scheme
…. 左侧栏选择Run
, 接着在Info tab
选择 Wait for executable to be launched
:
这个设置使调试在等待,第一次点击推送消息才唤醒APP.
构建并运行. 当APP安装好后, 发送多个推送. 点击推送,APP就好打开news tab:
- 第二种情况,APP在前台或者后台(进程存在)。
处理进程存在的APP,在AppDelegate
增加下面的方法:
func application(
_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler:
@escaping (UIBackgroundFetchResult) -> Void
) {
guard let aps = userInfo["aps"] as? [String: AnyObject] else {
completionHandler(.failed)
return
}
NewsItem.makeNewsItem(aps)
}
这个方法通过push message创建了一个新NewsItem.
在进程存在的情况下,这个方法会调用。修改 scheme
回到 launching > automatically. 路径为:WenderCast
scheme > Edit Scheme
> Run
> Info tab
> automatically
.
构建Build并运行run. app运行z在前台并停留在News tab. 发送推送通知可以看到消息item在增加:
That’s it! 你的app现在可以神奇地接收推送消息了.
定制Push的相应事件
显示Actionable notifications
Actionable notifications 可以加定制化按钮在推送消息里面,比如可以看到email APP显示回复按钮,Tweets显示点赞按钮.
在方法registerForPushNotifications()
里面, 在guard
下面,getNotificationSettings()
的上面加入以下方法:
// 1
let viewAction = UNNotificationAction(
identifier: viewActionIdentifier, title: "View",
options: [.foreground])
// 2
let newsCategory = UNNotificationCategory(
identifier: newsCategoryIdentifier, actions: [viewAction],
intentIdentifiers: [], options: [])
// 3
UNUserNotificationCenter.current().setNotificationCategories([newsCategory])
代码说明:
- 创建新的notification action, title View在按钮上. 这个事件有唯一的标识, 区分不同的事件处理.
- 定义news category, 它包含了上面的view action. 它有区分的标识符"
newsCategory
" 在payload里面, 区分不同的category. - 最后,调用
setNotificationCategories
, 注册 actionable notification.
That’s it! 构建并运行 app去注册新的 notification settings.
app推到后台,接着用PushNotifications
发送下面的 payload
:
{
"aps": {
"alert": "Breaking News!",
"sound": "default",
"link_url": "https://raywenderlich.com",
"category": "NEWS_CATEGORY"
}
}
如果一切顺利,下拉推送通知,你可以看到下面的结果View action:
Nice! 点击会唤醒WenderCast
, 但是它没有任何响应事件. 为了使其调整的News tab,需要完善delegate.
处理Actionable notifications的Action
当触发了notification action
, UNUserNotificationCenter
通知 delegate
. 在文件AppDelegate.swift
的最下面, 增加 class extension:
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
// 1
let userInfo = response.notification.request.content.userInfo
// 2
if let aps = userInfo["aps"] as? [String: AnyObject],
let newsItem = NewsItem.makeNewsItem(aps) {
(window?.rootViewController as? UITabBarController)?.selectedIndex = 1
// 3
if response.actionIdentifier == viewActionIdentifier,
let url = URL(string: newsItem.link) {
let safari = SFSafariViewController(url: url)
window?.rootViewController?.present(safari, animated: true,
completion: nil)
}
}
// 4
completionHandler()
}
}
custom action
唤醒APP后,callback
做了很熟悉的解析payload
的操作:
- 获取
aps
dictionary. - 创建
NewsItem
,并跳转到News tab. - 检查
action identifier
, 是否存在identifier
. 如果是 “View” action并且链接是有效的, 它会展示显示链接页面在SFSafariViewController
. - 调用系统的
completion handler
.
最后需要设置delegate为UNUserNotificationCenter
. 在application(_:didFinishLaunchingWithOptions:)
最上面加下面的代码:
UNUserNotificationCenter.current().delegate = self
Build and run. 再次结束app的进程, 接着发送推送用下面的payload:
{
"aps": {
"alert": "New Posts!",
"sound": "default",
"link_url": "https://raywenderlich.com",
"category": "NEWS_CATEGORY"
}
}
下拉 notification并点击 View action,你可以看到WenderCast present 显示Safari View controller
, 当APP启动以后:
Congratulations, 你已经实现了actionable notification!
静默推送
当数据库有新数据的时候,发个静默推送(Silent Push Notifications), 后台帮用户更新数据就好。 这样的好处是,不用客户端间断性轮询更新数据。
需要在Background Modes开启 Remote notifications, 路径为 WenderCast target > Capabilities tab > Background Modes (打开) > Remote notifications(勾选):
现在,APP可以在后台,获取到静默推送了
在类 AppDelegate
中, 找到 application(_:didReceiveRemoteNotification:)
. 把 NewsItem.makeNewsItem()
替换为下面代码:
// 1
if aps["content-available"] as? Int == 1 {
let podcastStore = PodcastStore.sharedStore
// 2
podcastStore.refreshItems { didLoadNewItems in
// 3
completionHandler(didLoadNewItems ? .newData : .noData)
}
} else {
// 4
NewsItem.makeNewsItem(aps)
completionHandler(.newData)
}
解析代码:
- 检查
content-available
是否为1
, 是则表示silent notification
. - 异步刷新
podcast list
. - 当刷新结束调用
completion handler
让系统更新数据(没新数据则不处理). - 如果不是
silent notification
, 采取是新内容创建新的news item
.
build and run, App保持在前台foreground, PushNotifications
推送下面的payload :
{
"aps": {
"content-available": 1
}
}
静默推送,除非服务端返回新的数据,否则界面看不出变化,可以用调试的方式,看看走的逻辑是否符合预期。
总结
Congratulations! 你已经完成了推送的知识:证书配置、Project设置、Provider模拟推送、App处理推送payload、定制化按钮Actionable notifications、 静默推送!
代码在:https://github.com/zgpeace/WenderCast-Starter
分支说明:master是初始化代码, finish是按照上面的例子完成的。
真机测试,需要修改所有的BundleId, Certificate, Profile。
感谢阅读:如有任何问题,请留言,谢谢!
参考文章:
https://www.raywenderlich.com/8164-push-notifications-tutorial-getting-started
https://medium.com/flawless-app-stories/ios-remote-push-notifications-in-a-nutshell-d05f5ccac252
https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html
最后
以上就是甜美帽子为你收集整理的APNs Push Notification教程一的全部内容,希望文章能够帮你解决APNs Push Notification教程一所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复