推送原理:
iOS端推送绕不开APNS,我们发送的每一条推送都经过苹果的APNS然后在下发给iphone Device。当用户第一次启动app时,会提示用户是否接受远程通知,如果接受那么NSUserNotficationCenter会将设备的UUID和项目的id发送给APNS apns将加密生成的Token返回给设备,这时我们将该字段传回服务器或者保存。当我们需要给用户发送推送的时候,服务器会将toKen和消息体打包发送给Apns,apns然后根据token筛选并将这条消息下发给iphone。iphone在根据项目id寻找对应的app.形成环。
ios推送流程
1.准备阶段 生成Push证书,将生成的push证书转换成p12(后台java)或者pem(PHP)
2.项目配置:导入push证书 并且 打开项目推送开关(8.0新增)TARGETS->Capabillities->Push Notifications
3.获取Token
4.接受推送消息
具体实现
1.获取Token
由于版本10对push框架有更新,所以我们需要区分开来分别处理
10以后需要导入库文件
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import <UserNotifications/UserNotifications.h>
#endif
添加并实现代理方法
@interface AppDelegate ()<UNUserNotificationCenterDelegate>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
//10
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!error&&granted) {
NSLog(@"用户点击了允许接受推送");
}else{
NSLog(@"用户点击了不允许接受推送");
}
}];
}else if ([[UIDevice currentDevice].systemVersion floatValue]>=8.0){
//8.0-9.0
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
[application registerUserNotificationSettings:settings];
}else{
//7.0
[application registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |UIRemoteNotificationTypeSound |UIRemoteNotificationTypeAlert)];
}
//注册远程消息通知获取deviceToken
[application registerForRemoteNotifications];
return YES;
}
在AppDelegate代理中获取token
//注册apns成功获取devicetoken 10/10以下获取token都走这个代理方法
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSString *toKen = [[[[NSData dataWithData:deviceToken] description]stringByReplacingOccurrencesOfString:@"<" withString:@""]stringByReplacingOccurrencesOfString:@">" withString:@""];
NSLog(@"token-----%@",toKen);
//发送给服务器或者保存都可以根据操作
}
//token获取失败
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
//Optional
NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error);
}
token获取到以后是保存还是发送给服务器根据需求
如果你只做到这一步。应用在未启动或者应用在后台是可以接受到推送的。能基本满足常规需求了,如果你在寻找应用在前台也能接受提示框或者点击推送通知能够跳转到指定界面的需求时请往下看
app有三种状态未启动,在后台,在前台,对应的我们需要对这三个状态下接受到推送区别对待
当app未启动或者在后台时 无论10之前10之后都能接受推送消息有弹框
当app在前台运行时 10.0之前没有提示框 10.0以后有提示框
所以我们不仅要区分app状态还要对10之前和之后调用不同的方法代码如下
兼容10.0之前的版本
当应用在后台/未启或者前台都会调用此方法
//10中被下面的方法替换,并且苹果推荐使用下面的方法。 用法和上面相同10以下还可以使用
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
// Required,For systems with less than or equal to iOS6
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler{
//应用处于前台
if (application.applicationState == UIApplicationStateActive) {
NSLog(@"可以做个提示框");
//我们可以自定义一个推送或者加入一个view自动显示
}else if (application.applicationState == UIApplicationStateInactive){
//用用程序处于关闭状态(不在前台也不在后台),用户通过点击通知中心的消息将客户端从关闭状态调至前台
//我们可以搞事情,比如跳转到某个界面将角标变成0等等
}else{
//应用程序处于后台,点击推送通知会进入到该处,可以做相应操作
//我们可以搞事情,比如跳转到某个界面将角标变成0等等
}
completionHandler(UIBackgroundFetchResultNewData);
/*UIBackgroundFetchResult枚举 主要用来在后台状态下进行一些操作的。比如请求数据,操作完成以后必须通知系统获取完成
UIBackgroundFetchResultNewData,
UIBackgroundFetchResultNoData,
UIBackgroundFetchResultFailed
*/
}
10.0之后的版本(包含10)
当应用在后台或者未启动,点击通知栏会调用
点击通知栏都会调用这个方法。 程序退出或者后台运行时,点击通知栏会调用*/
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler{
NSLog(@"消息来了%@",response.notification.request.content.userInfo);
//可以做跳转,或者把角标设为0等等
}
当应用在前台运行时,接受到推送消息时 时不会有提示。如果需要提示 添加如下代码
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler{
/*UNNotificationPresentationOptions枚举
UNNotificationPresentationOptionBadge = (1 << 0),
UNNotificationPresentationOptionSound = (1 << 1),
UNNotificationPresentationOptionAlert = (1 << 2),
*/
//10以后前台运行时调用该方法 调用会有提示
completionHandler(UNNotificationPresentationOptionBadge|
UNNotificationPresentationOptionSound|
UNNotificationPresentationOptionAlert);
}
到此。完整的推送流程就完成了,响应操作看项目需求,比如点击推送弹框跳转到指定界面,或者应用在前台也能接受推送等等。
非常规需求
1.静默推送
在用户察觉不到的情况下没有声音,没有振动,没有弹框提示进行远程推送,推送完毕根据推送过来的相关信息完成相关的操作。该功能也是10.0新增功能。
实现静默推送的必要条件
1.必须要有此字段 content-available:1 此字段为静默推送标志
2.aps字典中不能有 alert、badge、sound 可以添加自定义字段
3.打开BackgroundModes中的Remote Notification开关
执行代码
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
//当app在前台或者在后台说到静默推送时会走该方法
}
2.更换推送提示音
当应用未启动或者在后台时提示音时系统播放不需要添加播放代码,我们只需要把音频文件导入到项目,并且在推送字段中sound的值设置为音频文件名。就ok 注意:音频文件mp3,wav等常见语音格式都可以支持。
当应用在前台需要我们自己添加播放代码。具体如下
SystemSoundID sound = 1;
// 转换 URL
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:@"音频" ofType:@“mp3”];
NSURL *soundURL = [NSURL fileURLWithPath:soundFilePath];
// 生成系统音效id
AudioServicesCreateSystemSoundID((__bridge CFURLRef)soundURL, &sound);
// 播放系统音效
AudioServicesPlaySystemSound(sound);
注意当应用在前台 10.0之前和10.0之后分别添加上面代码。
3.角标问题
在远程推送的协议中,有一个badge字段,这个字段是用来设置程序角标值的。当app处于非运行状态或者在后台时,收到远程推送,app并不会运行任何代码,一切事务都是由系统处理 。所以角标多少根据badge值多少来设定。所以关于角标叠加问题:个人认为根据badge值来设定,当点击推送进入应用时-1.然后发送给服务器保存好,下次发送时服务器badge字段-1发送过来就ok.