iOS13 deviceToken 获取失败,获取不完整 导致推送失败 apns推送失败

一个iOS13适配的问题。目前会导致一些第三方的推送失败,比如环信
我目前的app里面集成的是环信3.6之前的版本,出现无法收到推送的问题,
首先用Easy APNs Provider验证一下推送证书是不是有问题,需要获取设备的devicetoken,
一般来说我们会在以下代码中获取deviceToken:

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    //1
    NSLog(@"deviceToken:%@",deviceToken);
    //2
    NSString *token = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
    token = [token stringByReplacingOccurrencesOfString:@" " withString:@""];
    NSLog(@"\n>>>[DeviceToken Success]:%@\n\n", token);
  
    [[NSUserDefaults standardUserDefaults] setObject:deviceToken forKey:@"deviceTokenData"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

打印结果是:

deviceToken:{length = 32, bytes = 0x5b829d46 063b18f9 99a7799c 6921ab00 ... 054a5633 f4d4d27a }

>>>[DeviceToken Success]:{length=32,bytes=0x5b829d46063b18f999a7799c6921ab00...054a5633f4d4d27a}

可以看到控制台打印的信息不完整的,中间缺少了16位,显示为“...”
我一开始以为只是控制台对于64位的data数据显示做了处理,所以我为了测试推送,添加了第三种获取token的方式:

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    //1
    NSLog(@"deviceToken:%@",deviceToken);
    //2
    NSString *token = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
    token = [token stringByReplacingOccurrencesOfString:@" " withString:@""];
    NSLog(@"\n>>>[DeviceToken Success]:%@\n\n", token);
    //3
    NSMutableString *deviceTokenString = [NSMutableString string];
    const char *bytes = deviceToken.bytes;
    NSInteger count = deviceToken.length;
    for (int i = 0; i < count; i++) {
        //%02x  (x代表以十六进制形式输出,02代表不足两位,前面补0输出,如果超过两位,则以实际输出)
        [deviceTokenString appendFormat:@"%02x", bytes[i]&0x000000FF];
    }
    UIPasteboard *pab = [UIPasteboard generalPasteboard];
    [pab setString:deviceTokenString];
    NSLog(@"deviceTokenString:%@",deviceTokenString);
    [[NSUserDefaults standardUserDefaults] setObject:deviceToken forKey:@"deviceTokenData"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

这次,能获取到完整的token了。因为要测试正式环境下的推送问题,所以打的adHoc包,并且自动复制token,就可以在app外粘贴出来发送到电脑上进行推送测试啦:

deviceTokenString:5b829d46063b18f999a7799c6921ab0067571c83e0740b9e054a5633f4d4d27a

之后通过验证,推送证书没问题。才开始联系环信,得知是iOS13对于devicetoken的处理导致的,环信已经在3.6.4的包修复了此问题。
然而新的环信sdk暂时还不能通过cocoapods集成,考虑到手动集成,可能会出现让我不想遇到的:或是引用或是文件路径或是文件冲突或者其他乱七八糟的问题,所以研究一下暂时不更新sdk的解决办法。

查了一些资料得出的结果:
nslog在使用的时候会调用log对象的description方法,返回值是一个字符串,有时候我们log一些自定义的类,显示为<类名:地址>,就是description返回字符串的内容。想详细了解的可以查看:
https://www.jianshu.com/p/f4722479758d
所以可以猜测环信sdk里面,对我们传进去的data类型的token用的就是:

NSString *tokenStr = [deviceToken description];
//转为字符串之后,上报到服务器或者拿来参与别的方法

转为string类型数据,然后再sdk里面使用的。
所以尝试一下把所有环信用到token的接口,改为将deviceToken字节转化为字符串deviceTokenString后,将deviceTokenString传入环信SDK
改完代码,打adHoc包,进行测试。成功收到APNs推送。

猜测环信SDK里面拿到Token之后,应该直接调用了description方法,转为字符串进行后续的操作,结果iOS13之后转出此方法转出的字符串比较长时,中间会有“...”,导致环信服务端无法收到正确的deviceToken 。
我们传string类型数据进去,执行description方法并不会报错,并且能返回正确的deviceToken字符串(也就是其本身)。

最后附上一个16进制格式的nsstring直转nsdata的方法:

//字符串里的每一位是一个16进制数字,每两个16进制位是一个2的八次方,等于一个btye,等于nsdata中的一个字节。
所以for循环每次+2.
NSMutableData* data = [NSMutableData data];
int idx;
for (idx = 0; idx+2 <= deviceTokenString.length; idx+=2) {
        NSRange range = NSMakeRange(idx, 2);
        NSString* hexStr = [deviceTokenString substringWithRange:range];
        NSScanner* scanner = [NSScanner scannerWithString:hexStr];
        unsigned int intValue;
        [scanner scanHexInt:&intValue];
        [data appendBytes:&intValue length:1];
}

你可能感兴趣的:(iOS13 deviceToken 获取失败,获取不完整 导致推送失败 apns推送失败)