本文主要是說一些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,下個版本一上線,全部問題都解決。