iOS 13 適配

推薦文章


iOS Swift 自定義導(dǎo)航欄 FLNavigationBar 解決所有問題

新特性適配


1. 第三方登錄

Sign In with Apple will be available for beta testing this summer. It will be required as an option for users in apps that support third-party sign-in when it is commercially available later this year. [原文]

如果 APP 支持三方登陸(Facbook、Google、微信、QQ、支付寶等),就必須支持蘋果登錄,且要放前邊.

Sign in with Apple 設(shè)計(jì)規(guī)范

2. 黑暗模式

通過UITraitCollection.currentTraitCollection.userInterfaceStyle獲取當(dāng)前模式。

iOS 13提供了內(nèi)置的動(dòng)態(tài)Color,會(huì)根據(jù)當(dāng)前userInterfaceStyle自動(dòng)顯示不同的顏色。

UIColor systemFillColor
UIColor secondarySystemFillColor
UIColor tertiarySystemFillColor
UIColor quaternarySystemFillColor
...

// 更多的時(shí)候需要自定義動(dòng)態(tài)顏色:
(UIColor )colorWithDynamicProvider:(UIColor (^)(UITraitCollection *))dynamicProvider API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
(UIColor )initWithDynamicProvider:(UIColor (^)(UITraitCollection *))dynamicProvider API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
//在回調(diào)中根據(jù)不同的userInterfaceStyle返回不同的顏色。

Web 同樣需要適配黑暗模式
Web Content適配
APP 適配教程
Adopting iOS Dark Mode
iOS13 Dark Mode 適配
WWDC2019-214-iOS 13 適配 dark mode
WWDC 設(shè)計(jì)分會(huì):iOS 13 設(shè)計(jì)新特性(1)
WWDC 設(shè)計(jì)分會(huì):iOS 13 設(shè)計(jì)新特性(2)

Api 變化


1. KVC 限制

iOS13 以后已經(jīng)不能肆無忌憚的通過 KVC 來修改一些沒有暴露出來的屬性了

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Access to xxx's _xxx ivar is prohibited. This is an application bug'

// UITextField 的 _placeholderLabel
[textField setValue:[UIColor xxx] forKeyPath:@"_placeholderLabel.textColor"];

// UISearchBar 的 _searchField
[searchBar valueForKey:@"_searchField"];

2. DeviceToken有變化


[deviceToken description] 獲取到的格式發(fā)生變化

// objc
NSString *dt = [deviceToken description];
dt = [dt stringByReplacingOccurrencesOfString: @"<" withString: @""];
dt = [dt stringByReplacingOccurrencesOfString: @">" withString: @""];
dt = [dt stringByReplacingOccurrencesOfString: @" " withString: @""];
// swift
let dt = deviceToken.description.replacingOccurrences(of:"<", with:"").replacingOccurrences(of:">", with:"").replacingOccurrences(of:" ", with:"")

解決方案

// objc
NSMutableString *dt= [NSMutableString string];
const char *bytes = deviceToken.bytes;
NSInteger count = deviceToken.length;
for (int i = 0; i < count; i++) {
    [dt appendFormat:@"%02x", bytes[i]&0x000000FF];
}
// swift
var dt: String = ""
let bytes = [UInt8](deviceToken)
for item in bytes {
     dt += String(format:"%02x", item&0x000000FF)
}

3. CNCopyCurrentNetworkInfo 變化


An app that fails to meet any of the above requirements receives the following return value:

  • An app linked against iOS 12 or earlier receives a dictionary with pseudo-values. In this case, the SSID is Wi-Fi (or WLAN in the China region), and the BSSID is 00:00:00:00:00:00.
  • An app linked against iOS 13 or later receives NULL.

iOS13 以后只有開啟了 Access WiFi Information capability,才能獲取到 SSID 和 BSSID
參考:CNCopyCurrentNetworkInfo

4. 藍(lán)牙權(quán)限說明

// 在iOS 13之前,想獲取手機(jī)連接的藍(lán)牙設(shè)備信息,可以直接使用此方法, 并不需要聲明權(quán)限
[CBCentralManager retrieveConnectedPeripheralsWithServices:]

iOS 13之后,必須在Info.plist文件中增加NSBluetoothAlwaysUsageDescription說明,否則crash。

視圖適配


  • 之前標(biāo)記為 API_DEPRECATED 部分類被移除

1. UISearchDisplayController

在 iOS 8 之前,我們在 UITableView 上添加搜索框需要使用 UISearchBar + UISearchDisplayController 的組合方式,而在 iOS 8 之后,蘋果就已經(jīng)推出了 UISearchController 來代替這個(gè)組合方式。在 iOS 13 中,如果還繼續(xù)使用 UISearchDisplayController 會(huì)直接導(dǎo)致崩潰,崩潰信息如下:

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'UISearchDisplayController is no longer supported when linking against this version of iOS. Please migrate your application to UISearchController.' 

另外說一下,在 iOS 13 中終于可以獲取直接獲取搜索的文本框:

_searchBar.searchTextField.text = @"search";

2. MPMoviePlayerController 被棄用

在 iOS 9 之前播放視頻可以使用 MediaPlayer.framework 中的MPMoviePlayerController類來完成,它支持本地視頻和網(wǎng)絡(luò)視頻播放。但是在 iOS 9 開始被棄用,如果在 iOS 13 中繼續(xù)使用的話會(huì)直接拋出異常:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'MPMoviePlayerController is no longer available. Use AVPlayerViewController in AVKit.'

解決方案是使用 AVFoundation 里的 AVPlayer

3. LaunchImage 被棄用

iOS 8 之前我們是在LaunchImage 來設(shè)置啟動(dòng)圖,但是隨著蘋果設(shè)備尺寸越來越多,我們需要在對(duì)應(yīng)的 aseets 里面放入所有尺寸的啟動(dòng)圖,這是非常繁瑣的一個(gè)步驟。因此在 iOS 8 蘋果引入了 LaunchScreen.storyboard,支持界面布局用的 AutoLayout + SizeClass ,可以很方便適配各種屏幕。

需要注意的是,蘋果在 Modernizing Your UI for iOS 13 section 中提到,從2020年4月開始,所有支持 iOS 13 的 App 必須提供 LaunchScreen.storyboard,否則將無法提交到 App Store 進(jìn)行審批。

4. 模態(tài)彈出默認(rèn)交互改變


/*
 Defines the presentation style that will be used for this view controller when it is presented modally. Set this property on the view controller to be presented, not the presenter.
 If this property has been set to UIModalPresentationAutomatic, reading it will always return a concrete presentation style. By default UIViewController resolves UIModalPresentationAutomatic to UIModalPresentationPageSheet, but other system-provided view controllers may resolve UIModalPresentationAutomatic to other concrete presentation styles.
 Defaults to UIModalPresentationAutomatic on iOS starting in iOS 13.0, and UIModalPresentationFullScreen on previous versions. Defaults to UIModalPresentationFullScreen on all other platforms.
 */
@property(nonatomic,assign) UIModalPresentationStyle modalPresentationStyle API_AVAILABLE(ios(3.2));

iOS 13 的 presentViewController 默認(rèn)有視差效果,模態(tài)出來的界面現(xiàn)在默認(rèn)都下滑返回。 一些頁面必須要點(diǎn)確認(rèn)才能消失的,需要適配。如果項(xiàng)目中頁面高度全部是屏幕尺寸,那么多出來的導(dǎo)航高度會(huì)出現(xiàn)問題。

// Swift
self.modalPresentationStyle = .fullScreen

// Objective-C
self.modalPresentationStyle = UIModalPresentationFullScreen;


這樣帶來了新的交互方式,下拉就可以 dismiss 控制器,實(shí)測這是個(gè)很爽的功能,體驗(yàn)大幅度提升,但是對(duì)我們開發(fā)者來說呢,帶來了一些坑,下面讓我們來看看吧。

首先 UIModalPresentationStyle 增加了一個(gè) automatic 屬性,在 iOS 13 下默認(rèn)就是這個(gè)屬性。系統(tǒng)會(huì)根據(jù)推出的控制器來選擇是 pageSheet 還是 fullScreen,比如當(dāng)我們用 UIImagePickerController 推出相機(jī)是 fullScreen,我們自己寫的控制器是 pageSheet。如果我們只想推出 fullScreen 的控制器也很簡單,present 之前設(shè)置 vc.modalPresentationStyle = .fullScreen 就好了。

接下來說一下 pageSheet 的坑是什么,我們先來看下 fullScreen 的調(diào)用順序。

再來看下 pageSheet 的調(diào)用順序

當(dāng)A控制器 present B控制器,A控制器的 viewWillDisappearviewDidDisappear 不會(huì)調(diào)用,當(dāng)B控制器 dismiss,A控制器的 viewWillAppearviewDidAppear 也不會(huì)調(diào)用。也就是說如果你有一些邏輯是放在這4個(gè)方法中的,要么把業(yè)務(wù)邏輯換個(gè)地方,要么設(shè)置 vc.modalPresentationStyle = .fullScreen。

另外,UIViewController 增加一個(gè)了屬性 isModalInPresentation,默認(rèn)為 false,當(dāng)該屬性為 false 時(shí),用戶下拉可以 dismiss 控制器,為 true 時(shí),下拉不可以 dismiss控制器。該屬性可以配合有編輯功能的控制器使用,讓我們來看下官方的 Demo

image

<figcaption></figcaption>

我們可以看到,未編輯內(nèi)容時(shí)下拉可以 dismiss,編輯了內(nèi)容后下拉不可以dismiss,同時(shí)彈出了一個(gè) alert 提示用戶要不要保存編輯過的內(nèi)容。詳細(xì)的代碼大家可以去 Demo 里看,這里就簡單說一下。

首先判斷用戶是否輸入,有輸入將 isModalInPresentation 改為 true。然后實(shí)現(xiàn) UIAdaptivePresentationControllerDelegate 代理的 presentationControllerDidAttemptToDismiss: 方法。這個(gè)方法會(huì)在 isModalInPresentation = true,且用戶嘗試下拉 dismiss 控制器時(shí)調(diào)用。最后在這個(gè)方法里彈出 alert 提示用戶是否保存編輯過的內(nèi)容即可。

5. UISegmentedControl 默認(rèn)樣式改變

默認(rèn)樣式變?yōu)榘椎缀谧?,如果設(shè)置修改過顏色的話,頁面需要修改原本設(shè)置選中顏色的 tintColor 已經(jīng)失效,新增了 selectedSegmentTintColor 屬性用以修改選中的顏色。

6. UITabbar 層次發(fā)生改變,無法通過設(shè)置 shadowImage去掉上面的線

7. App啟動(dòng)過程中,部分View可能無法實(shí)時(shí)獲取到frame


可能是為了優(yōu)化啟動(dòng)速度,App 啟動(dòng)過程中,部分View可能無法實(shí)時(shí)獲取到正確的frame

// 只有等執(zhí)行完 UIViewController 的 viewDidAppear 方法以后,才能獲取到正確的值,在viewDidLoad等地方 frame Size 為 0,例如:
 [[UIApplication sharedApplication] statusBarFrame];

8. UISearchBar 黑線處理導(dǎo)致崩潰

之前為了處理搜索框的黑線問題,通常會(huì)遍歷 searchBar 的 subViews,找到并刪除 UISearchBarBackground,在 iOS13 中這么做會(huì)導(dǎo)致 UI 渲染失敗,然后直接崩潰,崩潰信息如下:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Missing or detached view for search bar layout'

解決辦法是設(shè)置 UISearchBarBackground 的 layer.contents 為 nil:

for (UIView *view in _searchBar.subviews.lastObject.subviews) {
    if ([view isKindOfClass:NSClassFromString(@"UISearchBarBackground")]) {
        // [view removeFromSuperview];
        view.layer.contents = nil;
        break;
    }
}

9. UIActivityIndicatorView

之前的 UIActivityIndicatorView 有三種 style 分別為 whiteLarge, whitegray,現(xiàn)在全部廢棄。
增加兩種 style 分別為 mediumlarge,指示器顏色用 color 屬性修改。

10. UINavigationBar

修改 layoutMargins 屬性崩潰

// MARK: layoutMargins 設(shè)置
- (void)barGainASystemView {
    if (@available(iOS 11.0, *)) {
        if (!_systemNavigationBarContentView) {
            for (UIView *subView in self.subviews) {
                if ([NSStringFromClass([subView class]) isEqualToString:@"_UINavigationBarContentView"]) {
                    _systemNavigationBarContentView = subView;
                }
            }
        }
        if (_systemNavigationBarContentView) {
//            _systemNavigationBarContentView.layoutMargins = UIEdgeInsetsZero;
        }
    }
}
·參考文獻(xiàn)

本文結(jié)合以下文檔內(nèi)容和個(gè)人遇到的問題,對(duì)常見適配問題進(jìn)行總結(jié)

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

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

  • 在簡書偶爾會(huì)被鎖定,本文在掘金也同步更新。 iOS 13 支持適配的機(jī)型 iPhone 11、iPhone 11 ...
    _森宇_閱讀 9,758評(píng)論 2 37
  • iOS 13 如期而至,適配工作可以開展起來啦。在適配 iOS 13 過程中,遇到了如下一些問題。 1. UITe...
    前行哲閱讀 20,555評(píng)論 48 136
  • iOS13 beta版本已經(jīng)發(fā)布,手癢的升級(jí)Xcode和iOS,同時(shí)也發(fā)現(xiàn)了一些問題,這里更新下。。。 KVC i...
    張叔叔閱讀 24,821評(píng)論 10 15
  • 私有KVC 與系統(tǒng)版本無關(guān),與Xcode版本有關(guān),Xcode11編譯會(huì)奔潰。 其中UITextField [tex...
    Kity_Pei閱讀 15,762評(píng)論 12 13
  • 前言 蘋果爸爸又出新品,想必各位大佬,都是緊跟其步伐,在此總結(jié)下目前iOS 13 遇到的奔潰,以及Dark Mod...
    天下林子閱讀 1,812評(píng)論 1 12

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