iOS10推送必看!解决极光推送不提示消息

日期:2026-04-01 03:37 | 人气:

假设你身为iOS开发者,必然会记得2016年刚发布iOS10那会儿推送机制发生那回极大改 ,好多遗留旧项目将其更新升级之后产生了接收不到推送、消息不予以提示这般离奇之问题 ,特别是那些依旧兼容iOS8的项目 ,运用极光推送之际更是频繁遭遇阻碍 ,此篇文章会帮你把这些阻碍给填平。

于2016年9月14日苹果推送iOS10正式版以后,推送的注册方式出现了根本性变化,回调方法也发生了根本性变化。若你依旧沿用iOS9以及之前的写法,通知根本不会弹出。更为麻烦的是,许多老应用当初为了兼容iOS8,代码里留存着旧的推送注册逻辑,而这些代码在iOS10上会直接失效,从而使得用户收不到任何提醒。

推送开关必须打开

历经众多软件,Xcode8以及更高版本里,有关给用户设备发送特别提示,提供了一个能被看到开关,该内容为明确显式。其所在位置于项目的功能选项卡哪,位置也相当局限,你能够检索到名为发布有影响的通知的选项,把原本状态改成开启,变成启用的状态。好多开发软件的人员会忽视重要这一步骤要点,致使推送证书尽管安排配备正确,然而应用就是接收不到通知。

开启开关之后,系统会自行创建产出一个entitlements文件。此文件于开发阶段之时有可能出现报错状况,特别是在你将开发环境由Development换至Production之际,APS Environment字段会呈现出错误情形。碰到这种状况时,点击Fix Issue即便能够消除报错方面的因素,但却有可能再度把环境变回Development。

经过实际的测试得出,打包生成的那个ipa包里是不包含这个entitlements文件的,因此我的那种建议是这样。就是,千万别去纠结于这个开关是不是会报错。只要证书配置得正确无误,那就直接进行打包然后着手测试就好了。用生产证书去打包以后,借助极光推送的生产状态的环境来发送消息,消息是能够正常被收到的。

系统自带推送的注册流程

在iOS10的环境下,远程推送的注册代码是需要进行重写工作的。首先呢,要导入UserNotifications.framework,并且要遵守UNUserNotificationCenterDelegate协议。而后呀,注册代码需放置在didFinishLaunchingWithOptions方法之中,其核心要点则是调用requestAuthorizationWithOptions方法去请求用户给予授权。

注册成功之后,获取device token这项操作所采用的方法并未发生改变,依旧是于didRegisterForRemoteNotificationsWithDeviceToken回调当中取得token然后将其上报给服务器,要注意的是,iOS10把以往旧有的didReceiveRemoteNotification方法予以废除了,新增了两个代理方式用以处理推送的接收以及点击。

通知的统一处理

#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import 
#endif

iOS10将本地通知、远程通知纳入合并处理历程。往昔之时,本地通知、远程通知依赖不同回调途径前行,如今一致经由UNUserNotificationCenterDelegate的两项具体方式:由willPresentNotification着手处理当处于前台阶段收到通知之际呈现的逻辑事项,借didReceiveNotificationResponse应对处理伴随用户 click点击通知单后生成的响应关联逻辑。

 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
  //iOS10特有
  UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
  // 必须写代理,不然无法监听通知的接收与点击
  center.delegate = self;
  [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
   if (granted) {
    // 点击允许
    NSLog(@"注册成功");
    [center getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
     NSLog(@"%@", settings);
    }];
   } else {
    // 点击不允许
    NSLog(@"注册失败");
   }
  }];
 }else if ([[UIDevice currentDevice].systemVersion floatValue] >8.0){
  //iOS8 - iOS10
  [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeSound | UIUserNotificationTypeBadge categories:nil]];
 }else if ([[UIDevice currentDevice].systemVersion floatValue] < 8.0) {
  //iOS8系统以下
  [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound];
 }
 // 注册获得device Token
 [[UIApplication sharedApplication] registerForRemoteNotifications];

要辨识通知类别得看UNNotificationTrigger类,倘若为远程推送情形下,trigger属于UNPushNotificationTrigger类型。要是属于本地通知范畴,鉴于触发条件存在差异,能够是UNTimeIntervalNotificationTrigger、UNCalendarNotificationtrigger或者UNLocationNotificationTrigger。

// 获得Device Token
 - (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
 NSLog(@"%@", [NSString stringWithFormat:@"Device Token: %@", deviceToken]);
}
// 获得Device Token失败
- (void)application:(UIApplication *)application
didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
 NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error);
}

于willPresentNotification方法当中,你能够抉择在处于前台之际是否展现通知弹窗。倘若未曾实现此方法,那么在前台接收到通知之时系统不会有任何的提示。于didReceiveNotificationResponse方法里面,你需要依据response.notification.request.content.userInfo来跳转至对应的页面。

旧版本方法的兼容

要是你有进行兼容iOS8以及iOS9的需求,那就不可以直接把旧的推送代码给删除掉 ,正确的做法是去做系统版本的判断。对于iOS10及往上的系统 ,要采用新的UNUserNotificationCenter方法 ;对于iOS10以下的系统 ,则继续运用原来的UIApplication注册方法。

在iOS10这个系统版本之上,那个旧的didReceiveRemoteNotification方法仍然会被调用起来,可有个前提条件,也即是你还没有去实现新设置设立的代理方法。要是你已经实现了新的方法,那么旧的方法就不会再一次被触发启动了。为了能够始终维持保持逻辑的统一整齐,建议在新的代理方法当中去调用旧的方法,如此一来一套代码便能够同时去兼容新旧不同的系统。

极光推送的适配方案

// iOS 10收到通知
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
 NSDictionary * userInfo = notification.request.content.userInfo;
 UNNotificationRequest *request = notification.request; // 收到推送的请求
 UNNotificationContent *content = request.content; // 收到推送的消息内容
 NSNumber *badge = content.badge; // 推送消息的角标
 NSString *body = content.body; // 推送消息体
 UNNotificationSound *sound = content.sound; // 推送消息的声音
 NSString *subtitle = content.subtitle; // 推送消息的副标题
 NSString *title = content.title; // 推送消息的标题
 if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
  NSLog(@"iOS10 前台收到远程通知:%@", [self logDic:userInfo]);
 }
 else {
  // 判断为本地通知
  NSLog(@"iOS10 前台收到本地通知:{\\\\nbody:%@,\\\\ntitle:%@,\\\\nsubtitle:%@,\\\\nbadge:%@,\\\\nsound:%@,\\\\nuserInfo:%@\\\\n}",body,title,subtitle,badge,sound,userInfo);
 }
 completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert); // 需要执行这个方法,选择是否提醒用户,有Badge、Sound、Alert三种类型可以设置
}

// 通知的点击事件
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{
 NSDictionary * userInfo = response.notification.request.content.userInfo;
 UNNotificationRequest *request = response.notification.request; // 收到推送的请求
 UNNotificationContent *content = request.content; // 收到推送的消息内容
 NSNumber *badge = content.badge; // 推送消息的角标
 NSString *body = content.body; // 推送消息体
 UNNotificationSound *sound = content.sound; // 推送消息的声音
 NSString *subtitle = content.subtitle; // 推送消息的副标题
 NSString *title = content.title; // 推送消息的标题
 if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
  NSLog(@"iOS10 收到远程通知:%@", [self logDic:userInfo]);
 }
 else {
  // 判断为本地通知
  NSLog(@"iOS10 收到本地通知:{\\\\nbody:%@,\\\\ntitle:%@,\\\\nsubtitle:%@,\\\\nbadge:%@,\\\\nsound:%@,\\\\nuserInfo:%@\\\\n}",body,title,subtitle,badge,sound,userInfo);
 }
 // Warning: UNUserNotificationCenter delegate received call to -userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: but the completion handler was never called.
 completionHandler(); // 系统要求执行这个方法
}

要是你运用的是极光推送,那适配之时就会简便不少。首先务必要保证极光推送的SDK版本为3.0.0及更高,只因仅有新版本才详尽支持iOS10的推送机制。进行注册通知时用不着自行书写系统注册代码,因为极光的registerForRemoteNotification方法内部已然处理了版本判断。

Warning: UNUserNotificationCenter delegate received call to -userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler: but the completion handler was never called.

于AppDelegate的didFinishLaunchingWithOptions之中调用极光的初始化方法,且于注册成功的回调之内上传device token。极光给出了两条新的代理方法,二者分别对应iOS10的通知接收以及点击事件,你仅需于极光的回调里编写自身的业务逻辑便可。

- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo {
 NSLog(@"iOS6及以下系统,收到通知:%@", [self logDic:userInfo]);
}
- (void)application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:
(void (^)(UIBackgroundFetchResult))completionHandler {
 NSLog(@"iOS7及以上系统,收到通知:%@", [self logDic:userInfo]);
 completionHandler(UIBackgroundFetchResultNewData);
}

实际测试方法

if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
 JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init];
 entity.types = UNAuthorizationOptionAlert|UNAuthorizationOptionBadge|UNAuthorizationOptionSound;
 [JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
#endif
 } else if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
  //可以添加自定义categories
  [JPUSHService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge |
              UIUserNotificationTypeSound |
              UIUserNotificationTypeAlert)
           categories:nil];
 } else {
  //categories 必须为nil
  [JPUSHService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |
              UIRemoteNotificationTypeSound |
              UIRemoteNotificationTypeAlert)
           categories:nil];
 }

在完成适配之后,务必要切实地开展真机测试。切莫过度依赖模拟器,因为模拟器的推送行为与真机是存在着差异之别的。首先要将其打包成为ipa文件,借助TestFlight或者直接安装到手机上面,接着使用极光推送的生产环境来发送一条消息出来。要是这条消息能够正常地弹出,那就表明适配已然成功了。

/*
 * @brief handle UserNotifications.framework [willPresentNotification:withCompletionHandler:]
 * @param center [UNUserNotificationCenter currentNotificationCenter] 新特性用户通知中心
 * @param notification 前台得到的的通知对象
 * @param completionHandler 该callback中的options 请使用UNNotificationPresentationOptions
 */
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger options))completionHandler;
/*
 * @brief handle UserNotifications.framework [didReceiveNotificationResponse:withCompletionHandler:]
 * @param center [UNUserNotificationCenter currentNotificationCenter] 新特性用户通知中心
 * @param response 通知响应对象
 * @param completionHandler
 */
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler;

测试的时候需留意手机系统版本,应当在iOS8,还有iOS9,以及iOS10这三个系统上开展测试,最终目的是要保障哪怕是处于老版本使用状态的用户依然能够收到推送,可是当前的状况是好多开发者居然仅仅只进行了对于最新系统的测试工作,并且全都忽略了那些依旧还在沿用iOS8和iOS9系统做手机使用的用户,随后便出现了上线之后收到数额可观的反馈消息直接表明收不到消息这种现象。

if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
 // 这个方法,不管是收到通知代理还是点击通知的代理,如果使用极光推送,我们都是需要增加这个方法的。
 [JPUSHService handleRemoteNotification:userInfo];
 NSLog(@"iOS10 收到远程通知:%@", [self logDic:userInfo]);
 [rootViewController addNotificationCount];
 }
 else {
 // 判断为本地通知
 NSLog(@"iOS10 收到本地通知:{\\\\nbody:%@,\\\\ntitle:%@,\\\\nsubtitle:%@,\\\\nbadge:%@,\\\\nsound:%@,\\\\nuserInfo:%@\\\\n}",body,title,subtitle,badge,sound,userInfo);
 }

你于适配iOS10推送之际,碰到过收不到消息这种情况,或者证书环境出现报错的状况吗?欢迎于评论区分享你那踩坑时的经历了,也牢记着要去点赞收藏呀,以便往后开发之时能够随时去查阅呢。

旋转小火锅定制流程

免费咨询

提供图纸

免费设计

免费报价

无忧安装

终身维护