iOS11 & iPhoneX適配總結(jié)

一滋觉、前言

iOS11發(fā)布也有一段時(shí)間了到千,每次版本升級(jí)昌渤,相關(guān)的適配工作當(dāng)然是下個(gè)版本的核心工作之一。而且這次iOS11的更新憔四,相對(duì)于iOS10的更新來說膀息,改動(dòng)點(diǎn)還是比較多的。除了iOS11系統(tǒng)的更新之外加矛,iPhoneX劉海的打理工作也是必不可少履婉。以前我們總是慶幸作為iOS開發(fā)者,不必像Android開發(fā)者需要考慮各種不同機(jī)型的適配問題斟览。但是現(xiàn)在,隨著iPhone各種歷史版本的存在辑奈,各種花式的新版本產(chǎn)生苛茂,不同版本之間的適配問題,也是未來我們作為iOS開發(fā)者必然要考慮的重要問題之一鸠窗。
這次我主要負(fù)責(zé)我們這邊兩款A(yù)pp(滴滴代駕司機(jī)端+駕管App)iOS11&iPhoneX適配工作妓羊。中間也躺過很多坑,一一記錄了下來寫成這篇文章稍计,既是對(duì)自己工作的一次總結(jié)躁绸,也可以分享給其他iOS開發(fā)者,能夠讓大家少趟一些坑。
本文將分為三個(gè)部分净刮,分別從三方庫適配剥哑、UI適配、權(quán)限適配淹父、補(bǔ)充知識(shí)等方面分別進(jìn)行展開株婴。

二、三方庫適配問題暑认。

2.1 CocoaLumberjack 編譯出錯(cuò)

CocoaLumberjack編譯報(bào)錯(cuò)

問題原因:

從錯(cuò)誤提示可以看出在Xcode9中os_log_error的第二個(gè)參數(shù)format必須要為不可變的string類型困介,而不是char*。

解決方案:

我們只要改成如下形式就可以了

os_log_error(OS_LOG_DEFAULT, "%s", msg);

CocoaLumberjack的作者也在[issue883](https://github.com/Co coaLumberjack/CocoaLumberjack/issues/883)中解決了該問題蘸际。如果你的工程是pod依賴的話座哩,將pod版本升級(jí)到3.3.0版本即可。

2.2 WebViewJavascriptBridge崩潰處理

我們代駕司機(jī)端web容器使用的是WKWebView粮彤,jsBridge使用的是WebViewJavascriptBridge這個(gè)三方庫根穷,更新到Xcode9之后,只要進(jìn)入WKWebView容器驾诈,就會(huì)產(chǎn)生如下crash:


WebViewJavascriptBridge crash

問題原因:

當(dāng)你使用WKWebView作為你的H5容器的時(shí)候缠诅,WKNavigationDelegate有個(gè)回調(diào)就是

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

這個(gè)回調(diào)主要負(fù)責(zé)根據(jù)webView、navigationAction相關(guān)信息決定這次跳轉(zhuǎn)是否可以繼續(xù)進(jìn)行乍迄。調(diào)用decisionHandler(WKNavigationActionPolicyAllow);響應(yīng)這次跳轉(zhuǎn)請(qǐng)求管引。調(diào)用decisionHandler(WKNavigationActionPolicyCancel);就是不響應(yīng)這次跳轉(zhuǎn)請(qǐng)求。

查看WebViewJavascriptBridge源碼可以看出闯两,在WKWebViewJavascriptBridge.m文件中褥伴,

WKVebViewCrash.png

在Xcode9中,如果連續(xù)看了兩次調(diào)用decisionHandler方法就會(huì)crash漾狼。這個(gè)問題在之前版本的Xcode均是沒有問題的重慢。

解決方案:

  • 方案一:修改源碼

    在上面代碼的149行和150行之間添加return;

  • 方案二:pod依賴,原作者沒有修改此問題逊躁,無法修改源碼似踱,也可以在業(yè)務(wù)代碼中進(jìn)行規(guī)避。

    在你自己業(yè)務(wù)代碼的對(duì)應(yīng)對(duì)調(diào)中添加排除代碼稽煤,如下:


    WKWebViewCrash2.png

2.3 LumberjackConsole UI適配

出錯(cuò)樣式 正確樣式
收縮出錯(cuò)
收縮正確
展開出錯(cuò)
展開正確

問題原因:

iOS7之后核芽,如何你設(shè)置self.edgesForExtendedLayout = UIRectEdgeNone的話,系統(tǒng)通過設(shè)置UIViewController的automaticallyAdjustsScrollViewInsets屬性來自動(dòng)調(diào)整UIScrollView的contentInset,使UIscrollView能夠呈現(xiàn)在我們的可是范圍之內(nèi)酵熙,而不會(huì)被navBar擋住轧简。這個(gè)屬性在iOS11中被廢棄掉了,在iOS11中代替該屬性功能的則是UIScrollView類中的contentInsetAdjustmentBehavior和adjustedContentInset屬性.在iOS11中用來決定scrollView超出安全區(qū)域與邊緣距離的屬性是adjustedContentInset而不是contentInset匾二。當(dāng)scrollView超出安全區(qū)域時(shí)系統(tǒng)會(huì)自動(dòng)調(diào)整SafeAreaInsets值哮独,進(jìn)而影
響 adjustedContentInset拳芙,所以導(dǎo)致scrollView下移20pt或者64pt。當(dāng)使用自定義的 navigationbar皮璧,并且scrollView的frame超出安全區(qū)域舟扎,SafeAreaInsets為(20,0,0,0);當(dāng)使用系統(tǒng)的navigationbar,SafeAreaInsets為(64,0,0,0)恶导。

解決方案:

在UIScrollView或者UITableView初始化的地方浆竭,加入如下代碼即可。

針對(duì)LumberjackConsole這個(gè)開源庫惨寿,我們可以在PTEConsoleTableView.m文件中的commonInit最后加入如下代碼即可邦泄。

if([self respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]){
      [self setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];
}

三、UI適配

3.1 NavBar中右上角的customView產(chǎn)生偏移

出錯(cuò)樣式 正確樣式
適配前
適配后

問題原因:

在iOS11中裂垦,新的導(dǎo)航視圖顺囊,使用了AutoLayout布局。而我們這邊右上角的兩個(gè)按鈕組合成一個(gè)customView蕉拢,然后把這個(gè)customView設(shè)置給setRightBarButtonItems而來特碳。customView內(nèi)部都是frame布局,所以在自動(dòng)布局下面出錯(cuò)晕换。

解決方案:

NavBar中的customView里面針對(duì)iOS11午乓,均要采用自動(dòng)布局。

3.2 NavBar中自定義TitleView產(chǎn)生偏移

出錯(cuò)樣式 正確樣式
適配前
適配后

問題原因:

同上

解決方案:

同上

這里需要注意一點(diǎn)闸准,自動(dòng)布局的UI是延遲設(shè)置frame的益愈。如果aView采用自動(dòng)布局。然后你馬上調(diào)用它的aView.bounds是不正確的夷家。

3.3 NavBar中按鈕的響應(yīng)區(qū)域都變小了蒸其。

iOS11 之前 iOS11
iOS11 之前
iOS11

問題原因:

iOS11之前,雖然我們?cè)O(shè)置了NavBar上每一個(gè)[btn sizeToFit]库快。蘋果依然會(huì)幫我們把每一個(gè)按鈕的點(diǎn)擊區(qū)域擴(kuò)大摸袁,可以點(diǎn)擊區(qū)域如上圖綠色區(qū)域所示。但是在iOS11中义屏,你的按鈕的bounds為多大靠汁,那你的點(diǎn)擊區(qū)域就只有多大。估計(jì)這個(gè)改動(dòng)也與這次NavBar的大概有關(guān)系闽铐。

解決方案:

擴(kuò)大每一個(gè)btn的bounds膀曾,而不要使用sizeToFit方法。

3.4 NavBar的BarButtonItem無法貼邊阳啥。有(非plus手機(jī)16pt,plus手機(jī)20pt)的區(qū)域浪費(fèi)财喳。造成UI偏移察迟,并且最左側(cè)和最右側(cè)區(qū)域無法點(diǎn)擊斩狱。

修改前 修改后
修改前
修改后

問題原因:

這個(gè)UINavigationBarContentView平鋪在導(dǎo)航欄中作為iOS11的各個(gè)按鈕的父視圖,該視圖的所有的子視圖都會(huì)有一個(gè)layoutMargins被占用,也就是系統(tǒng)調(diào)整的占位。

解決方案:

去掉系統(tǒng)默認(rèn)占位扎瓶。

系統(tǒng)并沒有提供我們直接去掉系統(tǒng)默認(rèn)占位的方法所踊,那怎么做呢?

我們新建一個(gè)UINavigationBar的分類概荷,hook住UINavigationBar的layoutSubviews方法秕岛。然后遍歷View,重新設(shè)置layoutMargin約束误证。

重新設(shè)置layoutMargin約束

3.5 UITableView 默認(rèn)開啟Self-Sizing继薛,導(dǎo)致UI顯示有問題。

修改前 修改后
修改前
修改后

問題原因:

在iOS11中UITableView會(huì)默認(rèn)使 Self-Sizing,這會(huì)導(dǎo)致tableView
的 estimatedRowHeight 愈捅、 estimatedSectionHeaderHeight 遏考、 estimatedSectionFooterHeight 的高度估算屬性由默認(rèn)的0變成 UITableViewAutomaticDimension ,reloadData時(shí)可能會(huì)導(dǎo)致最后顯示的contentSize與預(yù)想的不一致;

同時(shí)在iOS11中如果不實(shí)現(xiàn) -tableView: viewForHeaderInSection: 和 tableView: viewForFooterInSection: 方法,則 -tableView: heightForHeaderInSection: 和 - tableView: heightForFooterInSection: 不會(huì)被調(diào)用蓝谨,而iOS11之前則沒問題灌具。上述都可能會(huì)導(dǎo)致界面出現(xiàn)錯(cuò)亂。

解決方案:

單獨(dú)關(guān)閉摸一個(gè)UITableView的Self-Sizing譬巫。

    _tableView.estimatedRowHeight = 0.;
    _tableView.estimatedSectionFooterHeight = 0.;
    _tableView.estimatedSectionHeaderHeight = 0.;

關(guān)閉所有的UIScroolView咖楣、UITableView和UICollectionView的Self-Sizing:

   UIScrollView.appearance.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
   UITableView.appearance.estimatedRowHeight = 0;
   UITableView.appearance.estimatedSectionFooterHeight = 0;
   UITableView.appearance.estimatedSectionHeaderHeight = 0;

3.6 keyWindow獲取錯(cuò)誤, 導(dǎo)致UI問題。

錯(cuò)誤 正確
錯(cuò)誤
正確

問題原因:

機(jī)器貓圖標(biāo)是一個(gè)UIWindow芦昔,windowLevel級(jí)別比UIWindowLevelStatusBar還高诱贿,所以可以常駐UI最上方。第一次進(jìn)入該頁面烟零,點(diǎn)擊“更多”瘪松,彈出popView,點(diǎn)擊收藏锨阿,彈出系統(tǒng)UIAlertView宵睦,此時(shí)UIAlertView變成了keyWindow。當(dāng)UIAlertView消失的時(shí)候墅诡,keyWindow會(huì)被誰接管呢壳嚎?

iOS11之前,彈出UIAlertView之前的keyWindow是[[UIApplication sharedApplication].delegate window]末早,那么消失的時(shí)候烟馅,keyWindow還是[[UIApplication sharedApplication].delegate window]。

iOS11, 彈出UIAlertView之前的keyWindow是[[UIApplication sharedApplication].delegate window]然磷,那么消失的時(shí)候郑趁,keyWindow變成z軸最高的UIWindow,即變成了機(jī)器貓那個(gè)window姿搜。所以導(dǎo)致popView被添加到機(jī)器貓window中寡润,造成UI樣式問題捆憎。

解決方案:

重寫自定義UIWindow的becomeKeyWindow的方法,每次自定義window將會(huì)變?yōu)閗eyWindow的時(shí)候梭纹,把keyWindow改成[[UIApplication sharedApplication].delegate window]躲惰。

- (void)becomeKeyWindow{
    UIWindow *appWindow = [[UIApplication sharedApplication].delegate window];
    [appWindow makeKeyWindow];
}

3.7 狀態(tài)欄高度寫死為20pt,導(dǎo)致在iPhoneX上面遮擋住statusBar变抽。

錯(cuò)誤 正確
錯(cuò)誤
正確

問題原因:

iPhoneX上的statusBar的高度為44pt础拨,跟其他iPhone型號(hào)的20pt不一樣。所以以后我們?cè)谝詓tatusBar為定位點(diǎn)的時(shí)候绍载,不能寫死20pt诡宗。而要使用[UIApplication sharedApplication].statusBarFrame.size.height來獲取,為了方便逛钻,可以定義為宏僚焦,放到pch文件中,如下:

#define kApplicationStatusBarHeight  [UIApplication sharedApplication].statusBarFrame.size.height //狀態(tài)欄的高度

解決方案:

狀態(tài)欄高度定位的時(shí)候不要寫死20曙痘,要使用[UIApplication sharedApplication].statusBarFrame.size.height來獲取芳悲。

補(bǔ)充

iOS11之前導(dǎo)航欄默認(rèn)高度為64pt(這里高度指statusBar + NavigationBar),iOS11之后如果設(shè)置 prefersLargeTitles = YES則為96pt边坤,默認(rèn)情況下還是64pt名扛,但在iPhoneX上由于劉海的出現(xiàn) statusBar由以前的20pt變成 44pt,所以iPhoneX上高度變?yōu)?8pt茧痒,如果項(xiàng)目里隱藏了導(dǎo)航欄加了自定義按鈕之類的肮韧,這里需要注意適配一下。

3.8 通過遍歷statusBar的subviews中的UIStatusBarDataNetworkItemView獲取網(wǎng)絡(luò)狀態(tài)在iPhoneX上會(huì)crash旺订。

問題原因:

之前我們采用遍歷statusBar弄企,獲取UIStatusBarDataNetworkItemView實(shí)例,再獲取網(wǎng)絡(luò)狀態(tài)的区拳。代碼如下:

+ (NSNumber *) dataNetworkTypeFromStatusBar {
    UIApplication *app = [UIApplication sharedApplication];
    NSArray *subviews = [[[app valueForKey:@"statusBar"] valueForKey:@"foregroundView"] subviews];
    NSNumber *dataNetworkItemView = nil;
    
    @try {
        if ([subviews count] > 0) {
            for (id subview in subviews) {
                if([subview isKindOfClass:[NSClassFromString(@"UIStatusBarDataNetworkItemView") class]]) {
                    dataNetworkItemView = subview;
                    break;
                }
            }
        }
    }
    @catch (NSException *exception) {
    }
    @finally {
    }
    
    return [dataNetworkItemView valueForKey:@"dataNetworkType"];
}

但是在iphoneX的statusBar的內(nèi)部結(jié)構(gòu)已經(jīng)改變拘领,不能根據(jù)遍歷獲取UIStatusBarDataNetworkItemView的狀態(tài)獲取網(wǎng)絡(luò)狀態(tài)狀態(tài)。

可以通過po [statusBar recursiveDescription]打印出來iphoneX內(nèi)部結(jié)構(gòu)了樱调,可以看出變化非常的大约素。

解決方案:

使用AFNetworking中的AFNetworkReachabilityManager類,或者使用Reachability庫獲取網(wǎng)絡(luò)連接狀態(tài)笆凌。

四圣猎、權(quán)限適配

4.1 無法獲取定位信息,第一次打開app也無法彈出定位權(quán)限提示框

問題原因:

iOS11 定位相關(guān)的權(quán)限做了更改乞而,在iOS11上使用了新的定位權(quán)限key送悔。

解決方案:

如果原來申請(qǐng)的權(quán)限是始終允許NSLocationAlwaysUsageDescription,那么需要在保留原來的key的基礎(chǔ)上增加NSLocationWhenInUseUsageDescription和NSLocationAlwaysAndWhenInUsageDescription爪模。

五放祟、其他一些補(bǔ)充

5.1 如何判斷該設(shè)備是不是iPhoneX

5.2 一些常用的宏定義

#define IS_IPHONE_X [KDDeviceHelper is_iPhone_X]
#define IPHONE_NAVIGATIONBAR_HEIGHT  (IS_IPHONE_X ? 88 : 64)
#define IPHONE_STATUSBAR_HEIGHT      (IS_IPHONE_X ? 44 : 20)
#define IPHONE_SAFEBOTTOMAREA_HEIGHT (IS_IPHONE_X ? 34 : 0)
#define IPHONE_TOPSENSOR_HEIGHT      (IS_IPHONE_X ? 32 : 0)

六鳍怨、參考文獻(xiàn)

iOS11&iPhone X適配.pdf
你可能需要為你的 APP 適配 iOS 11
升級(jí)到XCode9(BaseSDK:iOS11)的各種坑 持續(xù)更新中
一個(gè)iOS 11BUG的發(fā)現(xiàn)、定位和解決
如何判斷設(shè)備是否為iPhone X跪妥,iOS獲取設(shè)備型號(hào)的方法

七、聯(lián)系方式

新浪微博
github
簡書首頁

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末声滥,一起剝皮案震驚了整個(gè)濱河市眉撵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌落塑,老刑警劉巖纽疟,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異憾赁,居然都是意外死亡污朽,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門龙考,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蟆肆,“玉大人,你說我怎么就攤上這事晦款⊙坠Γ” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵缓溅,是天一觀的道長蛇损。 經(jīng)常有香客問我,道長坛怪,這世上最難降的妖魔是什么淤齐? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮袜匿,結(jié)果婚禮上更啄,老公的妹妹穿的比我還像新娘。我一直安慰自己沉帮,他們只是感情好锈死,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著穆壕,像睡著了一般待牵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上喇勋,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天缨该,我揣著相機(jī)與錄音,去河邊找鬼川背。 笑死贰拿,一個(gè)胖子當(dāng)著我的面吹牛蛤袒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播膨更,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼妙真,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了荚守?” 一聲冷哼從身側(cè)響起珍德,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎矗漾,沒想到半個(gè)月后锈候,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡敞贡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年泵琳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片誊役。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡获列,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出势木,到底是詐尸還是另有隱情蛛倦,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布啦桌,位于F島的核電站溯壶,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏甫男。R本人自食惡果不足惜且改,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望板驳。 院中可真熱鬧又跛,春花似錦、人聲如沸若治。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽端幼。三九已至礼烈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間婆跑,已是汗流浹背此熬。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人犀忱。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓募谎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親阴汇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子数冬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容