APNs Push Notification教程一
语言: 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]) { // 2granted, error inprint("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 inprint("Notification settings: \(settings)")}
}
- 在 registerForPushNotifications, 用下面替换掉方法 requestAuthorization(options:completionHandler:) :
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {[weak self] granted, error inprint("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] {// 2NewsItem.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) {// 1let userInfo = response.notification.request.content.userInfo// 2if let aps = userInfo["aps"] as? [String: AnyObject],let newsItem = NewsItem.makeNewsItem(aps) {(window?.rootViewController as? UITabBarController)?.selectedIndex = 1// 3if response.actionIdentifier == viewActionIdentifier,let url = URL(string: newsItem.link) {let safari = SFSafariViewController(url: url)window?.rootViewController?.present(safari, animated: true,completion: nil)}}// 4completionHandler()}
}
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// 2podcastStore.refreshItems { didLoadNewItems in// 3completionHandler(didLoadNewItems ? .newData : .noData)}
} else {// 4NewsItem.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(Apple Push Notification services)
苹果的推送服务APNs基本原理简单来说就是苹果利用自己专门的推送服务器(APNs)接收来自我们自己应用服务器的需要被推送的信息,然后推送到指定的iOS设备上,然后由设备通知到我们的应用程序,设备以通知 ...
- pytorch打印模型参数_Pytorch网络压缩系列教程一:Prune你的模型
Pytorch网络压缩系列教程一:Prune你的模型 本文由林大佬原创,转载请注明出处,来自腾讯.阿里等一线AI算法工程师组成的QQ交流群欢迎你的加入: 1037662480 深度学习模型取得了前所未 ...
- ×××送通知服务教程 Apple Push Notification Services Tutorial
本文译自http://www.raywenderlich.com/.原文由iOS教程团队 Matthijs Hollemans 撰写,经原网站管理员授权本博翻译. 在iOS系统,考虑到手机电池电量,应 ...
- 推送技术 Push Notification
为什么80%的码农都做不了架构师?>>> 1.BB,Nokia,Palm都先后支持了Push,目前流行的Push方式有三种. (1)短信触发:2G时代长时间的数据连接会影响电话 ...
- Apple Push Notification Service(苹果推送服务)
https://developer.apple.com/library/IOS/documentation/NetworkingInternet/Conceptual/RemoteNotificati ...
- 怎样编写Apple Push Notification服务器
http://www.iphone-geek.cn/%E7%BC%96%E7%A8%8B/%E6%80%8E%E6%A0%B7%E7%BC%96%E5%86%99apple-push-notifica ...
- push notification for iphone
由于公司业务需求,以前一直做PHP开发,突然让我研究push notification ,一下子迷糊啦,不知所措,抓狂!但是在自己的努力下还是初有成效!现拿出来显摆一下! 1:push notific ...
- Push Notification (1)Google C2DM 服务
基于Google C2DM的消息推送 前提: 1. Android设备上有Google服务(可以在'设置'->'正在运行'中看到),并且设置了gmail帐号和同步. 2. 开发者需要注册gmai ...
- AUTOCAD自学教程一
AUTOCAD自学教程一 AUTOCAD自学教程 在学习任何一款软件的时候,第一步也是非常必要的一步就是如何的安装软件. 下面我们讲解如何的安装这个软件. 1.安装autocad 2.安装产品 3.正 ...
- 当用户流失比较明显后, 如何提升活跃度? push notification 是一个有效的方式吗?...
当用户流失比较明显后, 如何提升活跃度? push notification 是一个有效的方式吗? 添加评论 分享 按票数排序 10 个回答 赞同反对,不会显示你的姓名 Linda Jiang,友盟商 ...
最新文章
- 大数据开发套件—调度运维常见问题
- Countly 19.02.1 发布,实时移动和 web 分析报告平台
- Latex、Lyx学习备忘
- STM32系统滴答定时器(systick)应用
- 释疑の采购Invoice常用参数设置
- linux 键盘记录,学习笔记 kali linux 关于MS17-101漏洞攻击与键盘记录
- 博客园如何使用MarkDown
- 怎么在win7链接无线网络连接服务器,Win7系统网络连接一直显示正在获取网络地址但是连不上网解决方法...
- 动态规划问题中最长公共子序列---C语言实现
- C#利用NI VAS采集图片
- pip3 安装pycrypto 时报错
- 关闭进程_Xbox Game Bar重磅更新:可不离开游戏关闭系统进程
- 【软考高级:信息系统项目管理师】【信息项目十大管理】第二天:项目立项管理
- 网页分享至Facebook,Twitter,LinkedIn,WhatsApp,邮箱总结
- 1次阿里面试经验,4天走完全部流程,看这里对你有帮助!
- 小企业会计准则 ——主要账务处理和财务报表(1)
- php 获取上周日期_php获取本周以及上周 开始 和结束的日期
- 【Kaldi例子】Librispeech数据整理
- 【小程序测试】小程序介绍,项目简介
- window global
热门文章
- python数据分析 制图_Python与开源GIS:数据处理、空间分析与地图制图
- 群之脉PHP面试,面试问Redis集群,被虐的不行了......
- acid事务 mysql_MySQL 事务ACID特性
- 转:js中arguments详解
- 微服务容错限流Hystrix入门
- 动态规划——Palindrome Partitioning II
- 进入第一个Android应用界面
- iOS 网络与多线程--3.异步Get方式的网络请求(非阻塞)
- LeetCode - Duplicate Emails
- [原创]jQuery的this和$(this)