您好, , 海量一手媒体资源,专业、正规、高效,为企业提供一站式营销推广服务!
温馨提示
运营小帮手
一站式互联网营销服务平台
  全国免费咨询热线
0755-23071973
运营小帮手
软文发稿
PC端 选择媒体
更方便、更快捷!
查看媒体价格
软文发布、软文代写、百科制作、问答营销、微信营销、微信营销
查看媒体价格
当前位置: 运营小帮手首页 > 新闻中心 > 文章正文

iOS9适配整理那些坑

本文主要是说一些iOS9适配中出现的坑,如果只是要单纯的了解iOS9新特性可以看瞄神的开发者所需要知道的iOS 9 SDK新特性。9月17日凌晨,苹果给用户推送了iOS9正式版,随着有用户陆续升级iOS9,也就逐渐的衍生出了一系列的问题,笔者也在赶忙为自己维护的App做适配,本文写的一些坑基本都是亲身体验了。

兼容HTTP

一、NSAppTransportSecurity

iOS9让所有的HTTP默认使用了HTTPS,原来的HTTP协议传输都改成TLS1.2协议进行传输。直接造成的情况就是App发请求的时候弹出网络无法连接。解决办法就是在项目的info.plist文件里加上如下节点:

NSAppTransportSecurity字典中的keyNSAllowsArbitraryLoads设置为YES

这个子节点的意思是:是否允许任意加载? 设为YES的话就将禁用了AppTransportSecurity转而使用用户自定义的设置,这个问题就解决了。

上面说是苹果限制了HTTP协议,但是也并不是说所有的HTTPS都能完美适配iOS9了。

举个栗子,从app内起webView加载https的网页。新建个项目写几行起网页的代码

-(void)loadView{
UIWebView*web=[[UIWebViewalloc]initWithFrame:[UIScreenmainScreen].bounds];
self.view=web;
}
-(void)viewDidLoad{
[superviewDidLoad];

UIWebView*web=(UIWebView*)self.view;//董铂然
NSURL*url=[NSURLURLWithString:@"https://github.com/"];
NSURLRequest*request=[NSURLRequestrequestWithURL:url];
[webloadRequest:request];
}

中间的url就是我们想要加载的https地址,用https://baidu.com/https://github.com/分别试一下,结果不同

github的网页能打开,百度的网页打不开,下面打印了一行log

NSURLSession/NSURLConnectionHTTPloadfailed(kCFStreamErrorDomainSSL,-9802)

原因是苹果的官方资料说首先必须要基于TLS 1.2版本协议。然后证书的加密的算法还需要达到SHA256或者更高位的RSA密钥或ECC密钥,如果不符合,请求将被中断并返回nil.

在浏览器中是可以直接查看这个网站的加密算法的,先点绿锁再点证书信息。

从右边两张图可以看出,githubRSA加密的SHA-256符合苹果的要求,所以才可以展示。

针对百度的情况可以在info.plist中配置如下,如果网站引用的比较多应该是需要针对每个网站进行配置。

NSAppTransportSecurityNSExceptionDomainsNSIncludesSubdomainsNSExceptionRequiresForwardSecrecyNSExceptionAllowInsecureHTTPLoads写在下面便于复制。

其中的ForwardSecrecy理解为超前的密码保护算法,在官方资料里有写,一共是11种。配置完毕百度可以访问。

Bitcode

bitcode的理解应该是把程序编译成的一种过渡代码,然后苹果再把这个过渡代码编译成可执行的程序。bitcode也允许苹果在后期重新优化我们程序的二进制文件,有类似于App瘦身的思想。

用了xcode7的编译器编译之前没问题的项目可能会出现下列报错。

XXXX’doesnotcontainbitcode.Youmustrebuilditwithbitcodeenabled(XcodesettingENABLE_BITCODE),obtainanupdatedlibraryfromthevendor,ordisablebitcodeforthistarget.forarchitecturearm64

问题的原因是:某些第三方库还不支持bitcode。要不然是等待库的开发者升级了此项功能我们更新库,要不就是把这个bitcode禁用。

禁用的方法就是找到如下配置,选为NO.(iOS中bitcode是默认YESwatchOSbitcodes是不让改的必须YES。)

设置信任

这一条只和企业级应用或inhouse有关,和AppStore渠道的应用无关。

iOS8只是弹出一个窗问你是否需要让手机信任这个应用,但是在iOS9却直接禁止,如果真的想信任需要自己去手动开启。类似于Mac系统从未知开发者处下载的dmg直接打不开,然后要到系统偏好设置的安全性与隐私手动打开。 下图展示左边iOS8,右边iOS9

用户需要去设置—》通用—》描述文件里面自行添加信任。

这种问题的处理方法也就两种:

  • 1.提前周知暂时不要升级iOS9

  • 2.大多是公司员工使用的企业级应用,群发一个指导邮件。

字体

iOS8中,字体是Helvetica,中文的字体有点类似于“华文细黑”。只是苹果手机自带渲染,所以看上去可能比普通的华文细黑要美观。iOS9中,中文系统字体变为了专为中国设计的“苹方”有点类似于一种word字体“幼圆”。字体有轻微的加粗效果,并且最关键的是字体间隙变大了!

所以很多原本写死了widthlabel可能会出现“…”的情况。

iOS8:

iOS9 蛋疼:

上面这两张图也可以直观的看出同一个界面,同一个label的变化。

所以为了在界面显示上不出错,就算是固定长度的文字也还是建议使用sizetofit 或者ios向上取整 ceilf() 或者提前计算

CGSizesize=[titlesizeWithAttributes:@{NSFontAttributeName:[UIFontsystemFontOfSize:14.0f]}];
CGSizeadjustedSize=CGSizeMake(ceilf(size.width),ceilf(size.height));

URL scheme

URL scheme一般使用的场景是应用程序有分享或跳其他平台授权的功能,分享或授权后再跳回来。

iOS8并没有做过多限制,但是iOS9需要将你要在外部调用的URL scheme列为白名单,才可以完成跳转

如果iOS9没做适配 会报如下错误:

canOpenURL:failedforURL:"mqzone://qqapp"-error:"Thisappisnotallowedtoqueryforschememqzone"

具体的解决方案也是要在info.plist中设置LSApplicationQueriesSchemes类型为数组,下面添加所有你用到的scheme

statusbar

这个还好只是报一个警告,如果就是不管他,也不会出现问题。

<Error>:CGContextSaveGState:invalidcontext0x0.Ifyouwanttoseethebacktrace,pleasesetCG_CONTEXT_SHOW_BACKTRACEenvironmentalvariable.

以前我们为了能够实时的控制顶部statusbar的样式,可能会在喜欢使用

[[UIApplicationsharedApplication]setStatusBarStyle:UIStatusBarStyleLightContent]
[[UIApplicationsharedApplication]setStatusBarHidden:YES];

但是这么做之前需要将info.plist里面加上View controller-based status bar appearanceBOOL值设为NO,就是把控制器控制状态栏的权限给禁了,用UIApplication来控制。但是这种做法在iOS9不建议使用了,建议我们使用吧那个BOOL值设为YES,然后用控制器的方法来管理状态栏比如。

-(UIStatusBarStyle)preferredStatusBarStyle{
returnUIStatusBarStyleLightContent;
}

点进头文件可以验证刚才说法:

@property(readwrite,nonatomic,getter=isStatusBarHidden)BOOLstatusBarHiddenNS_DEPRECATED_IOS(2_0,9_0,"Use-[UIViewControllerprefersStatusBarHidden]");

didFinishLaunchingWithOptions

如果运行的时候报下列错误,那就是你的didFinishLaunchingWithOptions写的不对了

*****Assertionfailurein-[UIApplication_runWithMainScene:transitionContext:completion:],/BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3505.16/UIApplication.m:3294**

iOS9不允许在didFinishLaunchingWithOptions结束了之后还没有设置windowrootViewController。 也许是xcode7的编译器本身就不支持。

解决的方法当然就是先初始化个值,之后再赋值替换掉

UIWindow*window=[[UIWindowalloc]initWithFrame:[UIScreenmainScreen].bounds];
window.rootViewController=[[UIViewControlleralloc]init];

tableView

虽然现在的iOS9已经推送正式版了,但是iOS9使用时还是会感觉到App比以前更加卡顿了,tableView拖动时卡顿显示的最为明显。 并且之前遇到一个bug,原本好的项目用xcode7一编译,tableView实现新出了问题 ,[tableView reloadData]无效 有一行cell明明改变了但是实现新不出来。 感觉可能是这个方法和某种新加的特性冲突了,猜测可能是reloadData的操作被推迟到下一个RunLoop执行最终失效。

解决的方法是,注释[tableView reloadData],改用局部实现新,问题居然就解决了。

[self.tableViewreloadSections:[NSIndexSetindexSetWithIndex:0]withRowAnimation:UITableViewRowAnimationNone];

NSLocalizableString(XCode7问题)

如果你程序启动后出现主页面一片空白,或是报了以下的栈调用错误。那就是NSLocalizableString的死循环导致堆栈溢出了。

#00x003052a8in-[NSLocalizableStringlength]()
#10x003052ccin-[NSLocalizableStringlength]()
#20x003052ccin-[NSLocalizableStringlength]()
#30x003052ccin-[NSLocalizableStringlength]()
#40x003052ccin-[NSLocalizableStringlength]()
#50x003052ccin-[NSLocalizableStringlength]()
#60x003052ccin-[NSLocalizableStringlength]()
#70x003052ccin-[NSLocalizableStringlength]()
#80x003052ccin-[NSLocalizableStringlength]()
#90x003052ccin-[NSLocalizableStringlength]()
#100x003052ccin-[NSLocalizableStringlength]()
#110x003052ccin-[NSLocalizableStringlength]()
#120x003052ccin-[NSLocalizableStringlength]()
#130x003052ccin-[NSLocalizableStringlength]()
#140x003052ccin-[NSLocalizableStringlength]()
#150x003052ccin-[NSLocalizableStringlength]()
#160x003052ccin-[NSLocalizableStringlength]()

这个的解决方法就是找到特定的页面,然后将English前面的勾勾上。

bundle identifier(Xcode7问题)

如果你遇到了在本地编译通过,但是在CI上打包失败。并且报的错误是和bundle identifier相关,那很有可能是你plist文件中写的bundle identifier没有起作用。

因为xcode7新增了此功能,在target下面的BuildSetting里面增加了Product Bundle identifier。苹果之后的做法应该是推荐在此处设置bundle identifier,此处的设置会比info.plist里面优先读取。

如果你的Bundle identifier一直没变,可能不会发现此问题。如果改变了,你在plist中修改是无效的。

另一个做法就是在ci打包的配置Execute shell上增加以下代码

"Set:CFBundleIdentifiercom.XXX.XXX""XXX/SupportingFiles/XXX-Info.plist"

ActionSheet

Actionsheet在iOS8的时候改了一次版,当时是和AlertView二合一,并且以AlertViewController作为载体,之后再present出来,这在当时,苹果应该是想统一各个控件的展示方式,但是很多人可能并没有在意因为直接show那个方法并没有废除,大家都觉得应该是新旧都能用,再加上有的公司可能自己还做了一定扩展,诸多原因导致还是用的旧方法。

在iOS9上使用旧方法直接show,会出现左图的问题。如果用的是AlertViewController的方法则不会出现问题(右图)

我猜测可能是sheetwindowLevel比键盘低导致的。但是将优先级设到10000,然后显示在keyWindow上。

sheet.window.windowLevel=10000;
[sheetshowInView:[UIApplicationsharedApplication].keyWindow];

然后没有效果,然后又查了下stackoverflow有个方法能取出优先级最高的window

UIWindow*topWindow=[[[UIApplicationsharedApplication].windowssortedArrayUsingComparator:^NSComparisonResult(UIWindow*win1,UIWindow*win2){
returnwin1.windowLevel-win2.windowLevel;
}]lastObject];

试了下还是没有效果。 应该键盘的优先级无论如何都是最高的, 想盖在键盘上面的方法行不通。

当然,如果更换的成本比较大,也并不是没有办法,直接设置弹sheet之前收回键盘就好了。

暂时遇到这些问题,感觉iOS9的出现让所有iOS开发都是菊花一紧,预祝所有的iOS都能及时的做好适配改完bug,下个版本一上线,所有问题都解决。

推荐阅读

关键词:

猜您可能需要的服务: