iOS极光推送别名限制问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS极光推送别名限制问题相关的知识,希望对你有一定的参考价值。
参考技术A 我们的项目中集成了极光推送,将用户id设置为别名,方便服务端对某个用户发送自定义消息。前几天遇到了一个用户反应无法收到推送,经过调试发现在设置别名时返回了错误码6009,极光官网的说明如下:然后设置为debug模式,依然不知道是什么原因。于是先想到的就是升级一下SDK。升到最新版3.4.0之后,错误码变成了6017。错误原因如下:
然后在极光官方文档上发现了这样一句话:
RegistrationID就算作一个设备,即使我们是同一个手机,在卸载重装之后如果RegistrationID发生变化,就会算作一个新的设备,当重复卸载重装就会出现别名绑定失败,导致接收不到推送。
什么情况下RegistrationID会发生变化
然后我就尝试卸载重装,发现RegistrationID并未发生变化,这就很奇怪了。又是一通查找,找到了 这篇文章
里面有提到极光内部的一些处理,极光会将数据保存到粘贴板,如果重装时发现粘贴板有数据,RegistrationID就跟上次一样,如果没有数据,就会生成新的RegistrationID。
然后尝试卸载APP后关机重启,再安装。RegistrationID果然发生了变化。
到现在知道了收不到推送的原因了,极光官方提倡我们去充钱,能将设备上限提升到100个。但是无法从根本上解决问题,所以继续寻找解决方案。
在极光服务端的API文档中找到了 这一部分
我们可以在客户端通过调用极光服务端的API,解除别名绑定的设备。
具体解决思路如下:
极光在2020/03/10对别名绑定的设备数做了限制,在之前接入极光SDK的APP,使用别名功能时应该都存在这个问题的隐患,在此记录一下。
不得不吐槽一下极光的文档,对于设备也就是RegistrationID是否发生变化说的并不准确,而且ios的SDK里并未提供批量解除别名绑定的API。
至于这个API到底是由客户端去调用还是服务端去调用,就仁者见仁智者见智了。
iOS: 极光推送
之前做过环信和友盟的推送,照着官方文档集成其实挺简单的,今天公司需要,特地做了一下极光推送。不用不知道,原来极光推送集成如此简单,不得不说说了。
当然做推送钱需要做一些准备工作了,就是推送必须的p12推送证书:开发环境(开发时测试需要的推送证书)、生产环境(发布到AppStore时需要的推送证书),因为xcode已经升级到了7.0以上,所以一些真机测试的配置文件证书就不需要自己手动去创建了,只要有Apple ID,真机测试时,就能自动生成,免费测试:
制作证书的过程就不啰嗦了,详细看官方文档或者如下推荐:
http://jingyan.baidu.com/article/c1465413975cba0bfcfc4ccf.html
http://docs.jpush.io/client/ios_tutorials/#ios_1
http://docs.jpush.io/guideline/ios_guide/
http://allluckly.cn/投稿/tuogao28?utm_source=tuicool&utm_medium=referral
创建完证书,就是去极光官网注册账号,创建应用,截图如下:
将创建的证书上传到应用上了,上传成功后的截图如下:
证书上传成功后,生成APP Key,截图如下:
好了,这下工作做完了,剩下的就是代码实现了:
第一步:下载SDK,将需要的两个文件导入项目中:
集成压缩包内容
包名为JPush-iOS-SDK-{版本号}
- lib文件夹:包含头文件 JPUSHService.h,静态库文件jpush-ios-x.x.x.a ,支持的iOS版本为 5.0 及以上版本。(请注意:模拟器不支持APNs)
- pdf文件:集成指南
- demo文件夹:示例
第二步:导入需要依赖的库文件:
必要的框架
- CFNetwork.framework
- CoreFoundation.framework
- CoreTelephony.framework
- SystemConfiguration.framework
- CoreGraphics.framework
- Foundation.framework
- UIKit.framework
- Security.framework
- Xcode7需要的是libz.tbd;Xcode7以下版本是libz.dylib
- Adsupport.framework (获取IDFA需要;如果不使用IDFA,请不要添加)
第三步:创建一个工具类,名称为KJJPushHelper,封装注册时的各种方法
.h
// // KJJPushHelper.h // // Created by mac on 16/5/5. // Copyright © 2016年 mac. All rights reserved. // #import <Foundation/Foundation.h> @interface KJJPushHelper : NSObject // 在应用启动的时候调用 + (void)setupWithOption:(NSDictionary *)launchingOption appKey:(NSString *)appKey channel:(NSString *)channel apsForProduction:(BOOL)isProduction advertisingIdentifier:(NSString *)advertisingId; // 在appdelegate注册设备处调用 + (void)registerDeviceToken:(NSData *)deviceToken; // ios7以后,才有completion,否则传nil + (void)handleRemoteNotification:(NSDictionary *)userInfo completion:(void (^)(UIBackgroundFetchResult))completion; // 显示本地通知在最前面 + (void)showLocalNotificationAtFront:(UILocalNotification *)notification; @end
.m
// // KJJPushHelper.m // Created by mac on 16/5/5. // Copyright © 2016年 mac. All rights reserved. // #import "KJJPushHelper.h" #import "JPUSHService.h" @implementation KJJPushHelper + (void)setupWithOption:(NSDictionary *)launchingOption appKey:(NSString *)appKey channel:(NSString *)channel apsForProduction:(BOOL)isProduction advertisingIdentifier:(NSString *)advertisingId{ // Required #if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_7_1 // ios8之后可以自定义category if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0) { // 可以添加自定义categories [JPUSHService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil]; } else { #if __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_8_0 // ios8之前 categories 必须为nil [JPUSHService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert) categories:nil]; #endif } #else // categories 必须为nil [JPUSHService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert) categories:nil]; #endif // Required [JPUSHService setupWithOption:launchingOption appKey:appKey channel:channel apsForProduction:isProduction advertisingIdentifier:advertisingId]; return; } + (void)registerDeviceToken:(NSData *)deviceToken { [JPUSHService registerDeviceToken:deviceToken]; return; } + (void)handleRemoteNotification:(NSDictionary *)userInfo completion:(void (^)(UIBackgroundFetchResult))completion { [JPUSHService handleRemoteNotification:userInfo]; if (completion) { completion(UIBackgroundFetchResultNewData); } return; } + (void)showLocalNotificationAtFront:(UILocalNotification *)notification { [JPUSHService showLocalNotificationAtFront:notification identifierKey:nil]; return; } @end
第四步:创建一个APPDelegate的分类,在该类中调用KJJPushHelper中的类方法
// AppDelegate+KJJPushSDK.h // // Created by mac on 16/5/5. // Copyright © 2016年 mac. All rights reserved. // #import "AppDelegate.h" @interface AppDelegate (KJJPushSDK) -(void)JPushApplication:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions; @end // AppDelegate+KJJPushSDK.m // // Created by mac on 16/5/5. // Copyright © 2016年 mac. All rights reserved. // #import "AppDelegate+KJJPushSDK.h" #import "KJJPushHelper.h" #define JPushSDK_AppKey @"31e01f6a2f6d4b1209061aec" #define isProduction NO @implementation AppDelegate (KJJPushSDK) -(void)JPushApplication:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ [KJJPushHelper setupWithOption:launchOptions appKey:JPushSDK_AppKey channel:nil apsForProduction:isProduction advertisingIdentifier:nil]; } - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { // Required - 注册 DeviceToken [KJJPushHelper registerDeviceToken:deviceToken]; } - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { // Required,For systems with less than or equal to iOS6 [KJJPushHelper handleRemoteNotification:userInfo completion:nil]; } - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { // IOS 7 Support Required [KJJPushHelper handleRemoteNotification:userInfo completion:completionHandler]; // 应用正处理前台状态下,不会收到推送消息,因此在此处需要额外处理一下 if (application.applicationState == UIApplicationStateActive) { UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"收到推送消息" message:userInfo[@"aps"][@"alert"] delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定",nil]; [alert show]; } } - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { //Optional NSLog(@"did Fail To Register For Remote Notifications With Error: %@", error); } - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { [KJJPushHelper showLocalNotificationAtFront:notification]; return; } - (void)applicationDidBecomeActive:(UIApplication *)application { [application setApplicationIconBadgeNumber:0]; return; } @end
第五步:在AppDelegate中注册即可
//注册极光推送 [self JPushApplication:application didFinishLaunchingWithOptions:launchOptions];
好了,大功告成,插上真机运行:打印结果如下
去官网测试一下:
真机收到消息截图:
集成过程中遇到的问题,困扰了好久,后来找出来了,分享一下:
当时证书一切都没有问题,但是总是出现这个打印:
错误信息JPUSH | W - [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.
推送消息时,出现的提示:
我的原因是:
由于项目之前用到了环信SDK,环信得已经注册了通知,在AppDelegate中注册通知,didRegisterForRemoteNotificationsWithDeviceToken与didFailToRegisterForRemoteNotificationsWithError方法,均不执行。。。需到环信注册通知的地方,再次注册极光通知。方可以获取到Token执行。
扩展:极光推送中的定向推送
极光推送中,不使用广播推送,那么怎样做到定向推送,是开发者和需求一定会出现的问题,极光推送中可以有两个唯一值:
(1)注册Jpush成功后生成的registrationID,这个registrationID是标记设备唯一性的,你发现,当你在启动多次,注册Jpush时,这个值是不变的;在同一个设备上,更换用户登录,这个值仍然不变;最后,你删除应用程序,再下载时启动注册Jpush,这个值还是不变。这就可以定向向某台设备做推送,如果你能给自己的服务器上传这个值,并且给这个值绑定一些东西,是不是可以做更多事情呢。
(2)alias:只要了解极光推送的都知道这是设置别名的,官方文档上说明了这个值不是唯一的,但是建议开发者把它作为用户的唯一标记。我觉得这个作为唯一值是最好的,当你想定向向某个用户做推送,或者召唤他回归我们的应用程序,这个值就太好了。你可以将它设置为userId,这个时候推送就能知道向哪个用户发了。
以上是关于iOS极光推送别名限制问题的主要内容,如果未能解决你的问题,请参考以下文章