前言:
真的,我就挺服气的,哪里来的这么多bug。
在聊bug之前,我们首先来做个测试用的 demo,我们把极光推送集成进来。
1、假设你在Apple后台已经配置好了推送的开发证书和生产证书,并且你把这个证书导出p12文件上传到极光并且通过了验证。 (我这里开发环境和生产环境是区分开的),极光教程:

2、假设你已经创建了新工程,使用 pod 集成极光推送。
3、你需要在把项目配置一下,允许项目使用通知,允许在后台接收到通知消息。

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 {}
这个函数必须被调用,你才能收到通知。在调试的时候,在这个函数上打断点,看是否成功注册。

如果你打了断点,发现仍然没有调用这个函数,而且,就连注册失败的回调都不走:
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {}
那么,原因可能有以下:
1、尝试在 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {}
添加 :[[UIApplication sharedApplication] registerForRemoteNotifications];
强行注册通知。
2、你在调试的时候,多次卸载 App 然后重新运行,如此操作,该代理方法就不会走了。要么换手机,要么就等到它能回调。我等过几个小时才好,如果等到第二天,它也能好,因为,我等过。MD。
或者参考以下玩家的文章:
IOS didRegisterForRemoteNotificationsWithDeviceToken没有执行
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在后台才能收到内容:
在极光后台发送通知的时候,需要勾选这个字段:

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

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 收不到消息 / 排查不出请根据第 5 点说明提供信息
iOS,APP退到后台,获取推送成功的内容并且语音播报内容。
(Not get deviceToken yet )极光推送不成功deviceToken未获取
添加推送功能时 didRegisterForRemoteNotificationsWithDeviceToken不调用
关于didRegisterForRemoteNotificationsWithDeviceToken不执行的问题
IOS 不走didRegisterForRemoteNotificationsWithDeviceToken的解决方案
结语:
来这家写代码,每次需求,都能遇到些疑难杂症,bug还比较硬,很特么的是烦。今年因为 iOS系统 和 Mac系统 而导致的bug格外地多。就让人感觉很无语,很无聊,啥也不是。我都不想再写代码了。
网友评论