标题写得有点长,好让BAIDU愚蠢的SEO能找到。zzzzzz
最近图方便app迭代加入了极光的认证登录,百度一圈没找到解决方法,现在踩坑完毕了叶总要留下点什么。这个好东西呢,本身是个好东西,但是既然你是收费的好歹写好文档严格控制控制代码质量,而不是让开发者自己去踩坑,像我这种搬运工还要花力气整理呢,碰上懒一点的解决完自己的问题也就算了。结果一大帮像我这样的人还要花费时间修轮子。估计也没谁像我这样一半时间coding一半时间写经验的了呵呵。
由于版本不一样可能有所不同,不知道别人会不会修复修复,但求后人有参考,一切不写版本号的教程都是耍流氓。
$cat Podfile.lock查看pod库的版本。JPush(3.2.1)和JVerification(2.6.3)都使用了JCore(2.2.5)
两个模块整合前最好单独分别测试是否能通能用,以排除因为账号、证书、Bundleid等配置问题导致的错误。反正我两个模块都分开单独测试了。
当你乖乖按照极光官网那过时的教程加上一点百度coding完毕后。
···objectivec
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
......
[self registJpush:application :launchOptions];
[self Jverify];
}
-(void)Jverify{
JVAuthConfig *config = [[JVAuthConfig alloc] init];
config.appKey = appKey;
[JVERIFICATIONService setDebug:YES];
[JVERIFICATIONService setupWithConfig:config];
}
-(void)registJpush:(UIApplication *)application :(NSDictionary *)launchOptions{
if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
JPUSHRegisterEntity * entity = [[JPUSHRegisterEntity alloc] init];
entity.types = UNAuthorizationOptionAlert|UNAuthorizationOptionBadge|UNAuthorizationOptionSound;
[JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
}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];
}
//初始换JPush
[JPUSHService setupWithOption:launchOptions appKey:appKey
channel:channel
apsForProduction:isProduction
advertisingIdentifier:nil]; // 这里是没有advertisingIdentifier的情况,有的话,大家在自行添加
//添加监听通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkDidLogin:) name:kJPFNetworkDidLoginNotification object:nil];
//注册远端消息通知获取device token
[application registerForRemoteNotifications];
}
···
然后在业务控制器中加入官方提供的demo抠出来的代码,因为是没有教程告诉你怎么调用的。
···objectivec
-(void)configJVerify{
[JVERIFICATIONService getAuthorizationWithController:self hide:NO completion:^(NSDictionary *result) {
NSString *token = result[@"loginToken"];
NSInteger code = [result[@"code"] integerValue];
if(token){
dispatch_async(dispatch_get_main_queue(), ^{
[self verifyLoginToken:token];//得到token调用登录接口
});
}else if (code == 6004){
}else if(code != 6002){
[self mbShowToast:KLString(@"无效token")];
}
}];
}
···
锵!赶紧commond+r跑起来。然而什么都没有发生,继续对比了官方提供的demo,有个JVTelecomViewConreoller,翻烂都没在库里找到,应该是打包成framework了。不过还是能找到配置它的地方,把这些臭臭长长的UI代码复制到我们的业务控制器viewDidLoad初始化就行了,把图片改成自己想要的,比较随便。
再commond+r,页面还是没有按照demo那样显示出来。命名我单独测试的时候是没问题的,一切正常,把推送部分的代码注释掉也正常。为什么加上极光推送就不行了,那一定是两个模块公共部分的代码冲突了,说的就是JCore,首先推送和认证都分别初始化,推送的初始化先执行,极光服务器先收到JPush的业务请求,但这时候,我业务控制器已经调用的极光认证部分的方法getAuthorizationWithController,两个模块又是使用同一个JCore同一个appKey,那么很大可能是因为异步的原因,在JCore未接收到服务器返回的token的时候,认证模块已经访问了一个空的token,getAuthorizationWithController方法就很自然地返回了空。这个token业务是抽象的,我也不知道具体是什么,又看不到源码。我也不知道毕竟我是猜的。
根据这个猜想,我将认证的注册部分(在AppDelegate)和调用部分(业务控制器)分别开辟了5秒和10秒的延时线程执行:
···objectivec
//AppDelegate
__block ViewController *weakSelf = self;dispatch_time_tdelayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0* NSEC_PER_SEC));dispatch_after(delayTime, dispatch_get_main_queue(), ^{ [weakSelf Jverify];});
//业务控制器
__block ViewController *weakSelf = self;dispatch_time_tdelayTime =
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0*
NSEC_PER_SEC));dispatch_after(delayTime, dispatch_get_main_queue(), ^{
[weakSelf configJVerify];});
···
完美!可以打开,证明确实是异步问题,而这个问题官网是没有任何说明的。
既然知道了问题所在,就再修修边幅吧,我发现JPush注册完deviceToken之后是有这个通知回调的:kJPFNetworkDidLoginNotification。盲猜是注册完毕推送后的回调。于是在业务控制器注册了观察者,当收到kJPFNetworkDidLoginNotification时再去调用getAuthorizationWithController方法,确保认证模块的业务是在推送注册执行完后再执行的,修改代码如下:
···objectivec
- (void)viewDidLoad {
[super viewDidLoad];
............
[self JVerifyCustomUI];
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:@selector(configJVerify) name:kJPFNetworkDidLoginNotification object:nil];
}
···
这里还特别说明一下getAuthorizationWithController这个方法,同样极光也是没有任何文档提及过,好歹说明下返回参数,继续盲猜。
在执行到configJVerify这方法的同时,弹出了“无效token”的提示。并且打了断点证明这个completion比方法的第一行都要早执行。
差不多搞定了,只是最后有点困惑,就再琢磨一下,说不定能帮到用需要的人。查了一下这次completion块返回的code值,是6004。
这就印证了我的之前的想法。因为这个推送初始化完成后通过通知调用的,因为共用了JCore,JCore队列执行了所有的completion。那么只可能第一次的completion是推送模块通过JCore执行的,第二次的completion是认证模块通过JCore执行的。调用就调用吧,反正没崩溃,写个else if(code == 6004){}把这个过滤掉就行了。这也让我加深了对block的了解,block的可否调用,跟谁去声明它是没有必然联系的。
最后还是希望极光把这个隐藏的bug改过来,毕竟也是很浪费时间的,还有完善一下那咸丰年写的文档。
网友评论