iOS推送
在IOS推送服务中,Apple提供了两种不同方式的推送形式,一种是在通知栏上面显示的推送;另一种则是不带消息提醒的推送,俗称“静默消息”。
1. 普通推送和静默推送的区别
普通推送:收到推送后(有文字有声音),点开通知,进入APP后,才执行
- (void)application:(UIApplication didReceiveRemoteNotification:(NSDictionary fetchCompletionHandler:(void result))handler *)application *)userInfo (^)(UIBackgroundFetchResult
静默推送:(Silent Push)并不是必须要“静默”(通常是没有文字没有声音),只要推送payload中aps字典里包含了"content-available": 1的键值对,都具有静默推送的特性,不用点开通知,不用打开APP,就能执行
-(void)application:(UIApplication )application)userInfo didReceiveRemoteNotification:(NSDictionary fetchCompletionHandler:(void (^)(UIBackgroundFetchResultresult))handler
用户完全感觉不到所以静默推送又被我们称做 Background Remote Notification(后台远程推送)。
静默推送是在iOS7之后推出的一种推送方式。它与其他推送的区别在于允许应用收到通知后在后台(background)状态下运行一段代码,可用于从服务器获取内容更新。
PS:注册消息通知时通常的弹窗询问权限有什么用呢?其实只是请求用户允许在推送通知到来时能够有alert, badge和sound,而并不是在请求注册推送本身的权限。静默推送即使用户不允许应用的推送,静默推送依然会送达用户设备,只是不会有alert, badge和sound。这也符合静默推送的正常使用场景。
2. 远程推送时 , 应用的几种状态及对应回调方法
(1) . 应用开启时 , 应用在前台
(2) . 应用开启时 , 应用在后台
(3) . 应用未启动(应用被杀死)
从苹果APNS服务器远程推送时:
不使用<UserNotifications/UserNotifications.h>时(iOS10以后可用)
1 . 如果应用处于 (1) 状态 , 则不会发出声音 , 会直接调用appDelegate的代理方法didReceiveRemoteNotification(didReceiveRemoteNotification:fetchCompletionHandler:)
2 . 如果应用处于 (2) 状态 , 则会发出提示音, 点击推送消息 , 则会调用appDelegate的代理方法didReceiveRemoteNotification
3 . 如果应用处于 (3) 状态,则会发出提示音 , 点击推送消息 , 则会开启应用 , 在下面这个方法中会带上launchOptions这个参数,如果实现了application:didReceiveRemoteNotification:fetchCompletionHandler:这个方法,则还会调用这个方法
注:didReceiveRemoteNotification指以下两个方法。两个方法互斥。在两方法都实现的情况下方法2优先级高
1. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
2. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
iOS10使用<UserNotifications/UserNotifications.h>时
1 . 如果应用处于 (1) 状态 , 会发出声音 , 会直接调用appDelegate的代理方法userNotificationCenter:willPresentNotification:withCompletionHandler
2 . 如果应用处于 (2) 状态 , 则会发出提示音, 点击推送消息 , 则会调用appDelegate的代理方法
userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler
3 . 如果应用处于 (3) 状态,则会发出提示音 , 点击推送消息 , 则会开启应用 , 在下面这个方法中会带上launchOptions这个参数,如果实现了userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler这个方法,则还会调用这个方法
2. 静默推送及app的状态切换
在大多数情况下,启动一个app后都是进入前台,比如我们点击应用图标或点推送通知来启动应用。其实app在某些后台事件和特定条件下是可以直接启动到后台(launch into the background)的。
2.1 应用状态之一Suspended
这种状态其实和Background类似,而且从用户角度讲应用现在看起来确实是在“后台”,但它和Background状态不同的是Suspended下已经不能执行代码了。应用何时会进Suspended就是玄学了,这是由iOS系统自动控制的,而且不会有任何回调,可以看到UIApplicationDelegate里并没有像applicationWillBecomeSuspended:这种东西。这种状态下的应用虽然还在内存中,但是一旦设备内存吃尽,比如开了炉石传说的游戏,那么系统就会优先干掉(文档上用的是purge这个词)处于Suspended状态的应用,而且也不会有回调。
2.2 应用启动到前台的生命周期(以点击应用图标开始)
AppDelegate中走的回调方法
· application:willFinishLaunchingWithOptions:
· application:didFinishLaunchingWithOptions:
· applicationDidBecomeActive:
静默推送可以使应用启动到后台
前提是应用先被退到后台,过一段时间被系统移入Suspended状态,然后又被系统在内存吃紧时回收了内存(相当于应用已经被系统正当杀掉,而非用户双击Home键杀掉),在这以后,该应用收到静默推送即会启动应用到后台。
AppDelegate中走的回调方法变为
· application:willFinishLaunchingWithOptions:
· application:didFinishLaunchingWithOptions:
· applicationDidEnterBackground:
这个过程中,系统不会显示应用的window,就是说我们不会看到手机屏幕上突然鬼畜一下应用启动,但是应用的第一屏会被加载和渲染,比如你的window.rootViewController是一个TabBarController,那么它及其默认选中的selectedViewController都会被加载和渲染。这是因为系统认为在后台执行完任务后可能会有UI上的更新,所以在applicationDidEnterBackground:方法执行结束后便会有个快速的截图,来更新用户双击Home时看到的那个应用截图。
3. 收到静默推送时的后续该如何处理。
application:didReceiveRemoteNotification:fetchCompletionHandler:
这是应用收到静默推送的回调方法,我们最多有30s的时间来处理数据,比如静默推送表示某个列表或资源有更新,你可以在此处下载数据,在下载处理完数据后需要尽快调用completionHandler(...)告诉系统处理完毕。
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[Downloader fetchData:^(id x){ // 处理数据,更新UI 等
completionHandler(UIBackgroundFetchResultNewData);
}];
}
如果这次是启动到后台的情况,调用completionHandler(...)后会使应用马上进入之前的状态。那就有可能遇到这样的问题:很多时候我们需要在启动时发送一堆业务上的API请求,如果这次静默推送没有数据需要下载和处理,就会刚把启动处的API请求发出,就调用了completionHandler(...),导致发出的这些请求在下次打开应用时显示超时。这种情况下我们可以强行延时下completionHandler(...)的调用,来保证能在这次收到那些API的返回。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
completionHandler(UIBackgroundFetchResultNoData);
});
4. 静默推送
应用想收到静默推送需要满足的条件:
1.应用在前台/后台 (应用被杀死就收不到了)
2.应用实现了
application:didReceiveRemoteNotification:fetchCompletionHandler:/application:didReceiveRemoteNotification:
3. 消息定义时需设置:"content-available" = 1
流程:
1. 移动端注册消息,向APNs服务器获取deviceToken,并提交给后台保存;
2. 后台定义消息,并推送给APNs服务器。APNs根据deviceToken做分发。
3. 移动端收到推送消息后的逻辑处理。
消息定义示例:
特殊说明:
1. APNS去掉alert、badge、sound字段实现静默推送,增加增加字段"content-available":1,也可以在后台做一些事情。
//静默推送消息格式
{
"aps":{
"alert":"",
"content-available":1
},
"userInfo":"test"
}
*/
小结:
1.应用在后台/前台/被杀死,都可以收到普通的远程推送
2.应用在后台/前台时,可以通过静默推送,修改一些数据
3.应用被杀死时(相当于应用已经被系统正当杀掉,而非用户双击Home键杀掉),可以通过Background Fetch短时间唤醒应用
参考资料:
http://www.cocoachina.com/articles/23672
https://www.jianshu.com/p/f326987c737e
https://www.jb51.net/article/145654.htm
https://blog.csdn.net/ws_752958369/article/details/79732961
网友评论