本文主要是说一些iOS9
适配中出现的坑,若是只是要单纯的了解iOS9
新特性能够看瞄神的开发者所须要知道的 iOS 9 SDK
新特性。9月17日凌晨,苹果给用户推送了iOS9
正式版,随着有用户陆续升级iOS9
,也就逐渐的衍生出了一系列的问题,笔者也在赶紧为本身维护的App
作适配,本文写的一些坑基本都是亲身体验了。ios
1、NSAppTransportSecurity
git
iOS9
让全部的HTTP
默认使用了HTTPS
,原来的HTTP
协议传输都改为TLS1.2
协议进行传输。直接形成的状况就是App
发请求的时候弹出网络没法链接。解决办法就是在项目的info.plist
文件里加上以下节点:github
NSAppTransportSecurity
字典中的key
: NSAllowsArbitraryLoads
设置为YES
。web
这个子节点的意思是:是否容许任意加载? 设为YES
的话就将禁用了AppTransportSecurity
转而使用用户自定义的设置,这个问题就解决了。算法
上面说是苹果限制了HTTP
协议,可是也并非说全部的HTTPS
都能完美适配iOS9
了。shell
举个栗子,从app
内起webView
加载https
的网页。新建个项目写几行起网页的代码windows
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
- (void)loadView{
UIWebView *web = [[UIWebView alloc]initWithFrame:[UIScreen mainScreen].bounds];
self.view = web;
}
- (void)viewDidLoad {
[super viewDidLoad];
UIWebView *web = (UIWebView *)self.view; //董铂然
NSURL *url = [NSURL URLWithString:@"https://github.com/"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[web loadRequest:request];
}
|
中间的url
就是咱们想要加载的https
地址,用https://baidu.com/
和 https://github.com/
分别试一下,结果不一样数组
github
的网页能打开,百度的网页打不开,下面打印了一行log
:xcode
1
2
3
|
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
|
缘由是苹果的官方资料说首先必需要基于TLS 1.2
版本协议。而后证书的加密的算法还须要达到SHA256
或者更高位的RSA
密钥或ECC
密钥,若是不符合,请求将被中断并返回nil
.浏览器
在浏览器中是能够直接查看这个网站的加密算法的,先点绿锁再点证书信息。
从右边两张图能够看出,github
带RSA
加密的SHA-256
符合苹果的要求,因此才能够展现。
针对百度的状况能够在info.plist
中配置以下,若是网站引用的比较多应该是须要针对每一个网站进行配置。
NSAppTransportSecurity
,NSExceptionDomains
,NSIncludesSubdomains
,NSExceptionRequiresForwardSecrecy
,NSExceptionAllowInsecureHTTPLoads
写在下面便于复制。
其中的ForwardSecrecy
理解为超前的密码保护算法,在官方资料里有写,一共是11
种。配置完毕百度能够访问。
bitcode
的理解应该是把程序编译成的一种过渡代码,而后苹果再把这个过渡代码编译成可执行的程序。bitcode
也容许苹果在后期从新优化咱们程序的二进制文件,有相似于App
瘦身的思想。
用了xcode7
的编译器编译以前没问题的项目可能会出现下列报错。
1
2
3
|
XXXX’ does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. for architecture arm64
|
问题的缘由是:某些第三方库还不支持bitcode
。要否则是等待库的开发者升级了此项功能咱们更新库,要不就是把这个bitcode
禁用。
禁用的方法就是找到以下配置,选为NO.(iOS中bitcode
是默认YES
,watchOS
中bitcodes
是不让改的必须YES
。)
这一条只和企业级应用或inhouse
有关,和AppStore
渠道的应用无关。
在iOS8
只是弹出一个窗问你是否须要让手机信任这个应用,可是在iOS9
却直接禁止,若是真的想信任须要本身去手动开启。相似于Mac系统从未知开发者处下载的dmg
直接打不开,而后要到系统偏好设置的安全性与隐私手动打开。 下图展现左边iOS8
,右边iOS9
:
用户须要去设置—》通用—》描述文件里面自行添加信任。
这种问题的处理方法也就两种:
iOS9
iOS8
中,字体是Helvetica
,中文的字体有点相似于“华文细黑”。只是苹果手机自带渲染,因此看上去可能比普通的华文细黑要美观。iOS9
中,中文系统字体变为了专为中国设计的“苹方” 有点相似于一种word字体“幼圆”。字体有轻微的加粗效果,而且最关键的是字体间隙变大了!
因此不少本来写死了width
的label
可能会出现“…”的状况。
iOS8:
iOS9 蛋疼:
上面这两张图也能够直观的看出同一个界面,同一个label的变化。
因此为了在界面显示上不出错,就算是固定长度的文字也仍是建议使用sizetofit 或者ios向上取整 ceilf() 或者提早计算
1
2
3
4
|
CGSize size = [title sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:14.0f]}];
CGSize adjustedSize = CGSizeMake(ceilf(size.width), ceilf(size.height));
|
URL scheme
通常使用的场景是应用程序有分享或跳其余平台受权的功能,分享或受权后再跳回来。
在iOS8
并无作过多限制,可是iOS9
须要将你要在外部调用的URL scheme
列为白名单,才能够完成跳转
若是iOS9没作适配 会报以下错误:
1
2
3
|
canOpenURL: failed for URL : "mqzone://qqapp" - error: "This app is not allowed to query for scheme mqzone"
|
具体的解决方案也是要在info.plist
中设置LSApplicationQueriesSchemes
类型为数组,下面添加全部你用到的scheme
:
这个还好只是报一个警告,若是就是无论他,也不会出现问题。
1
2
3
|
<Error>: CGContextSaveGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
|
之前咱们为了可以实时的控制顶部statusbar
的样式,可能会在喜欢使用
1
2
3
4
|
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]
[[UIApplication sharedApplication] setStatusBarHidden:YES];
|
可是这么作以前须要将info.plist
里面加上View controller-based status bar appearance
的BOOL
值设为NO
,就是把控制器控制状态栏的权限给禁了,用UIApplication
来控制。可是这种作法在iOS9
不建议使用了,建议咱们使用吧那个BOOL
值设为YES,而后用控制器的方法来管理状态栏好比。
1
2
3
4
5
|
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent;
}
|
点进头文件能够验证刚才说法:
1
2
3
|
@property(readwrite, nonatomic,getter=isStatusBarHidden) BOOL statusBarHidden NS_DEPRECATED_IOS(2_0, 9_0, "Use -[UIViewController prefersStatusBarHidden]");
|
若是运行的时候报下列错误,那就是你的didFinishLaunchingWithOptions
写的不对了
1
2
3
|
***** Assertion failure in -[UIApplication _runWithMainScene:transitionContext:completion:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3505.16/UIApplication.m:3294**
|
iOS9
不容许在didFinishLaunchingWithOptions
结束了以后尚未设置window
的rootViewController
。 也许是xcode7
的编译器自己就不支持。
解决的方法固然就是先初始化个值,以后再赋值替换掉
1
2
3
4
|
UIWindow *window = [[UIWindowalloc] initWithFrame:[UIScreenmainScreen].bounds];
window.rootViewController = [[UIViewController alloc]init];
|
虽然如今的iOS9
已经推送正式版了,可是iOS9
使用时仍是会感受到App比之前更加卡顿了,tableView
拖动时卡顿显示的最为明显。 而且以前遇到一个bug
,本来好的项目用xcode7一编译,tableView
刷新出了问题 ,[tableView reloadData]
无效 有一行cell
明明改变了可是刷新不出来。 感受多是这个方法和某种新加的特性冲突了,猜想多是reloadData
的操做被推迟到下一个RunLoop
执行最终失效。
解决的方法是,注释[tableView reloadData]
,改用局部刷新,问题竟然就解决了。
1
2
3
|
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];
|
若是你程序启动后出现主页面一片空白,或是报了如下的栈调用错误。那就是NSLocalizableString
的死循环致使堆栈溢出了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#0 0x003052a8 in -[NSLocalizableString length] ()
#1 0x003052cc in -[NSLocalizableString length] ()
#2 0x003052cc in -[NSLocalizableString length] ()
#3 0x003052cc in -[NSLocalizableString length] ()
#4 0x003052cc in -[NSLocalizableString length] ()
#5 0x003052cc in -[NSLocalizableString length] ()
#6 0x003052cc in -[NSLocalizableString length] ()
#7 0x003052cc in -[NSLocalizableString length] ()
#8 0x003052cc in -[NSLocalizableString length] ()
#9 0x003052cc in -[NSLocalizableString length] ()
#10 0x003052cc in -[NSLocalizableString length] ()
#11 0x003052cc in -[NSLocalizableString length] ()
#12 0x003052cc in -[NSLocalizableString length] ()
#13 0x003052cc in -[NSLocalizableString length] ()
#14 0x003052cc in -[NSLocalizableString length] ()
#15 0x003052cc in -[NSLocalizableString length] ()
#16 0x003052cc in -[NSLocalizableString length] ()
|
这个的解决方法就是找到特定的页面,而后将English
前面的勾勾上。
若是你遇到了在本地编译经过,可是在CI
上打包失败。而且报的错误是和bundle identifier
相关,那颇有多是你plist
文件中写的bundle identifier
没有起做用。
由于xcode7
新增了此功能,在target
下面的BuildSetting
里面增长了Product Bundle identifier
。苹果以后的作法应该是推荐在此处设置bundle identifier
,此处的设置会比info.plist
里面优先读取。
若是你的Bundle identifier
一直没变,可能不会发现此问题。若是改变了,你在plist
中修改是无效的。
另外一个作法就是在ci打包的配置Execute shell
上增长如下代码
1
2
3
|
"Set :CFBundleIdentifier com.XXX.XXX" "XXX/Supporting Files/XXX-Info.plist"
|
Actionsheet
在iOS8的时候改了一次版,当时是和AlertView
二合一,而且以AlertViewController
做为载体,以后再present
出来,这在当时,苹果应该是想统一各个控件的展现方式,可是不少人可能并无在乎由于直接show
那个方法并无废除,你们都以为应该是新旧都能用,再加上有的公司可能本身还作了必定扩展,诸多缘由致使仍是用的旧方法。
在iOS9上使用旧方法直接show,会出现左图的问题。若是用的是AlertViewController
的方法则不会出现问题(右图)
我猜想多是sheet
的windowLevel
比键盘低致使的。可是将优先级设到10000
,而后显示在keyWindow
上。
1
2
3
4
|
sheet.window.windowLevel = 10000;
[sheet showInView:[UIApplication sharedApplication].keyWindow];
|
而后没有效果,而后又查了下stackoverflow
有个方法能取出优先级最高的window
1
2
3
4
5
|
UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
return win1.windowLevel - win2.windowLevel;
}] lastObject];
|
试了下仍是没有效果。 应该键盘的优先级不管如何都是最高的, 想盖在键盘上面的方法行不通。
固然,若是更换的成本比较大,也并非没有办法,直接设置弹sheet
以前收回键盘就行了。
暂时遇到这些问题,感受iOS9的出现让全部iOS开发都是菊花一紧,预祝全部的iOS都能及时的作好适配改完bug,下个版本一上线,全部问题都解决。