iOS11, Xcode9 and iphone X適配

weixin_33724059發表於2017-12-11

前言

最近公司的很多流量產品需要適配iOS 11 和iPhone X,由於公司的iPhone X到的比較晚,拖了好久才對這些流量產品進行更新。

問題

  1. 首先一個很明顯的適配問題,就是開啟app的時候沒有全屏,這時候要加入一張對應尺寸的啟動圖片就可以。
  • 豎屏尺寸:1125px × 2436px(375pt × 812pt @3x)
  • 橫屏尺寸:2436px × 1125px(812pt × 375pt @3x)
  1. 跟啟動屏有關的當然還有一個問題,那就是獲取螢幕的大小:[[UIScreen mainScreen] bounds].size 加入上面的圖片就可以了

導航欄

  1. navigationItem.titleView = 自定義view, 這時候這個自定義的view的大小就會出現問題,而且有點選時間也不會觸發。首先,在自定義titleview 裡重寫 intrinsicContentSize 屬性,程式碼如下

    @property(nonatomic, assign) CGSize intrinsicContentSize;
    

然後在 self.navigationItem.titleView = _titleView; 之前加入下面的程式碼:

_titleView.intrinsicContentSize = CGSizeMake(200, 40);

自定義的view還是要設定frame,不然不是iOS11還是可能出問題。

  1. 導航欄高度的變化

iOS11之前導航欄預設高度為64pt(這裡高度指statusBar + NavigationBar),iOS11之後如果設定了prefersLargeTitles = YES則為96pt,預設情況下還是64pt,但在iPhoneX上由於劉海的出現statusBar由以前的20pt變成了44pt,所以iPhoneX上高度變為88pt,由於劉海多出了24pt的高度,如果專案裡隱藏了導航欄加了自定義按鈕之類的,這裡需要注意適配一下。

1045631-fd1cf9117b3eaf75.png
968977-89a88f618da51832.png

1045631-2a6d39f7a2fefb8e.png
968977-b19a09df0a51bf50.png

viewSafeAreaInsetsDidChange方法裡面列印NSLog(@"%@",NSStringFromUIEdgeInsets(self.view.safeAreaInsets));即可知道安全區域的邊界

  1. 在iOS7之後,我們在設定UINavigationItemleftBarButtonItem,rightBarButtonItem的時候都會造成位置的偏移,我們經常習慣使用下面這個方法來調整下間距

    +(UIBarButtonItem *)fixedSpaceWithWidth:(CGFloat)width {`
     UIBarButtonItem *fixedSpace = [[UIBarButtonItem         alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
     fixedSpace.width = width;
     return fixedSpace;
     }
    

但是在iOS11沒有效果了,可以通過過改變按鈕的 contentEdgeInsetsimageEdgeInsets的值成功改變了按鈕的偏移問題,單獨設定contentEdgeInsets也可達到一定的效果

底部tarbar

  1. iPhone x:Tabbar從49pt變為83pt,如果是自己定義的tabbar需要自己加上34的高度,否則會點不到對應tabbar。如果是隱藏的tabbar的話,比如底部放了一個banner廣告的話,這時候也需要調整對應的高度,在xcode中調整了下如果隱藏tabbar,還要在底部放廣告的話可以距離底部24pt,蘋果tabbar多加了34,比點選距離多加了10pt,應該是讓使用者體驗更加的好點,不然24的話感覺快點到底部觸控欄的樣子。

UITableView and UICollectionView

  1. 在iOS 11上執行tableView向下偏移64px或者20px,因為iOS 11廢棄了automaticallyAdjustsScrollViewInsets,而是給UIScrollView增加了contentInsetAdjustmentBehavior屬性。避免這個坑的方法是要判斷

       if (@available(iOS 11.0, *)) {
         _tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
       }else {
         self.automaticallyAdjustsScrollViewInsets = NO;
       }
    
  2. IOS11以後,Self-Sizing預設開啟,包括Headers, footers。如果專案中沒使用estimatedRowHeight屬性,在IOS11下會有奇奇怪怪的現象,預設如果不去實現viewForHeaderInSection就不會呼叫heightForHeaderInSection,尾部試圖一樣,因為IOS11之前,estimatedRowHeight預設為0,Self-Sizing自動開啟後,contentSizecontentOffset都可能發生改變。可以通過以下方式禁用:

     self.tableView.estimatedRowHeight = 0; 
     self.tableView.estimatedSectionHeaderHeight = 0; 
     self.tableView.estimatedSectionFooterHeight = 0;
    
  3. 列表/頁面偏移,設定工程中的UITableView、UICollectionView、UIScrollView的contentInsetAdjustmentBehavior屬性,如下:

       if (@available(iOS 11.0, *)){
         _tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
      }
    

總的來說所有繼承與Scrollview 及其子類都需要設定 contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever ,每個設定很麻煩,沒關係。由於UIView及其子類都遵循UIAppearance協議,我們可以進行全域性配置:

// AppDelegate 進行全域性設定
if (@available(iOS 11.0, *)){
    [[UIScrollView appearance]     setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];
}
  1. 當你在tableView 裡面巢狀collectionView 的時候有可能出現一下錯誤:

     Assertion failure in -[UICollectionViewData validateLayoutInRect:],              /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3694.4.18/UICollectionViewData.m:435
     2017-11-15 15:59:08.616969+0800 tbEmojiGuangchang[70423:3415148] invalid mode 'kCFRunLoopCommonModes' provided to CFRunLoopRunSpecific - break on _CFRunLoopError_RunCalledWithInvalidMode to debug. This message will only appear once per execution.
    

    libc++abi.dylib: terminate_handler unexpectedly threw an exception

只要在重新整理collectionView之前呼叫[collectionView.collectionViewLayout invalidateLayout] 就行。

  -(NSInteger) numberOfSectionsInCollectionView:(UICollectionView *)collectionView{
      [collectionView.collectionViewLayout invalidateLayout];
      return 1;
  }
  1. 相簿許可權
    iOS11之後:預設開啟訪問相簿許可權(讀許可權),無需使用者授權,無需新增NSPhotoLibraryUsageDescription,適配iOS11之前的還是需要加的。 新增圖片到相簿(寫許可權),需要使用者授權,需要新增 NSPhotoLibraryAddUsageDescription,相簿的許可權狀態有以下四種狀態:

     PHAuthorizationStatusNotDetermined = 0, // User has not yet made a choice with regards to this application
     PHAuthorizationStatusRestricted,        // This application is not authorized to access photo data.
                                        // The user cannot change this application’s status, possibly due to active restrictions
                                        //   such as parental controls being in place.
    PHAuthorizationStatusDenied,            // User has explicitly denied this application access to photos data.
    PHAuthorizationStatusAuthorized         // User has authorized this application to access photos data.
    

iOS11之前如果還沒請求訪問相簿許可權的話狀態是:PHAuthorizationStatusNotDetermined ,使用者如果點選不允許訪問相簿的話狀態是:PHAuthorizationStatusDenied ,但是在iOS11就很奇葩,還沒請求訪問相簿許可權和使用者如果點選不允許訪問相簿的狀態都是PHAuthorizationStatusNotDetermined,導致不能判斷是否是使用者點選不允許的操作,也就沒辦法彈出那個引導使用者去設定開啟相簿許可權的視窗。我這邊的做法是如果應用是有需要新增相片到相簿的,要提前請求相簿功能:

oc 程式碼:

[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
    
}];

swift 程式碼:

if #available(iOS 11.0, *) {
        let library: PHAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
        if(library == PHAuthorizationStatus.notDetermined){
            PHPhotoLibrary.requestAuthorization { (status) in
            }
        }
 }
  1. 位置許可權

在IOS11,原有的NSLocationAlwaysUsageDeion被降級為NSLocationWhenInUseUsageDeion。因此,在原來專案中使用requestAlwaysAuthorization獲取定位許可權,而未在plist檔案中配置NSLocationAlwaysAndWhenInUseUsageDeion,系統框不會彈出。建議新舊key值都在plist裡配置,反正我試下來是沒有問題,唯一的區別是使用requestAlwaysAuthorization獲取許可權 IOS11系統彈框會把幾種許可權級別全部列出,供使用者選擇,顯然更人性化了。快去更新你的info.plist

 <!-- 位置 -->
<key>NSLocationUsageDescription</key>
<string>獲取地理位置,精準推送服務</string>
<!-- 在使用期間訪問位置 -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>獲取地理位置,精準推送服務</string>
<!-- 始終訪問位置 -->
<key>NSLocationAlwaysUsageDescription</key>
<string>App需要您的同意,才能始終訪問位置</string>
<!-- iOS 11訪問位置 -->
<key>NSLocationAlwaysAndWhenInUseUsageDeion</key>
<string>App需要您的同意,才能始終訪問位置</string>
  1. 使用第三方網路監測庫報錯


    1045631-269cb7f130a379ed.png
    325120-0850ff880b326807.png

解決方式如下:替換成如下程式碼:

__Check_Compile_Time(sizeof(ICMPHeader) == 8);
__Check_Compile_Time(offsetof(ICMPHeader, type) == 0);
__Check_Compile_Time(offsetof(ICMPHeader, code) == 1);
__Check_Compile_Time(offsetof(ICMPHeader, checksum) == 2);
__Check_Compile_Time(offsetof(ICMPHeader, identifier) == 4);
__Check_Compile_Time(offsetof(ICMPHeader, sequenceNumber) == 6)

後續更新...

  1. 跳轉appStore評論的連結更換了,很正常,因為iOS11之後appStore就大改版了,當然跳到裡面的連結應該也是會有所變化的,之前iOS11的連結是這樣的:

    http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=XXXXXXXX&pageNumber=0&sortOrdering=2&type=Purple+Software&mt=8"
    

iOS11之後需要改稱以下這樣,當然iOS11之前這個連結也是適用的:

itms-apps://itunes.apple.com/cn/app/idXXXXXX?mt=8&action=write-review
  1. UIToolBar 的坑,當你使用view整合UIToolBar的時候,這個時候使用xcode9執行的時候會發現一個非常坑的問題,就是在view的最頂層會多出一層UIToolBarContenVIew出來,到時你的整個view沒辦法點選,建議不要用UIToolbar來繼承。


    1045631-77ab66aa1b7e6aec.png
    CA99B4BE-B322-453E-951E-A0B5B32E4530.png

總結

以上是我在適配我的一些產品的時候碰到的一些問題,當然還有一些其他很小的細節有問題,只需要稍微調整就行,在這裡就不提了,蘋果每次更新一個大版本的時候都會出現各種各樣的問題,很多東西也變得越來越複雜,後面有在專案中碰到問題會在繼續更新~

相關文章