iOS 极光推 Not get deviceToken yet,didReceiveRemoteNotification withCompletionHandler

前言:

真的,我就挺服气的,哪里来的这么多bug。

在聊bug之前,我们首先来做个测试用的 demo,我们把极光推送集成进来。

1、假设你在Apple后台已经配置好了推送的开发证书和生产证书,并且你把这个证书导出p12文件上传到极光并且通过了验证。 (我这里开发环境和生产环境是区分开的),极光教程:

极光推送官方证书配置教程

我的配置.png

2、假设你已经创建了新工程,使用 pod 集成极光推送。
3、你需要在把项目配置一下,允许项目使用通知,允许在后台接收到通知消息。
项目配置添加推送.png
4、把极光推送的示例代码拷贝到 AppDelegate.m
#import "AppDelegate.h"

// 引入 JPush 功能所需头文件
#import "JPUSHService.h"
// iOS10 注册 APNs 所需头文件
#ifdef NSFoundationVersionNumber_iOS_9_x_Max
#import <UserNotifications/UserNotifications.h>
#endif

@interface AppDelegate ()<JPUSHRegisterDelegate>

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        
    //Required
    //notice: 3.0.0 及以后版本注册可以这样写,也可以继续用之前的注册方式
    JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init];
    if (@available(iOS 12.0, *)) {
        entity.types = JPAuthorizationOptionAlert|JPAuthorizationOptionBadge|JPAuthorizationOptionSound|JPAuthorizationOptionProvidesAppNotificationSettings;
    } else {
        // Fallback on earlier versions
    }
    if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) {
        // 可以添加自定义 categories
        // NSSet<UNNotificationCategory *> *categories for iOS10 or later
        // NSSet<UIUserNotificationCategory *> *categories for iOS8 and iOS9
    }
    [JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
    
    
    // Optional
    // 获取 IDFA
    // 如需使用 IDFA 功能请添加此代码并在初始化方法的 advertisingIdentifier 参数中填写对应值
    //NSString *advertisingId = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
    
    // Required
    // init Push
    // notice: 2.1.5 版本的 SDK 新增的注册方法,改成可上报 IDFA,如果没有使用 IDFA 直接传 nil
    [JPUSHService setupWithOption:launchOptions appKey:@"d25a9995b0198799bc47b1ef"
                          channel:@"AKK"
                 apsForProduction:NO
            advertisingIdentifier:nil];
    
    
    return YES;
}


- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    /// Required - 注册 DeviceToken
    [JPUSHService registerDeviceToken:deviceToken];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    //Optional
    NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error);
}

#pragma mark- JPUSHRegisterDelegate
// iOS 12 Support
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center openSettingsForNotification:(UNNotification *)notification{
    if (notification && [notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        //从通知界面直接进入应用
        NSLog(@"从通知界面直接进入应用");
    }else{
        //从通知设置界面进入应用
        NSLog(@"从通知设置界面进入应用");
    }
}

// iOS 10 Support
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler {
    // Required
    NSDictionary * userInfo = notification.request.content.userInfo;
    if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        [JPUSHService handleRemoteNotification:userInfo];
    }
    completionHandler(UNNotificationPresentationOptionAlert); // 需要执行这个方法,选择是否提醒用户,有 Badge、Sound、Alert 三种类型可以选择设置
}

// iOS 10 Support
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
    // Required
    NSDictionary * userInfo = response.notification.request.content.userInfo;
    if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        [JPUSHService handleRemoteNotification:userInfo];
    }
    completionHandler();  // 系统要求执行这个方法
}

- (void)jpushNotificationAuthorization:(JPAuthorizationStatus)status withInfo:(NSDictionary *)info {
    
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    
    NSLog(@"APP在后台收到消息:  \n %@", userInfo);
    
    // Required, iOS 7 Support
    [JPUSHService handleRemoteNotification:userInfo];
    completionHandler(UIBackgroundFetchResultNewData);
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    NSLog(@"APP在后台收到消息:  \n %@", userInfo);
    // Required, For systems with less than or equal to iOS 6
    [JPUSHService handleRemoteNotification:userInfo];
}

#pragma mark - UISceneSession lifecycle
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options  API_AVAILABLE(ios(13.0)){
    // Called when a new scene session is being created.
    // Use this method to select a configuration to create the new scene with.
    return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
}

- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions  API_AVAILABLE(ios(13.0)){
    // Called when the user discards a scene session.
    // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
    // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}

5、Command + R,运行项目,发送通知。

然而,有些时候,期望不尽人意,你没有收到推送。

BUG 1 :[JPUSHClientController] Not get deviceToken yet.

极光控制台打印提示:
[JPUSHClientController] Not get deviceToken yet. Maybe: your certificate not configured APNs? or current network is not so good so APNs registration failed? or there is no APNs register code? Please refer to JPush docs.

出现这个提示,基本上就是因为注册通知失败了,也就是项目启动的时候没有调用下面这个函数:

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {}

这个函数必须被调用,你才能收到通知。在调试的时候,在这个函数上打断点,看是否成功注册。

注册设备.png

如果你打了断点,发现仍然没有调用这个函数,而且,就连注册失败的回调都不走:

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {}

那么,原因可能有以下:

1、尝试在 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {}
添加 :[[UIApplication sharedApplication] registerForRemoteNotifications]; 强行注册通知。

2、你在调试的时候,多次卸载 App 然后重新运行,如此操作,该代理方法就不会走了。要么换手机,要么就等到它能回调。我等过几个小时才好,如果等到第二天,它也能好,因为,我等过。MD。

或者参考以下玩家的文章:

IOS didRegisterForRemoteNotificationsWithDeviceToken没有执行

关于推送(无法获取DeviceToken)

Not getting APNS Device token on ios 13

BUG 2 :didReceiveRemoteNotification: fetchCompletionHandler: 方法不回调

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {}
方法不回调。

当你把App退到后台(没有杀掉),然后你发推送,期望App在后台也能收推送的内容。然而你的手机上出现了通知横幅,但是却没有触发后台收到通知的函数(didReceiveRemoteNotification:fetchCompletionHandler:),因此你也就无法拿到通知的内容。原因有以下:

1、检查通知的内容是否包含 “content-available” 这个字段,这个字段对应布尔值,设置为true,App在后台才能收到内容:
在极光后台发送通知的时候,需要勾选这个字段:


极光推送页.png

在你的项目调试里面,这个字段是这样的:


字段.png

2、确保你的项目里面,在 Background Modes 里面 勾选了 Remote notification

3、如果你已经成功注册了设备,并且你已经正确设置了content-available = 1字段,也勾选了勾选了 Remote notification,但是!这个回调还是没有走,那么可能是iOS系统问题。我遇到过。我在调试的时候,用的手机是 iOS 13.5,iOS 13.3,这玩意就像抽疯了一样,时好时坏,上午怎么调试都收不到,睡一觉等到下午调试,又莫名其妙地收到通知了。隔天,我拿了自己的测试机,iOS 10.2.1,把App退到后台,我100%能收到通知,没有一个漏的。关于这个问题,我找了很多网上资料,也给极光提问了,以下文章给玩家参考:

我在极光官网上的提问

极光官网的回复

极光:iOS13 出现 Not get deviceToken yet, iOS12 不会

极光社区问题汇总页

苹果官网有人提问 iOS 13.3 收不到通知

stackoverflow 上的提问

后续

「JPush」收不到消息的排查方案

iOS 收不到消息 / 排查不出请根据第 5 点说明提供信息

iOS,APP退到后台,获取推送成功的内容并且语音播报内容。

iOS开发之极光推送的那些坑

iOS极光推送突然收不到推送消息

(Not get deviceToken yet )极光推送不成功deviceToken未获取

添加推送功能时 didRegisterForRemoteNotificationsWithDeviceToken不调用

关于didRegisterForRemoteNotificationsWithDeviceToken不执行的问题

IOS 不走didRegisterForRemoteNotificationsWithDeviceToken的解决方案

结语:

来这家写代码,每次需求,都能遇到些疑难杂症,bug还比较硬,很特么的是烦。今年因为 iOS系统 和 Mac系统 而导致的bug格外地多。就让人感觉很无语,很无聊,啥也不是。我都不想再写代码了。

推荐阅读更多精彩内容