如果是按照需求开发推送功能,那么只需要按照对应要求实施代码就可以了;但是如果要拿出一个iOS推送方案,就需要先对iOS系统的推送知识有个系统性的了解再说了。
一、静默推送与普通推送
静默推送
静默推送消息到来时不会有声音、震动、通知图标, 会唤醒APP运行在后台,会调用application:didReceiveRemoteNotification:fetchCompletionHandler:
方法,唤醒后有最多30S的时间来处理任务。值得注意的是,如果是用户手机Home键,手动退出APP,此APP在用户再次启动或者重启了手机之前,系统不会唤醒APP;
肯定还是要看官方的解释
A silent notification is a remote notification that doesn't display an alert, play a sound, or badge your app’s icon. It wakes your app in the background and gives it time to initiate downloads from your server and update its content.
// 以上是说:静默推送消息到来时会唤醒APP运行在后台,不会有声音、震动、通知图标.
Important
the system doesn't guarantee their delivery. In addition, the delivery of silent notifications may be throttled if the total number becomes excessive. The actual number of silent notifications allowed by the system depends on current conditions, but don't try to send more than two or three silent notifications per hour.
// 以上说:如果静默推送涉及用户过多会被“节流”,不要超过每小时2-3条。
To send a silent notification, create a remote notification whose aps dictionary includes only the content-available key, as shown in Listing 1. You may include custom keys in the payload, but the aps dictionary must not contain any keys that would trigger user interactions.
// 以上说: 发送静默推送时aps里面只能有一个键值对 "content-available" : 1
{
"aps" : {
"content-available" : 1
},
"customKey1" : "bar",
"customKey2" : 42
}
普通推送
不包含"content-available": 1的键值对,至于具体会不会有声音震动与用户的设置有关。
本地推送
- 可以设置UNCalendarNotificationTrigger(按日期触发 )、UNLocationNotificationTrigger(按照地点触发)、UNTimeIntervalNotificationTrigger(指定时间点触发);
- 可以自定义播放音频,不过音频文件需要在程序bundle或者在Library/Sounds目录里面(可以安装iMazing来查看真机的APP目录)
二、推送的图解及远程推送的注册
远程推送消息如何来到用户的手机? 按照下图的步骤走一遍就清楚了
if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
}];
} else if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0){// iOS8-iOS9
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound) categories:nil];
[application registerUserNotificationSettings:settings];
}
[application registerForRemoteNotifications];
需要注意的是远程推送的注册在注册方法调用后就会去得到一个deviceToken,与用户时候允许接收通知无关。也就是用户不同意的情况下,只要获取未出错,都能得到deviceToken. 且这个deviceToken不是固定的。
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSLog(@"deviceToken = %@",deviceToken);
NSString *token=[NSString stringWithFormat:@"%@",deviceToken];
token=[token stringByReplacingOccurrencesOfString:@"<" withString:@""];
token=[token stringByReplacingOccurrencesOfString:@">" withString:@""];
token=[token stringByReplacingOccurrencesOfString:@" " withString:@""];
// TODO
}
三、收到推送后调用的方法总结
因为iOS 8以下、iOS 8 - iOS 10、iOS 10以上系统对方法的调用都不同,所以需要弄清楚推送消息来临时会调用的方法才能做出合适的处理。这里只写iOS 8 以上需要实现的方法。
// 方法A:经过了公司测试机测试的可以信赖
// 1. iOS 8-iOS10 系统的普通推送,APP处于前台运行或者点击远程推送消息进入APP都会来到这个方法
// 2. 只要是静默推送消息,会调用此方法。
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
// 方法B:iOS10以上的方法,适用于iOS10以上设备
// 推送消息到达时用户APP正处于前台运行中会调用这个方法
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler;
// 方法C: iOS10以上的方法,适用于iOS10以上设备
// 用户通过点击推送通知进入APP时会调用这个方法
-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler;
// 这个是弃用的方法,实现方法A即可忽略这个方法
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo;
用一个图来总结上面就是:方法的标号看上面!!!
三、iOS10以上推送插件开发-UNNotificationServiceExtension、UNNotificationContentExtension
- 系统在展示通知之前,可以唤起app附带的UNNotificationServiceExtension,并且允许它改动通知的内容;
- 用户在对通知右滑查看、下拉或者3d touch的时候,通知会展开,展开后页面的布局可以由app附带的UNNotificationContentExtension来决定。
- 插件的使用可查看:https://www.jianshu.com/p/f77d070a8812
- 不使用VoIP push 的APP要实现到账语音播报功能等,使用UNNotificationServiceExtension是很好的选择
四、推送测试工具推荐
下面这个测试工具能帮助你测试推送消息
https://github.com/noodlewerk/NWPusher?spm=5176.100239.blogcont4803.8.59EeIh
推送插件的测试:步骤如下
第一步: 开发推送证书的生成、导出P12文件、查看APP是否可以接受通知等基本操作----略
第二步:Xcode中选择自己的插件然后点击运行,接下来会弹窗让你选择运行插件到哪个APP,这个时候选择自己的APP就可以了
第三步:打开上面的NWPusher工具,推送消息,即可以断点调试。
五、deviceToken变化之谜
从苹果官方的说法,deviceToken是会变化的
Never cache the device token locally on the user's device. Device tokens can change periodically, so caching the value risks sending an invalid token to your server
也就是说deviceToken是会变化的,而且变化之后上次获取到的deviceToken在有些设备上是不失效的,这就会产生一个bug: 一个推送消息可能会在同一台设备上出现多次,这点是极不好的。
解决办法:
还要获取到设备的另一个唯一标志IDFA(IDFA会在重置系统时变化,需要与keychain配合起来保证唯一性)与deviceToken同时上传给后台,后台记录deviceToken时需要先比对这个唯一标志再决定是替换还是新增。
这点可以在论坛和博客上都可以知道有人踩过坑,如:https://www.jianshu.com/p/a8ebb6c3e569
当然,如果是集成的第三方的推送功能,就不需要你去考虑这个问题了。
只能帮你到这,推荐阅读:
iOS静默推送进阶知识
了解iOS消息推送一文就够:史上最全iOS Push技术详解
iOS推送,看这篇就够了