iOS12、iOS11、iOS10、iOS9常見適配

iOS12、iOS11、iOS10、iOS9常見適配

@(IOS各個版本適配)

[TOC]

一、iOS12(Xcode10)

1.1、升級Xcode10后項(xiàng)目報錯

不允許多個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.

image

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

image

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

解決辦法二:

刪除其他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檢測代碼
if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {

}
復(fù)制代碼

swift檢測代碼
self.traitCollection.forceTouchCapability == .availible
復(fù)制代碼

二、iOS11(Xcode9)

2.1、安全區(qū)域(SafeArea)

iOS11為UIViewControllerUIView增加了兩個新的屬性safeAreaInsetssafeAreaLayoutGuide

  • safeAreaInsets 適用于手動計算.
  • safeAreaLayoutGuide 適用于自動布局.
UIViewController中新增:
- (void)viewSafeAreaInsetsDidChange;
UIView中新增:
- (void)viewSafeAreaInsetsDidChange;
復(fù)制代碼

Storyboard使用Safe Area最低只支持iOS9,iOS8的用戶就要放棄了

image

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

當(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以及viewControllerSafeArea(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)
#import "Adaptive11VC.h"
static inline UIEdgeInsets sgm_safeAreaInset(UIView *view) {
    if (@available(iOS 11.0, *)) {
        return view.safeAreaInsets;
    }
    return UIEdgeInsetsZero;
}

@interface Adaptive11VC ()
@end
@implementation Adaptive11VC
- (void)viewDidLoad {
    [super viewDidLoad];
}
- (void)testSafeArea {
    UIEdgeInsets safeAreaInsets = sgm_safeAreaInset(self.view);
    NSLog(@"safeAreaInsets = %@", NSStringFromUIEdgeInsets(safeAreaInsets));
}
- (void)viewSafeAreaInsetsDidChange {
    [super viewSafeAreaInsetsDidChange];
    [self testSafeArea];
}
@end
復(fù)制代碼

2.2、UIScrollView

iOS 11廢棄了UIViewControllerautomaticallyAdjustsScrollViewInsets屬性,新增了contentInsetAdjustmentBehavior屬性,所以當(dāng)超出安全區(qū)域時系統(tǒng)自動調(diào)整了SafeAreaInsets,進(jìn)而影響了adjustedContentInset,在iOS11中決定tableView內(nèi)容與邊緣距離的是adjustedContentInset,所以需要設(shè)置UIScrollViewcontentInsetAdjustmentBehavior屬性。

// 方式一:(不推薦)修改額外的安全區(qū)域
if (@available(iOS 11.0, *)) {
    self.additionalSafeAreaInsets = UIEdgeInsetsMake(-44, 0, 0, 0);
}
else {
    // Fallback on earlier versions
}
// 方式二:(推薦)設(shè)置為不自動調(diào)整
if (@available(iOS 11.0, *)) {
    // 作用于指定的UIScrollView
    self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
    // 作用與所有的UIScrollView
    UIScrollView.appearance.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
else {
    self.automaticallyAdjustsScrollViewInsets = NO;
}
復(fù)制代碼

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)致高度計算不對,會產(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)證,可使用以下代碼:

#import <LocalAuthentication/LocalAuthentication.h>
/**
 檢測TouchID是否可用
 */
- (void)checkBiometrics {
    LAContext *context = [[LAContext alloc] init];
    BOOL success = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
                                        error:nil];
    if ( success ) {
        NSLog(@"can use");
    }
    else {
        NSLog(@"can`t use ");
    }
}
/**
 在驗(yàn)證TouchID可用的情況下使用
 */
- (void)excuteBiometrics {
    LAContext *context = [[LAContext alloc] init];
    context.localizedFallbackTitle = @"自定義標(biāo)題";
    [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
            localizedReason:@"為什么使用TouchID寫這里"
                      reply:^(BOOL success, NSError * _Nullable error) {
        if ( success ) {
            // 指紋驗(yàn)證成功
        }
        else {
            switch (error.code) {
                case LAErrorUserFallback:{
                    NSLog(@"用戶選擇輸入密碼");
                    break;
                }
                case LAErrorAuthenticationFailed:{
                    NSLog(@"驗(yàn)證失敗");
                    break;
                }
                case LAErrorUserCancel:{
                    NSLog(@"用戶取消");
                    break;
                }
                case LAErrorSystemCancel:{
                    NSLog(@"系統(tǒng)取消");
                    break;
                }
                // 以下三種情況如果提前檢測TouchID是否可用就不會出現(xiàn)
                case LAErrorPasscodeNotSet:{
                    break;
                }
                case LAErrorTouchIDNotAvailable:{
                    break;
                }
                case LAErrorTouchIDNotEnrolled:{
                    break;
                }
                default:
                    break;
            }
        }
    }];
}
復(fù)制代碼

2.5、啟動圖的適配

方法一:通過LaunchScreen.storyboard方式啟動

方法二:使用Assets中的LaunchImage

image

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

  • 給Brand Assets添加一張1125*2436大小的圖片
    • 打開Assets.xcassets文件夾,找到Brand Assets
    • 右鍵Show in Finder
    • 添加一張1125*2436大小的圖片
  • 修改Contents.json文件,添加如下內(nèi)容
{
    "extent" : "full-screen",
    "idiom" : "iphone",
    "subtype" : "2436h",
    "filename" : "1125_2436.png",
    "minimum-system-version" : "11.0",
    "orientation" : "portrait",
    "scale" : "3x"
}
復(fù)制代碼

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(即使 NSLocationAlwaysUsageDescription 在 iOS 11及以上版本不再使用):

NSLocationWhenInUseUsageDescription
NSLocationAlwaysAndWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
NSLocationAlwaysAndWhenInUseUsageDescription  // 為 iOS 11 中新引入的一個 Key。
復(fù)制代碼

2.7、iOS11中 UIKit’s Bars 上的變化

三、iOS10(Xcode8)

3.1、(Why?Safe!)插件取消

Xcode8取消了三方插件(很多優(yōu)秀的插件,本來可以顯著提高效率)的功能,使用Extension代替 Xcode 8 Extension 推薦

3.2、證書問題

為了方便用戶來管理,提供Automatically manage signing。需要輸入開發(fā)者賬號!如果沒有賬號也沒關(guān)系,在下面也可以選擇DebugRealease、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添加NSContactsUsageDescriptionkey, value自己隨意填寫就可以,這里列舉出對應(yīng)的key(Source Code模式下):

<key>NSPhotoLibraryUsageDescription</key><string>App需要您的同意,才能訪問相冊</string>

<key>NSCameraUsageDescription</key><string>App需要您的同意,才能訪問相機(jī)</string>

<key>NSMicrophoneUsageDescription</key><string>App需要您的同意,才能訪問麥克風(fēng)</string>

<key>NSLocationUsageDescription</key><string>App需要您的同意,才能訪問位置</string>

<key>NSLocationWhenInUseUsageDescription</key><string>App需要您的同意,才能在使用期間訪問位置</string>

<key>NSLocationAlwaysUsageDescription</key><string>App需要您的同意,才能始終訪問位置</string>

<key>NSCalendarsUsageDescription</key><string>App需要您的同意,才能訪問日歷</string>

<key>NSRemindersUsageDescription</key><string>App需要您的同意,才能訪問提醒事項(xiàng)</string>

<key>NSMotionUsageDescription</key><string>App需要您的同意,才能訪問運(yùn)動與健身</string>

<key>NSHealthUpdateUsageDescription</key><string>App需要您的同意,才能訪問健康更新 </string>

<key>NSHealthShareUsageDescription</key><string>App需要您的同意,才能訪問健康分享</string>

<key>NSBluetoothPeripheralUsageDescription</key><string>App需要您的同意,才能訪問藍(lán)牙</string>

<key>NSAppleMusicUsageDescription</key><string>App需要您的同意,才能訪問媒體資料庫</string>
復(fù)制代碼

隱私數(shù)據(jù) 對應(yīng)key值
相冊 NSPhotoLibraryUsageDescription
相機(jī) NSCameraUsageDescription
麥克風(fēng) NSMicrophoneUsageDescription
位置 NSLocationUsageDescription
在使用期間訪問位置 NSLocationWhenInUseUsageDescription
始終訪問位置 NSLocationAlwaysUsageDescription
日歷 NSCalendarsUsageDescription
提醒事項(xiàng) NSRemindersUsageDescription
運(yùn)動與健身 NSMotionUsageDescription
健康更新 NSHealthUpdateUsageDescription
健康分享 NSHealthShareUsageDescription
藍(lán)牙 NSBluetoothPeripheralUsageDescription
媒體資料庫 NSAppleMusicUsageDescription

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];

// iOS系統(tǒng)版本 >= 10.0
{
    NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
    if ([[UIApplication sharedApplication] canOpenURL:url]) {
        [[UIApplication sharedApplication] openURL:url];
    }
}
return;
// iOS系統(tǒng)版本 >= 10.0
// But! 不建議這樣做哦,官方文檔中說過:
// `URL is now considered a private API and use will result in app rejection`.
// 雖然是有可能躲過蘋果的檢測,但是蘋果如果發(fā)現(xiàn)你這樣用了,app上架是有被拒的風(fēng)險的.
{
    NSURL *url = [NSURL URLWithString:@"APP-Prefs:root=WIFI"];
    if ([[UIApplication sharedApplication] canOpenURL:url]) {
        if (@available(iOS 10.0, *)) {
            [[UIApplication sharedApplication] openURL:url 
                                               options:@{} 
                                     completionHandler:nil];
        } else {
            // Fallback on earlier versions
        }
    }
}
// iOS系統(tǒng)版本 < 10.0
{
    NSURL *url = [NSURL URLWithString:@"prefs:root=WIFI"];
    if ([[UIApplication sharedApplication] canOpenURL:url]) {
        [[UIApplication sharedApplication] openURL:url];
    }
}
復(fù)制代碼

跳轉(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)化

  • <input checked="" disabled="" type="checkbox" style="font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; overflow: visible; box-sizing: border-box; padding: 0px;"> 在iOS 10 之前,cell只能從重用隊列里面取出,再走一遍生命周期,并調(diào)用cellForItemAtIndexPath創(chuàng)建或者生成一個cell.

  • <input checked="" disabled="" type="checkbox" style="font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; overflow: visible; box-sizing: border-box; padding: 0px;"> 在iOS 10 中,系統(tǒng)會cell保存一段時間,也就是說當(dāng)用戶把cell滑出屏幕以后,如果又滑動回來,cell不用再走一遍生命周期了,只需要調(diào)用willDisplayCell方法就可以重新出現(xiàn)在屏幕中了.

  • <input checked="" disabled="" type="checkbox" style="font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; overflow: visible; box-sizing: border-box; padding: 0px;"> iOS 10 中,系統(tǒng)是一個一個加載cell的,二以前是一行一行加載的,這樣就可以提升很多性能;

  • <input checked="" disabled="" type="checkbox" style="font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; overflow: visible; box-sizing: border-box; padding: 0px;"> iOS 10 新增加的Pre-Fetching預(yù)加載

3.7、UIRefreshControl

在iOS 10 中, UIRefreshControl可以直接在UICollectionView和UITableView中使用,并且脫離了UITableViewController.現(xiàn)在RefreshControl是UIScrollView的一個屬性.

3.8、UserNotifications(用戶通知)

  • <input checked="" disabled="" type="checkbox" style="font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; overflow: visible; box-sizing: border-box; padding: 0px;"> iOS 10所有相關(guān)通知被統(tǒng)一到了UserNotifications.framework框架中。增加了撤銷、更新、中途還可以修改通知的內(nèi)容。通知不在是簡單的文本了,可以加入視頻、圖片,自定義通知的展示等等。

  • <input checked="" disabled="" type="checkbox" style="font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; overflow: visible; box-sizing: border-box; padding: 0px;"> iOS 10相對之前的通知來說更加好用易于管理,并且進(jìn)行了大規(guī)模優(yōu)化,對于開發(fā)者來說是一件好事。

  • <input checked="" disabled="" type="checkbox" style="font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; overflow: visible; box-sizing: border-box; padding: 0px;"> 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。

image

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

解決辦法二: 移除不支持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 里面增加以下配置:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>
復(fù)制代碼

如果復(fù)雜一些,還可以指定白名單域名,聲明所支持 TLS 的最低版本。另外需要注意的是,即使寫了上述配置,在 HTTPS 頁面中,HTTP 的 javascript 或 css 不會被加載,因?yàn)樘O果認(rèn)為這降低了頁面的安全性。

4.3、canOpenUrl 限制

canOpenUrl 可以用來判斷用戶是否安裝了某個 APP。也許是出于用戶隱私的考慮,iOS9 上對 canOpenUrl 做了限制,最多只能對 50 個 scheme 做判斷。如果是用 Xcode7 編譯,需要在 plist 里面聲明這些 scheme,沒有聲明的會直接返回 NO:

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>weixin</string>
    <string>wechat</string>
</array>
復(fù)制代碼

4.4、UIStatusBar的問題

iOS9中廢棄的方法

// 修改狀態(tài)欄的樣式為白色
// 'setStatusBarStyle(_:animated:)' was deprecated in iOS 9.0: Use -[UIViewController preferredStatusBarStyle]
UIApplication.shared.setStatusBarStyle(.lightContent, animated: true)
// 隱藏狀態(tài)欄
// 'setStatusBarHidden(_:with:)' was deprecated in iOS 9.0: Use -[UIViewController prefersStatusBarHidden]
UIApplication.shared.setStatusBarHidden(true, with: .fade)
復(fù)制代碼

用下面兩個方法替換

-[UIViewController preferredStatusBarstyle]
-[UIViewController preferredStatusBarHidden]
復(fù)制代碼

參考資料:

iOS12適配

iOS12AdaptationTips

關(guān)于iPhone X 的適配

iOS11適配iPhoneX總結(jié)

iOS 10 適配知識點(diǎn)總結(jié)

聊聊iOS 10更新以后跳轉(zhuǎn)系統(tǒng)設(shè)置的幾種方式

iOS 10 調(diào)用系統(tǒng)"設(shè)置"里的功能(全)

iOS TouchID驗(yàn)證和Keychain結(jié)合使用

iOS10AdaptationTips

適配iOS9

微信 iOS 9 適配總結(jié)

iOS9AdaptationTips

作者:指尖猿
鏈接:http://www.itdecent.cn/p/c30c1c3b569f

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容