iOS 13 適配

一、前言

針對 iOS 13,蘋果作了很是大的調整,其中 Dark 模式是最新的 UI 層面可見的改變,而針對iPad推出了 iPadOS,致使了與 iOS 的分化,同時爲了 iPad 而不得不對 iOS 一樣作出的改變,好比一個應用支持多 window 顯示。因此,每一年 WWDC 後,由於每一個應用的狀況不同,使用的API各不相同,致使適配的工做沒法一致,你們遇到的坑不相同,因此,把你們遇到的問題都彙總起來,那就是必定有做用,這就是本文的初心。ios

二、iOS 13 適配問題

1. 如何關閉程序中的暗黑模式?

iOS13最大的特色是帶來了暗黑模式,可是若是不適配的話,可能會出現該是黑色的地方用了白色了,該是白色的地方是黑色了,看不到了,怎麼關掉呢?git

  • 1.1 代碼方式: 能夠每個頁面設置,固然也能夠總體設置,通常咱們的APP都是在一個window下的,那就總體設置APP裏的window:
#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
    if(@available(iOS 13.0,*)){
        self.window.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
    }
#endif
複製代碼
  • 1.2 配置文件方式: 在 Info.plist 添加key: UIUserInterfaceStyle 設置爲強制用暗黑模式(Dark)或白天模式(Light

iOS13-Dark.png

<key>UIUserInterfaceStyle</key>
<string>UIUserInterfaceStyleLight</string>
複製代碼

目前蘋果尚未公佈何時強制適配黑夜模式。按以前的官方的文章實際上是沒有強制要求全部App都適配,由於有些App確實可能很難適配。github

若是您須要更多時間調節 app 在深色模式中的外觀,或您的 app 不適用於深色模式,您可進一步瞭解如何停用深色模式。web

2. UIWebView 已棄用

ITMS-90809: Deprecated API Usage - Apple will stop accepting submissions of apps that use UIWebView APIs . See developer.apple.com/documentati… for more information.swift

UIWebView iOS 2.0–12.0 Deprecated Mac Catalyst 13.0–13.0 Deprecatedwindows

2019-12月更新瀏覽器

The App Store will no longer accept new apps using UIWebView as of April 2020 and app updates using UIWebView as of December 2020.bash

蘋果已經強制要求2020年4月新應用不能再使用 UIWebView,2020年12月全部應用更新不能在使用 UIWebView。微信

3. PresentViewController 模式變更

iOS13後,Prensent方式彈出頁面時,默認的模式變爲了UIModalPresentationAutomatic,這樣的方式也挺好的,動畫也好看,自帶關閉,只要下拉就關閉頁面了,這樣的動畫方式下,以前會出現的《UITabBar在iPhoneX等Push時顯示錯亂問題》 的問題也不存在了。 但有的時候,咱們不但願使用這個樣式,好比須要用戶不能關閉的:app

iOS13-PresentViewController.png

只要指定彈出頁的 modalPresentationStyle 屬性,注意是要Present的頁面:

UIViewController *vc = [[UIViewController alloc] init];
vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self.navigationController presentViewController:vc animated:YES completion:nil];
複製代碼

4. 增長"一直使用藍牙"的權限申請

iOS 13起,app的 info.plist裏增長

<key>NSBluetoothAlwaysUsageDescription</key>
<string>咱們要一直使用您的藍牙,具體作什麼別問我</string>
複製代碼

5. WKWebView 中測量頁面內容高度的方式變動

iOS 13之前

document.body.scrollHeight 
複製代碼

iOS 13中

document.documentElement.scrollHeight
複製代碼

二者相差55 應該是瀏覽器定義高度變了

6. UIActivityIndicatorView

以前的 UIActivityIndicatorView 有三種 style 分別爲 whiteLarge, whitegray,如今所有廢棄。 增長兩種 style 分別爲 mediumlarge,指示器顏色用 color 屬性修改。

iOS13-UIActivityIndicatorView.png

7. Status Bar

去掉原來 .default .lightContent,改成 :

![iOS13-Status Bar.png](github.com/iHTCboy/iGa… Bar.png)

8. Sign In with Apple

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. Apple登陸將於今年夏天進行beta測試。對於支持第三方用戶登陸的應用中,apple 登陸將在今年晚些時候上市銷售時做爲選項。

經過API來獲取到諸如用戶姓名這樣的信息,可是最爲關鍵的userIdentifier則是毫無規律可言的(至少在咱們開發者看來),而這個userIdentifier則爲同一個開發者帳號下的全部app中保持有且僅有一個。 另外,apple 登陸是支持跨平臺,安卓和 windows 的 web 頁面中使用 apple id 登陸受權。

注意: Sign In with Apple 須要用戶開啓了兩步認證,若是沒有開啓則會在第一次使用時提示開啓,不開啓將沒法使用。

另外,蘋果登陸按鈕有所要求, 詳細見 Sign In with Apple - Sign In with Apple - Human Interface Guidelines - Apple Developer

2019年9月更新

4.8 經過 Apple 登陸 若是 app 專門使用第三方或社交登陸服務 (例如,Facebook 登陸、Google 登陸、經過 Twitter 登陸、經過 LinkedIn 登陸、經過 Amazon 登陸或微信登陸) 來對其進行設置或驗證這個 app 的用戶主賬戶,則該 app 必須同時提供「經過 Apple 登陸」做爲等效選項。用戶的主賬戶是指在 app 中創建的、用於標識身份、登陸和訪問功能和相關服務的賬戶。 在如下狀況下,不要求提供「經過 Apple 登陸」選項:

  • 您的 app 僅使用公司自有的賬戶設置和登陸系統。
  • 您的 app 是一款教育、企業或商務 app,要求用戶使用現有的教育或企業賬戶登陸。
  • 您的 app 使用政府或行業支持的公民身份系統或電子身份證來鑑定用戶身份。
  • 您的 app 是特定第三方服務的客戶端,用戶須要使用他們的郵件、社交媒體或其餘第三方賬戶直接登陸才能訪問內容。

9. KVC 限制

iOS 13 經過 KVC 方式修改私有屬性,有 Crush 風險,謹慎使用! iOS13 之後已經不能肆無忌憚的經過 KVC 來修改一些沒有暴露出來的屬性了。會崩潰: 'Access to UITextField's _placeholderLabel ivar is prohibited. This is an application bug'

已知:

// UITextField的placeholder的顏色
[textField setValue:[UIColor xxx] forKeyPath:@"_placeholderLabel.textColor"];
// UISearchBar 的 _searchField
[searchBar valueForKey:@"_searchField"];
複製代碼

修改以下:

NSMutableAttributedString *placeholderString = [[NSMutableAttributedString alloc] initWithString:placeholder attributes:@{NSForegroundColorAttributeName : self.placeholderColor}];
_textField.attributedPlaceholder = placeholderString;
複製代碼

10. UISegmentedControl 默認樣式改變

默認樣式變爲白底黑字,若是設置修改過顏色的話,頁面須要修改。另外UI樣式發生了變化。

11. App啓動過程當中,部分View可能沒法實時獲取到frame

多是爲了優化啓動速度(或者留海屏緣由),App 啓動過程當中,部分View可能沒法實時獲取到正確的frame

// 只有等執行完 UIViewController 的 viewDidAppear 方法之後,才能獲取到正確的值,在viewDidLoad等地方 frame Size 爲 0,例如:
 [[UIApplication sharedApplication] statusBarFrame];
複製代碼

12. MPMoviePlayerController 在iOS 13 棄用

在使用到MPMoviePlayerController的地方,直接拋了異常:

'MPMoviePlayerController is no longer available. Use AVPlayerViewController in AVKit.'
複製代碼

替代方案就是AVKit裏面的那套播放器

13. iOS 13 DeviceToken有變化

這個很重要!!! 可能大多數使用第三方推送的童鞋都不會注意到這個問題,通常如今的第三方推送都是將DeviceToken原始數據丟進去,具體的解析都是第三方內部處理,因此,這些第三方解析DeviceToken的方式正確的話,那就毫無問題。若是大家是經過這種方式來獲取DeviceToken,那你須要注意了。(這個坑也是多年前埋下的,不少文章介紹的也是下面這個方法,不規範的作法早晚要還的),以下:

NSString *dt = [deviceToken description];
dt = [dt stringByReplacingOccurrencesOfString: @"<" withString: @""];
dt = [dt stringByReplacingOccurrencesOfString: @">" withString: @""];
dt = [dt stringByReplacingOccurrencesOfString: @" " withString: @""];
複製代碼

這段代碼運行在 iOS 13 上已經沒法獲取到準確的DeviceToken字符串了,iOS 13 經過[deviceToken description]獲取到的內容已經變了。

{length = 32, bytes = 0x778a7995 29f32fb6 74ba8167 b6bddb4e ... b4d6b95f 65ac4587 }
複製代碼

解決方法,fb sdk 中:

+ (NSString *)hexadecimalStringFromData:(NSData *)data
{
    NSUInteger dataLength = data.length;
    if (dataLength == 0) {
        return nil;
    }
    const unsigned char *dataBuffer = data.bytes;
    NSMutableString *hexString = [NSMutableString stringWithCapacity:(dataLength * 2)];
    for (int i = 0; i < dataLength; ++i) {
        [hexString appendFormat:@"%02x", dataBuffer[i]];
    }
    return [hexString copy];
}
複製代碼

友盟推送的解決方法

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
     if (![deviceToken isKindOfClass:[NSData class]]) return;
           const unsigned *tokenBytes = (const unsigned *)[deviceToken bytes];
          NSString *hexToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
          ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
          ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
          ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];
          NSLog(@"deviceToken:%@",hexToken);
     }
}

複製代碼

這2個方法那個好? 根據蘋果文檔 application:didRegisterForRemoteNotificationsWithDeviceToken:

友盟的兼容方案並不嚴謹,蘋果說tokens長度可變,建議不要硬編碼!!

更多參考: iOS13 PKPushCredentials broken |Apple Developer Forums facebook-objc-sdk/FBSDKInternalUtility.m 【公告】iOS 13正式發佈後對U-Push的影響 NotificationCenter · Issue #23 · ChenYilong/iOS13AdaptationTips

14. 即將廢棄的 LaunchImage

從 iOS 8 的時候,蘋果就引入了 LaunchScreen,咱們能夠設置 LaunchScreen來做爲啓動頁。固然,如今你還可使用LaunchImage來設置啓動圖。不過使用LaunchImage的話,要求咱們必須提供各類屏幕尺寸的啓動圖,來適配各類設備,隨着蘋果設備尺寸愈來愈多,這種方式顯然不夠 Flexible。而使用 LaunchScreen的話,狀況會變的很簡單, LaunchScreen是支持AutoLayout+SizeClass的,因此適配各類屏幕都不在話下。

注意: 從2020年4月開始,全部使⽤ iOS13 SDK 的 App 將必須提供 LaunchScreen,LaunchImage即將退出歷史舞臺。

再補充一點,在使用 LaunchScreen的時候,裏面用到的圖片資源,最好別放在 xcassets 裏面,否則在你修改圖片後,你會發現真機上並不會生效。

15. App Delegate

iOS 支持多界面同時運行多個用戶界面。 root view controller 的 view superview 也不直接是 UIWindow 了:

iOS13-Multiple-Windows.png

iOS 13 能夠多windows窗口,把ui相關的生命週期單獨到 SceneDelegate:

iOS13-SessionLifecycle.png

若是實現 SceneDelegate 那麼iOS 13會調整 SceneDalegate, 若是不實現,就會使用 AppDelegate。iOS 12 如下仍是調用 AppDelegate:

iOS13-UISessionDelegate.png

@property(nullable, nonatomic,readonly) UIWindow *keyWindow API_DEPRECATED("Should not be used for applications that support multiple scenes as it returns a key window across all connected scenes", ios(2.0, 13.0));
複製代碼

獲取keyWindow 使用 [UIApplicatoin sharedApplication].keyWindow 狀況就有多種:

  • 一、此接口已經棄用
  • 二、針對 iPad, 一個應用能夠打開多窗口(好比 office 能夠打開多個 word 文檔。),此時,keyWindow 就有多個 scenes,並不惟一。
  • 三、針對 iPhone,目前還不能同時打開多窗口。因此 keyWindow 仍是惟一的,暫時不影響獲取。

沒有了 keyWindow,那之後怎麼得到當前激活中的 window 呢?能夠看看這裏:How to resolve: 'keyWindow' was deprecated in iOS 13.0

具體調整可參見官方WWDC: Architecting Your App for Multiple Windows - WWDC 2019 - Videos - Apple Developer

16. - (BOOL)application: openURL: options: 中 SourceApplication 爲 nil

在 Xcode 11以前的文檔:

// value is an NSString containing the bundle ID of the originating application

在 Xcode 11後變爲:

// value is an NSString containing the bundle ID of the originating application; non-nil if the originating application and this application share the same team identifier

官方在線文檔:

UIApplicationOpenURLOptionsSourceApplicationKey A key that contains the bundle ID of the app that sent the open-URL request to your app.

The value of this key is an NSString object containing the bundle ID of the app that made the request. If the request originated from another app belonging to your team, UIKit sets the value of this key to the ID of that app. If the team identifier of the originating app is different than the team identifier of the current app, the value of the key is nil.

在 iOS 13 中,非同一開發者帳號(team identifier)的App,在 iOS 13 經過 URL Scheme 打開App裏,在代理方法 - (BOOL)application: openURL: options: 中將UIApplicationOpenURLOptionsSourceApplicationKey返回爲nil,也就是說,再也拿不到原App的 bundle ID,關於這個你們都說是蘋果爲了解決隱私問題?

對於開發者來講,若是有使用到 SourceApplication 字段,只能在 iOS 13以上調整本身的業務邏輯。

總結

這些都只是常見和彙總網上你們遇到的狀況,還有不少細節上,針對 iOS13 須要你們細調,這些年下來,iOS各系統版本以前的突變不少,固然這樣也有好處,好比 WKWebview 支持 iOS 8.0 + , SFSafariViewController 支持 iOS 9.0+,慢慢地,不少更好的 API 你們均可以使用,拋棄舊的接口,兼容新的接口,這樣的工做,可預見將來一直會這樣,誰叫咱們是 API 使用者!努力成爲提供 API man 吧!

參考


  • 若有不正確的地方,歡迎指導!
  • 若有疑問,歡迎在評論區一塊兒討論!
> 注:本文首發於 [iHTCboy's blog](https://iHTCboy.com),如若轉載,請注來源
相關文章
相關標籤/搜索