iOS10以及XCode8适配问题汇总

升级iOS10以后,遇到了很多新的的问题。经过一段时间的适配,暴露的问题基本都已经解决。这里把这些问题作一个统一的汇总,方便其他同学再遇到类似的问题时,进行查阅。
这些问题,大致分为下面几类:

一、权限crash闪退

iOS 10 开始对隐私权限更加严格,如果你不设置就会直接崩溃,现在很多遇到崩溃问题了,一般解决办法都是在info.plist文件添加对应的Key-Value就可以了。如下图:

iOS10以及XCode8适配问题汇总_第1张图片

特别注意:value值不能为空,否则AppStore提交会审核被拒。

二、系统版本方法判断失效

由于iOS系统已经升级到iOS10,版本号由1位数变成了2位数,在之前处理版本号相关的代码需要重新检查确认没有使用错误,Firefly iOS组便发现此前使用的版本号判断方法上存在缺陷。
项目组在此之前通过使用compare来对iOS系统的版本进行比较,具体代码如下:

[[[UIDevicecurrentDevice] systemVersion] compare:@"9.0"] != NSOrderedAscending;

上述的代码的意图是判断当前iOS系统与9.0的关系,本来是要将字符串转化成数字之后与9.0进行比较,然后得出结果。但在compare时存在缺陷,直接使用compare函数在比较时是将两者当成字符串进行字典比较,并非按预想根据数值比较。在iOS10版本之前,这行代码返回的结果是对的,因为数字1-9在字典中的顺序与数字顺序一致,所以并未出错。但当iOS升级到10后,版本获取返回的”10.0”与”9.0”比较时,会按字符串进行字典比较,进而先将”1”与”9”比较,结果发现”1”在”9”前面,从而认为”10.0”小于”9.0”,得出错误结果,导致许多依赖版本的方法运行出错。该方法有点类似于当年的千年虫,缺陷会在某个时间才会暴露出来,iOS升级到10便触发这个bug的原因。版本判断正确的方法是使用带options的compare函数,如下所示:

[[[UIDevicecurrentDevice] systemVersion] compare:@"9.0" options:NSNumericSearch] != NSOrderedAscending;
  • 之前如果存在类似的代码:
#define IOS10_OR_LATER ( [[[UIDevice currentDevice] systemVersion] compare:@"10.0"] != NSOrderedAscending )
#define IOS9_OR_LATER ( [[[UIDevice currentDevice] systemVersion] compare:@"9.0" ] != NSOrderedAscending )
  • iOS10以后要采用更加严谨的判断方法:
#define IOS10_OR_LATER  ( [[[UIDevice currentDevice] systemVersion] compare:@"10.0" options:NSNumericSearch] != NSOrderedAscending )
#define IOS9_OR_LATER  ( [[[UIDevice currentDevice] systemVersion] compare:@"9.0" options:NSNumericSearch] != NSOrderedAscending )
#define IOS8_OR_LATER  ( [[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] != NSOrderedAscending )
#define IOS7_OR_LATER  ( [[[UIDevice currentDevice] systemVersion] compare:@"7.0" options:NSNumericSearch] != NSOrderedAscending )
#define IOS6_OR_LATER  ( [[[UIDevice currentDevice] systemVersion] compare:@"6.0" options:NSNumericSearch] != NSOrderedAscending )
#define IOS5_OR_LATER  ( [[[UIDevice currentDevice] systemVersion] compare:@"5.0" options:NSNumericSearch] != NSOrderedAscending )
#define IOS4_OR_LATER  ( [[[UIDevice currentDevice] systemVersion] compare:@"4.0" options:NSNumericSearch] != NSOrderedAscending )
#define IOS3_OR_LATER  ( [[[UIDevice currentDevice] systemVersion] compare:@"3.0" options:NSNumericSearch] != NSOrderedAscending )
三、控制台多余log

XCode8新建一个工程,运行。会发现控制台输出很多系统级别的log,如果不想看到这些log,解决办法是设置OS_ACTIVITY_MODE : disable。
具体的途径是:【product】-【scheme】-【Edit Scheme】-【Run】-【Argument】-【Environment Variable】添加keyValue【OS_ACTIVITY_MODE disable】可以停止输出打印此日志。

iOS10以及XCode8适配问题汇总_第2张图片
四、IDFA获取失败

首先关于IDFA的说明文档,有这么一句话:

Important
In iOS 10.0 and later, the value of advertisingIdentifier is all zeroes when the user has limited ad tracking.

ios10更新之后一旦开启了 设置->隐私->广告->限制广告跟踪之后 获取到的idfa将会是一串00000 ,而且每次开启在关闭之后 相应的idfa也会重新生成,相当于还原了一次广告标识符。
针对这种修改,目前Firefly_iOS采用的解决方案是:
设备标识首先采用IDFA,获取时增加判断[[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled],如果获取不到,就返回vender ID。
同时,新增一个用户设备指纹接口,专门标识用户的使用设备是否发生变化。采用的方案是verder id + keychain。第一次将verder id存入keychain,之后都从keychain获取。
相关代码实现:

+ (NSString *)deviceIdentifier
{
    static NSString *_identify = nil;
    static  dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (_identify == nil)
        {
            // iOS10以后IDFA可能会由于设置获取不到
            if ([[ASIdentifierManager sharedManager] isAdvertisingTrackingEnabled])
            {
                _identify = [[[ASIdentifierManager sharedManager] advertisingIdentifier] UUIDString];
            }
            else
            {
                _identify = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
            }
        }
    });
    
    return _identify;
}

+ (NSString *)verifyCode
{
    static NSString *_identify = nil;
    static  dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (_identify == nil)
        {
            _identify = [FireflyKeychain passwordForService:kFireflyAppIdentifyService
                                                   username:kFireflyAppIdentifyUser];
            if (_identify == nil)
            {
                _identify = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
                [FireflyKeychain setPassword:_identify
                                  forService:kFireflyAppIdentifyService
                                    username:kFireflyAppIdentifyUser];
            }
        }
    });
    
    return _identify;
}
五、模拟器环境,RSA公钥获取不到,导致crash

具体的原因和keychain的权限问题有关,将工程配置里的keychain开关打开即可。

iOS10以及XCode8适配问题汇总_第3张图片
六、推送修改

首先,工程设置的开关一定要记得打开:

iOS10以及XCode8适配问题汇总_第4张图片

具体的使用规则,先简单记录如下,后续会继续完善:
iOS 9 以前的通知

  • 1.在调用方法时,有些方法让人很难区分,容易写错方法,这让开发者有时候很苦恼。
  • 2.应用在运行时和非运行时捕获通知的路径还不一致。
  • 3.应用在前台时,是无法直接显示远程通知,还需要进一步处理。
  • 4.已经发出的通知是不能更新的,内容发出时是不能改变的,并且只有简单文本展示方式,扩展性根本不是很好。

iOS 10 开始的通知

  • 1.所有相关通知被统一到了UserNotifications.framework框架中。
  • 2.增加了撤销、更新、中途还可以修改通知的内容。
  • 3.通知不在是简单的文本了,可以加入视频、图片,自定义通知的展示等等。
  • 4.iOS 10相对之前的通知来说更加好用易于管理,并且进行了大规模优化,对于开发者来说是一件好事。
  • 5.iOS 10开始对于权限问题进行了优化,申请权限就比较简单了(本地与远程通知集成在一个方法中)。
七、ATS问题
  • 1.在iOS 9的时候,默认非HTTS的网络是被禁止的,我们可以在info.plist文件中添加NSAppTransportSecurity字典,将NSAllowsArbitraryLoads设置为YES来禁用ATS;
  • 2.从2017年1月1日起,所有新提交的 app 默认不允许使用NSAllowsArbitraryLoads来绕过ATS的限制,默认情况下你的 app 可以访问加密足够强的(TLS V1.2以上)HTTPS内容;
  • 3.可以选择使用NSExceptionDomains设置白名单的方式对特定的域名开放HTTP内容来通过审核,比如说你的应用集成了第三方的登录分享SDK,可以通过这种方式来做。
    下面以新浪SDK作为示范:
NSAppTransportSecurity

 NSExceptionDomains
 
  sina.cn
  
   NSThirdPartyExceptionMinimumTLSVersion
   TLSv1.0
   NSThirdPartyExceptionRequiresForwardSecrecy
   
   NSIncludesSubdomains
   
  
  weibo.cn
  
   NSThirdPartyExceptionMinimumTLSVersion
   TLSv1.0
   NSThirdPartyExceptionRequiresForwardSecrecy
   
   NSIncludesSubdomains
   
  
 

八、NSAllowsArbitraryLoadsInWebContent键

在iOS 10 中info.plist文件新加入了NSAllowsArbitraryLoadsInWebContent键,允许任意web页面加载,同时苹果会用 ATS 来保护你的app。

九、安全传输不再支持SSLv3,

建议尽快停用SHA1和3DES算法。

参考:
http://www.cnblogs.com/oc-bowen/p/5916630.html
http://www.2cto.com/kf/201609/547127.html

你可能感兴趣的:(iOS10以及XCode8适配问题汇总)