@(IOS各個版本適配)
[TOC]
一、iOS12(Xcode10)
1.1、升級Xcode10后項(xiàng)目報(bào)錯
不允許多個info.plist
Xcode10是默認(rèn)選中的最新的New Build System(Default),在這個編譯系統(tǒng)的環(huán)境下,不允許多個info.plist
解決辦法一:(推薦)
把build system切換到 Legacy Build System,換言之就是切換成老的編譯系統(tǒng),就OK了。
Xcode->File->Project Settings-> Build System -> Legacy Build System.


解決辦法二:
刪除其他info.plist文件。
iOS 12移除了libstdc++, 用libc++替代
Xcode10中l(wèi)ibstdc++相關(guān)的3個庫(libstdc++、libstdc++.6、libstdc++6.0.9)應(yīng)該都是被徹底廢棄了,如果你使用的三方庫中有依賴,請盡快和提供方溝通,告知他們遷移吧。如果自己開發(fā)使用,也盡快考慮遷移的事宜吧。
1.2、iPhone XR不支持3D-Touch
OC檢測代碼
1if(self.traitCollection.forceTouchCapability?==?UIForceTouchCapabilityAvailable)?{
2?
3}
swift檢測代碼
1self.traitCollection.forceTouchCapability?==?.availible
二、iOS11(Xcode9)
2.1、安全區(qū)域(SafeArea)
iOS11為UIViewController和UIView增加了兩個新的屬性safeAreaInsets和safeAreaLayoutGuide
safeAreaInsets 適用于手動計(jì)算.
safeAreaLayoutGuide 適用于自動布局.
1UIViewController中新增:
2-?(void)viewSafeAreaInsetsDidChange;
3UIView中新增:
4-?(void)viewSafeAreaInsetsDidChange;
在Storyboard使用Safe Area最低只支持iOS9,iOS8的用戶就要放棄了


當(dāng)UIViewController調(diào)用- (void)viewDidLoad時它的所有子視圖的safeAreaInsets屬性都等于UIEdgeInsetsZero。
viewSafeAreaInsetsDidChange的調(diào)用時機(jī)如下:
?1、viewDidLoad
?2、viewWillAppear
?3、viewSafeAreaInsetsDidChange
?4、viewWillLayoutSubviews
?5、viewDidAppear
只有在調(diào)用viewSafeAreaInsetsDidChange后,才能獲得view以及viewController的SafeArea(UIEdgeInsets)。因此在viewDidload中根據(jù)SafeArea設(shè)置界面會有問題。
iPhone X:有導(dǎo)航欄的時候可以+44
豎屏 safeAreaInsets = (top = 44, left = 0, bottom = 34, right = 0)
橫屏 safeAreaInsets = (top = 0, left = 44, bottom = 21, right = 44)
01#import"Adaptive11VC.h"
02staticinline?UIEdgeInsets?sgm_safeAreaInset(UIView?*view)?{
03????if(@available(iOS?11.0,?*))?{
04????????returnview.safeAreaInsets;
05????}
06????returnUIEdgeInsetsZero;
07}
08?
09@interfaceAdaptive11VC?()
10@end
11@implementation?Adaptive11VC
12-?(void)viewDidLoad?{
13????[superviewDidLoad];
14}
15-?(void)testSafeArea?{
16????UIEdgeInsets?safeAreaInsets?=?sgm_safeAreaInset(self.view);
17????NSLog(@"safeAreaInsets?=?%@",?NSStringFromUIEdgeInsets(safeAreaInsets));
18}
19-?(void)viewSafeAreaInsetsDidChange?{
20????[superviewSafeAreaInsetsDidChange];
21????[self?testSafeArea];
22}
23@end
2.2、UIScrollView
iOS 11廢棄了UIViewController的automaticallyAdjustsScrollViewInsets屬性,新增了contentInsetAdjustmentBehavior屬性,所以當(dāng)超出安全區(qū)域時系統(tǒng)自動調(diào)整了SafeAreaInsets,進(jìn)而影響了adjustedContentInset,在iOS11中決定tableView內(nèi)容與邊緣距離的是adjustedContentInset,所以需要設(shè)置UIScrollView的contentInsetAdjustmentBehavior屬性。
01//?方式一:(不推薦)修改額外的安全區(qū)域
02if(@available(iOS?11.0,?*))?{
03????self.additionalSafeAreaInsets?=?UIEdgeInsetsMake(-44,?0,?0,?0);
04}
05else{
06????//?Fallback?on?earlier?versions
07}
08//?方式二:(推薦)設(shè)置為不自動調(diào)整
09if(@available(iOS?11.0,?*))?{
10????//?作用于指定的UIScrollView
11????self.tableView.contentInsetAdjustmentBehavior?=?UIScrollViewContentInsetAdjustmentNever;
12????//?作用與所有的UIScrollView
13????UIScrollView.appearance.contentInsetAdjustmentBehavior?=?UIScrollViewContentInsetAdjustmentNever;
14}
15else{
16????self.automaticallyAdjustsScrollViewInsets?=?NO;
17}
2.3、tableview問題
iOS11開始UITableView開啟了自動估算行高,estimatedRowHeight estimatedSectionHeaderHeight estimatedSectionFooterHeight三個高度估算屬性由默認(rèn)的0變成了UITableViewAutomaticDimension,如果不實(shí)現(xiàn)-tableView: viewForFooterInSection: 和 -tableView: viewForHeaderInSection:,那么estimatedRowHeight estimatedSectionHeaderHeight estimatedSectionFooterHeight三個高度估算屬性由默認(rèn)的0變成了UITableViewAutomaticDimension,導(dǎo)致高度計(jì)算不對,會產(chǎn)生空白。解決方法是實(shí)現(xiàn)對應(yīng)方法或吧這三個屬性設(shè)為0。
2.4、LocalAuthentication 本地認(rèn)證
本地認(rèn)證框架提供了從具有指定安全策略(密碼或生物學(xué)特征)的用戶請求身份驗(yàn)證的功能。例如,要求用戶僅使用Face ID或Touch ID進(jìn)行身份驗(yàn)證,可使用以下代碼:
01#import/**
02?檢測TouchID是否可用
03?*/
04-?(void)checkBiometrics?{
05????LAContext?*context?=?[[LAContext?alloc]?init];
06????BOOL?success?=?[context?canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
07????????????????????????????????????????error:nil];
08????if(?success?)?{
09????????NSLog(@"can?use");
10????}
11????else{
12????????NSLog(@"can`t?use?");
13????}
14}
15/**
16?在驗(yàn)證TouchID可用的情況下使用
17?*/
18-?(void)excuteBiometrics?{
19????LAContext?*context?=?[[LAContext?alloc]?init];
20????context.localizedFallbackTitle?=?@"自定義標(biāo)題";
21????[context?evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
22????????????localizedReason:@"為什么使用TouchID寫這里"
23??????????????????????reply:^(BOOL?success,?NSError?*?_Nullable?error)?{
24????????if(?success?)?{
25????????????//?指紋驗(yàn)證成功
26????????}
27????????else{
28????????????switch(error.code)?{
29????????????????caseLAErrorUserFallback:{
30????????????????????NSLog(@"用戶選擇輸入密碼");
31????????????????????break;
32????????????????}
33????????????????caseLAErrorAuthenticationFailed:{
34????????????????????NSLog(@"驗(yàn)證失敗");
35????????????????????break;
36????????????????}
37????????????????caseLAErrorUserCancel:{
38????????????????????NSLog(@"用戶取消");
39????????????????????break;
40????????????????}
41????????????????caseLAErrorSystemCancel:{
42????????????????????NSLog(@"系統(tǒng)取消");
43????????????????????break;
44????????????????}
45????????????????//?以下三種情況如果提前檢測TouchID是否可用就不會出現(xiàn)
46????????????????caseLAErrorPasscodeNotSet:{
47????????????????????break;
48????????????????}
49????????????????caseLAErrorTouchIDNotAvailable:{
50????????????????????break;
51????????????????}
52????????????????caseLAErrorTouchIDNotEnrolled:{
53????????????????????break;
54????????????????}
55????????????????default:
56????????????????????break;
57????????????}
58????????}
59????}];
60}
2.5、啟動圖的適配
方法一:通過LaunchScreen.storyboard方式啟動
方法二:使用Assets中的LaunchImage

給Brand Assets添加一張1125*2436大小的圖片
打開Assets.xcassets文件夾,找到Brand Assets
右鍵Show in Finder
添加一張1125*2436大小的圖片
修改Contents.json文件,添加如下內(nèi)容
1{
2"extent":?"full-screen",
3"idiom":?"iphone",
4"subtype":?"2436h",
5"filename":?"1125_2436.png",
6"minimum-system-version":?"11.0",
7"orientation":?"portrait",
8"scale":?"3x"
9}
2.6、定位相關(guān)
在 iOS 11 中必須支持 When In Use 授權(quán)模式(NSLocationWhenInUseUsageDescription),在 iOS 11 中,為了避免開發(fā)者只提供請求 Always 授權(quán)模式這種情況,加入此限制,如果不提供When In Use 授權(quán)模式,那么 Always 相關(guān)授權(quán)模式也無法正常使用。
如果要支持老版本,即 iOS 11 以下系統(tǒng)版本,那么建議在 info.plist 中配置所有的 Key(即使
1NSLocationAlwaysUsageDescription?在?iOS?11及以上版本不再使用):
2NSLocationWhenInUseUsageDescription
3NSLocationAlwaysAndWhenInUseUsageDescription
4NSLocationAlwaysUsageDescription
5NSLocationAlwaysAndWhenInUseUsageDescription??//?為?iOS?11?中新引入的一個?Key。
三、iOS10(Xcode8)
3.1、(Why?Safe!)插件取消
Xcode8取消了三方插件(很多優(yōu)秀的插件,本來可以顯著提高效率)的功能,使用Extension代替
3.2、證書問題
為了方便用戶來管理,提供Automatically manage signing。需要輸入開發(fā)者賬號!如果沒有賬號也沒關(guān)系,在下面也可以選擇Debug、Realease、inHouse模式下對應(yīng)的證書也可以!
3.3、隱私數(shù)據(jù)訪問問題
iOS10,蘋果加強(qiáng)了對隱私數(shù)據(jù)的保護(hù),要對隱私數(shù)據(jù)權(quán)限做一個適配,iOS10調(diào)用相機(jī),訪問通訊錄,訪問相冊等都要在info.plist中加入權(quán)限訪問描述,不然之前你們的項(xiàng)目涉及到這些權(quán)限的地方就會直接crash掉。
解決辦法:
只需要在info.plist添加NSContactsUsageDescription的key, value自己隨意填寫就可以,這里列舉出對應(yīng)的key(Source Code模式下):
1NSPhotoLibraryUsageDescriptionApp需要您的同意,才能訪問相冊NSCameraUsageDescriptionApp需要您的同意,才能訪問相機(jī)NSMicrophoneUsageDescriptionApp需要您的同意,才能訪問麥克風(fēng)NSLocationUsageDescriptionApp需要您的同意,才能訪問位置NSLocationWhenInUseUsageDescriptionApp需要您的同意,才能在使用期間訪問位置NSLocationAlwaysUsageDescriptionApp需要您的同意,才能始終訪問位置NSCalendarsUsageDescriptionApp需要您的同意,才能訪問日歷NSRemindersUsageDescriptionApp需要您的同意,才能訪問提醒事項(xiàng)NSMotionUsageDescriptionApp需要您的同意,才能訪問運(yùn)動與健身NSHealthUpdateUsageDescriptionApp需要您的同意,才能訪問健康更新?NSHealthShareUsageDescriptionApp需要您的同意,才能訪問健康分享NSBluetoothPeripheralUsageDescriptionApp需要您的同意,才能訪問藍(lán)牙NSAppleMusicUsageDescriptionApp需要您的同意,才能訪問媒體資料庫

3.4、跳轉(zhuǎn)到app內(nèi)的隱私數(shù)據(jù)設(shè)置頁面
iOS 10 干掉了所有系統(tǒng)設(shè)置的 URL Scheme,這意味著你再也不可能直接跳轉(zhuǎn)到系統(tǒng)設(shè)置頁面(比如 WiFi、蜂窩數(shù)據(jù)、定位等)。
跳轉(zhuǎn)方式
方式一:prefs:root=某項(xiàng)服務(wù) 適用于 小于 iOS10的系統(tǒng);
NSURL *url = [NSURL URLWithString:@"prefs:root=WIFI"];
方式二:prefs:root=bundleID 適用于 大于等于iOS8系統(tǒng),小于iOS10的系統(tǒng)
NSURL *url = [NSURL URLWithString:@"prefs:root=bundleID"];
方式三:UIApplicationOpenSettingsURLString 適用于 大于等于iOS8的系統(tǒng)
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
01//?iOS系統(tǒng)版本?>=?10.0
02{
03????NSURL?*url?=?[NSURL?URLWithString:UIApplicationOpenSettingsURLString];
04????if([[UIApplication?sharedApplication]?canOpenURL:url])?{
05????????[[UIApplication?sharedApplication]?openURL:url];
06????}
07}
08return;
09//?iOS系統(tǒng)版本?>=?10.0
10//?But!?不建議這樣做哦,官方文檔中說過:
11//?`URL?is?now?considered?a?private?API?and?use?will?result?in?app?rejection`.
12//?雖然是有可能躲過蘋果的檢測,但是蘋果如果發(fā)現(xiàn)你這樣用了,app上架是有被拒的風(fēng)險(xiǎn)的.
13{
14????NSURL?*url?=?[NSURL?URLWithString:@"APP-Prefs:root=WIFI"];
15????if([[UIApplication?sharedApplication]?canOpenURL:url])?{
16????????if(@available(iOS?10.0,?*))?{
17????????????[[UIApplication?sharedApplication]?openURL:url?
18??????????????options:@{}?
19????completionHandler:nil];
20????????}?else{
21????????????//?Fallback?on?earlier?versions
22????????}
23????}
24}
25//?iOS系統(tǒng)版本?<?10.0
26{
27????NSURL?*url?=?[NSURL?URLWithString:@"prefs:root=WIFI"];
28????if([[UIApplication?sharedApplication]?canOpenURL:url])?{
29????????[[UIApplication?sharedApplication]?openURL:url];
30????}
31}
跳轉(zhuǎn)目的地
iOS系統(tǒng)版本 <= iOS7 , 只能跳轉(zhuǎn)到 系統(tǒng)設(shè)置頁面
iOS系統(tǒng)版本 >= iOS8 ,支持跳轉(zhuǎn)到第三方應(yīng)用的設(shè)置界面中。使用prefs:root=bundleID ,bundleID是你第三方應(yīng)用工程的唯一ID
iOS系統(tǒng)版本 >= iOS10,支持跳轉(zhuǎn)到自己應(yīng)用設(shè)置,不支持跳轉(zhuǎn)到系統(tǒng)設(shè)置
3.5、字體變化
蘋果的默認(rèn)字體會隨著iOS系統(tǒng)版本的不同而不同,iOS10中字體變大了。導(dǎo)致了原來的顯示有問題,會造成...的出現(xiàn)。暫時沒有好的解決辦法,需要自己在一個個適配一下!
3.6、UICollectionViewCell的的優(yōu)化
在iOS 10 之前,cell只能從重用隊(duì)列里面取出,再走一遍生命周期,并調(diào)用cellForItemAtIndexPath創(chuàng)建或者生成一個cell.
在iOS 10 中,系統(tǒng)會cell保存一段時間,也就是說當(dāng)用戶把cell滑出屏幕以后,如果又滑動回來,cell不用再走一遍生命周期了,只需要調(diào)用willDisplayCell方法就可以重新出現(xiàn)在屏幕中了.
iOS 10 中,系統(tǒng)是一個一個加載cell的,二以前是一行一行加載的,這樣就可以提升很多性能;
iOS 10 新增加的Pre-Fetching預(yù)加載
3.7、UIRefreshControl
在iOS 10 中, UIRefreshControl可以直接在UICollectionView和UITableView中使用,并且脫離了UITableViewController.現(xiàn)在RefreshControl是UIScrollView的一個屬性.
3.8、UserNotifications(用戶通知)
iOS 10所有相關(guān)通知被統(tǒng)一到了UserNotifications.framework框架中。增加了撤銷、更新、中途還可以修改通知的內(nèi)容。通知不在是簡單的文本了,可以加入視頻、圖片,自定義通知的展示等等。
iOS 10相對之前的通知來說更加好用易于管理,并且進(jìn)行了大規(guī)模優(yōu)化,對于開發(fā)者來說是一件好事。
iOS 10開始對于權(quán)限問題進(jìn)行了優(yōu)化,申請權(quán)限就比較簡單了(本地與遠(yuǎn)程通知集成在一個方法中)。
四、iOS9(Xcode7)
4.1、Bitcode
Xcode7 默認(rèn)啟用 Bitcode,但是如果我們用到的第三方庫編譯時還沒啟用 Bitcode,主工程就會編譯不過。Bitcode 是蘋果 App Thinning 的機(jī)制之一,可以減少安裝包的大小。App store 會將這個 Bitcode 編譯為可執(zhí)行的64位或32位程序。
解決辦法一:
最簡單的解決辦法是先把 Bitcode 關(guān)掉:把 Build settings - Build Options - Enable Bitcode 改為 NO。

解決辦法二:
移除不支持BitCode的平臺SDK,或者尋找支持BitCode的替代品,或者聯(lián)系SDK方支持BitCode。
4.2、HTTP 請求失敗
iOS9 默認(rèn)不支持 HTTP 請求,需要改用更安全的 HTTPS(默認(rèn)用 TLS 1.2)。蘋果還提供了配置,使得所有安全性更低的網(wǎng)絡(luò)請求也能使用,解決方案就是在 info.plist 里面增加以下配置:
1NSAppTransportSecurity????NSAllowsArbitraryLoads
如果復(fù)雜一些,還可以指定白名單域名,聲明所支持 TLS 的最低版本。另外需要注意的是,即使寫了上述配置,在 HTTPS 頁面中,HTTP 的 javascript 或 css 不會被加載,因?yàn)樘O果認(rèn)為這降低了頁面的安全性。
4.3、canOpenUrl 限制
canOpenUrl 可以用來判斷用戶是否安裝了某個 APP。也許是出于用戶隱私的考慮,iOS9 上對 canOpenUrl 做了限制,最多只能對 50 個 scheme 做判斷。如果是用 Xcode7 編譯,需要在 plist 里面聲明這些 scheme,沒有聲明的會直接返回 NO:
1LSApplicationQueriesSchemes????weixin????wechat
4.4、UIStatusBar的問題
iOS9中廢棄的方法
1//?修改狀態(tài)欄的樣式為白色
2//?'setStatusBarStyle(_:animated:)'?was?deprecated?in?iOS?9.0:?Use?-[UIViewController?preferredStatusBarStyle]
3UIApplication.shared.setStatusBarStyle(.lightContent,?animated:?true)
4//?隱藏狀態(tài)欄
5//?'setStatusBarHidden(_:with:)'?was?deprecated?in?iOS?9.0:?Use?-[UIViewController?prefersStatusBarHidden]
6UIApplication.shared.setStatusBarHidden(true,?with:?.fade)
7復(fù)制代碼用下面兩個方法替換
8-[UIViewController?preferredStatusBarstyle]
9-[UIViewController?preferredStatusBarHidden]
參考資料:
聊聊iOS 10更新以后跳轉(zhuǎn)系統(tǒng)設(shè)置的幾種方式
iOS 10 調(diào)用系統(tǒng)"設(shè)置"里的功能(全)