iOS9、iOS10、iOS11、iOS12常见适配

一、iOS12(Xcode10)

1.1、升级Xcode10后项目报错

不允许多个info.plist

Xcode10是默认选中的最新的New Build System(Default),在这个编译系统的环境下,不允许多个info.plist

解决办法一:(推荐)

把build system切换到 Legacy Build System,换言之就是切换成老的编译系统,就OK了。

Xcode->File->Project Settings-> Build System -> Legacy Build System.

image.png
image.png

解决办法二:

删除其他info.plist文件。

iOS 12移除了libstdc++, 用libc++替代

Xcode10中libstdc++相关的3个库(libstdc++、libstdc++.6、libstdc++6.0.9)应该都是被彻底废弃了,如果你使用的三方库中有依赖,请尽快和提供方沟通,告知他们迁移吧。如果自己开发使用,也尽快考虑迁移的事宜吧。

1.2、iPhone XR不支持3D-Touch

OC检测代码

if (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable) {

}

swift检测代码

self.traitCollection.forceTouchCapability == .availible

二、iOS11(Xcode9)

2.1、安全区域(SafeArea)

iOS11为UIViewController和UIView增加了两个新的属性safeAreaInsets和safeAreaLayoutGuide

safeAreaInsets 适用于手动计算.

safeAreaLayoutGuide 适用于自动布局.

UIViewController中新增:

- (``void``)viewSafeAreaInsetsDidChange;

UIView中新增:

- (``void``)viewSafeAreaInsetsDidChange;

在Storyboard使用Safe Area最低只支持iOS9,iOS8的用户就要放弃了

image.png
image.png

当UIViewController调用- (void)viewDidLoad时它的所有子视图的safeAreaInsets属性都等于UIEdgeInsetsZero。

viewSafeAreaInsetsDidChange的调用时机如下:

1、viewDidLoad

2、viewWillAppear

3、viewSafeAreaInsetsDidChange

4、viewWillLayoutSubviews

5、viewDidAppear

只有在调用viewSafeAreaInsetsDidChange后,才能获得view以及viewController的SafeArea(UIEdgeInsets)。因此在viewDidload中根据SafeArea设置界面会有问题。

iPhone X:有导航栏的时候可以+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

2.2、UIScrollView

iOS 11废弃了UIViewController的automaticallyAdjustsScrollViewInsets属性,新增了contentInsetAdjustmentBehavior属性,所以当超出安全区域时系统自动调整了SafeAreaInsets,进而影响了adjustedContentInset,在iOS11中决定tableView内容与边缘距离的是adjustedContentInset,所以需要设置UIScrollView的contentInsetAdjustmentBehavior属性。

// 方式一:(不推荐)修改额外的安全区域

if (@available(iOS ``11.0``, *)) {

self.additionalSafeAreaInsets = UIEdgeInsetsMake(-``44``, ``0``, ``0``, ``0``);

}

else {

// Fallback on earlier versions

}

// 方式二:(推荐)设置为不自动调整

if (@available(iOS ``11.0``, *)) {

// 作用于指定的UIScrollView

self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;

// 作用与所有的UIScrollView

UIScrollView.appearance.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;

}

else {

self.automaticallyAdjustsScrollViewInsets = NO;

}

2.3、tableview问题

iOS11开始UITableView开启了自动估算行高,estimatedRowHeight estimatedSectionHeaderHeight estimatedSectionFooterHeight三个高度估算属性由默认的0变成了UITableViewAutomaticDimension,如果不实现-tableView: viewForFooterInSection: 和 -tableView: viewForHeaderInSection:,那么estimatedRowHeight estimatedSectionHeaderHeight estimatedSectionFooterHeight三个高度估算属性由默认的0变成了UITableViewAutomaticDimension,导致高度计算不对,会产生空白。解决方法是实现对应方法或吧这三个属性设为0。

2.4、LocalAuthentication 本地认证

本地认证框架提供了从具有指定安全策略(密码或生物学特征)的用户请求身份验证的功能。例如,要求用户仅使用Face ID或Touch ID进行身份验证,可使用以下代码:

#``import /**

检测TouchID是否可用

*/

- (``void``)checkBiometrics {

LAContext *context = [[LAContext alloc] init];

BOOL success = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics

error:nil];

if ( success ) {

NSLog(@"can use"`);

}

else {

NSLog(@"cant use ");

}

}

/**

在验证TouchID可用的情况下使用

*/

- (``void``)excuteBiometrics {

LAContext *context = [[LAContext alloc] init];

context.localizedFallbackTitle = @"自定义标题"`;

[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics

localizedReason:@"为什么使用TouchID写这里"

reply:^(BOOL success, NSError * _Nullable error) {

if ( success ) {

// 指纹验证成功

}

else {

switch (error.code) {

case LAErrorUserFallback:{

NSLog(@"用户选择输入密码"`);

break;

}

case LAErrorAuthenticationFailed:{

NSLog(@"验证失败"`);

break;

}

case LAErrorUserCancel:{

NSLog(@"用户取消"`);

break;

}

case LAErrorSystemCancel:{

NSLog(@``"系统取消"``);

break;

}

// 以下三种情况如果提前检测TouchID是否可用就不会出现

case LAErrorPasscodeNotSet:{

break;

}

case LAErrorTouchIDNotAvailable:{

break;

}

case LAErrorTouchIDNotEnrolled:{

break;

}

default:

break;

}

}

}];

}

2.5、启动图的适配

方法一:通过LaunchScreen.storyboard方式启动

方法二:使用Assets中的LaunchImage

image.png

  • 给Brand Assets添加一张1125*2436大小的图片

  • 打开Assets.xcassets文件夹,找到Brand Assets

  • 右键Show in Finder

  • 添加一张1125*2436大小的图片

  • 修改Contents.json文件,添加如下内容

{

"extent" : ``"full-screen"``,

"idiom" : ``"iphone"``,

"subtype" : ``"2436h"``,

"filename" : ``"1125_2436.png"``,

"minimum-system-version" : ``"11.0"``,

"orientation" : ``"portrait"``,

"scale" : ``"3x"

}

|

2.6、定位相关

在 iOS 11 中必须支持 When In Use 授权模式(NSLocationWhenInUseUsageDescription),在 iOS 11 中,为了避免开发者只提供请求 Always 授权模式这种情况,加入此限制,如果不提供When In Use 授权模式,那么 Always 相关授权模式也无法正常使用。

如果要支持老版本,即 iOS 11 以下系统版本,那么建议在 info.plist 中配置所有的 Key(即使

|

1

2

3

4

5

|

NSLocationAlwaysUsageDescription 在 iOS ``11``及以上版本不再使用):

NSLocationWhenInUseUsageDescription

NSLocationAlwaysAndWhenInUseUsageDescription

NSLocationAlwaysUsageDescription

NSLocationAlwaysAndWhenInUseUsageDescription ``// 为 iOS 11 中新引入的一个 Key。

|

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

三、iOS10(Xcode8)

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

Xcode8取消了三方插件(很多优秀的插件,本来可以显著提高效率)的功能,使用Extension代替

Xcode 8 Extension 推荐

3.2、证书问题

为了方便用户来管理,提供Automatically manage signing。需要输入开发者账号!如果没有账号也没关系,在下面也可以选择Debug、Realease、inHouse模式下对应的证书也可以!

3.3、隐私数据访问问题

iOS10,苹果加强了对隐私数据的保护,要对隐私数据权限做一个适配,iOS10调用相机,访问通讯录,访问相册等都要在info.plist中加入权限访问描述,不然之前你们的项目涉及到这些权限的地方就会直接crash掉。

解决办法:

只需要在info.plist添加NSContactsUsageDescription的key, value自己随意填写就可以,这里列举出对应的key(Source Code模式下):

NSPhotoLibraryUsageDescriptionApp需要您的同意,才能访问相册NSCameraUsageDescriptionApp需要您的同意,才能访问相机NSMicrophoneUsageDescriptionApp需要您的同意,才能访问麦克风NSLocationUsageDescriptionApp需要您的同意,才能访问位置NSLocationWhenInUseUsageDescriptionApp需要您的同意,才能在使用期间访问位置NSLocationAlwaysUsageDescriptionApp需要您的同意,才能始终访问位置NSCalendarsUsageDescriptionApp需要您的同意,才能访问日历NSRemindersUsageDescriptionApp需要您的同意,才能访问提醒事项NSMotionUsageDescriptionApp需要您的同意,才能访问运动与健身NSHealthUpdateUsageDescriptionApp需要您的同意,才能访问健康更新 NSHealthShareUsageDescriptionApp需要您的同意,才能访问健康分享NSBluetoothPeripheralUsageDescriptionApp需要您的同意,才能访问蓝牙NSAppleMusicUsageDescriptionApp需要您的同意,才能访问媒体资料库

|

image.png

3.4、跳转到app内的隐私数据设置页面

iOS 10 干掉了所有系统设置的 URL Scheme,这意味着你再也不可能直接跳转到系统设置页面(比如 WiFi、蜂窝数据、定位等)。

跳转方式

方式一:prefs:root=某项服务 适用于 小于 iOS10的系统;

NSURL *url = [NSURL URLWithString:@"prefs:root=WIFI"];

方式二:prefs:root=bundleID 适用于 大于等于iOS8系统,小于iOS10的系统

NSURL *url = [NSURL URLWithString:@"prefs:root=bundleID"];

方式三:UIApplicationOpenSettingsURLString 适用于 大于等于iOS8的系统

NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];

// iOS系统版本 >= 10.0

{

NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];

if ([[UIApplication sharedApplication] canOpenURL:url]) {

[[UIApplication sharedApplication] openURL:url];

}

}

return``;

// iOS系统版本 >= 10.0

// But! 不建议这样做哦,官方文档中说过:

//URL is now considered a private API and use will result in app rejection.

// 虽然是有可能躲过苹果的检测,但是苹果如果发现你这样用了,app上架是有被拒的风险的.

{

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系统版本 < 10.0

{

NSURL *url = [NSURL URLWithString:@``"prefs:root=WIFI"``];

if ([[UIApplication sharedApplication] canOpenURL:url]) {

[[UIApplication sharedApplication] openURL:url];

}

}

跳转目的地

iOS系统版本 <= iOS7 , 只能跳转到 系统设置页面

iOS系统版本 >= iOS8 ,支持跳转到第三方应用的设置界面中。使用prefs:root=bundleID ,bundleID是你第三方应用工程的唯一ID

iOS系统版本 >= iOS10,支持跳转到自己应用设置,不支持跳转到系统设置

3.5、字体变化

苹果的默认字体会随着iOS系统版本的不同而不同,iOS10中字体变大了。导致了原来的显示有问题,会造成...的出现。暂时没有好的解决办法,需要自己在一个个适配一下!

3.6、UICollectionViewCell的的优化

在iOS 10 之前,cell只能从重用队列里面取出,再走一遍生命周期,并调用cellForItemAtIndexPath创建或者生成一个cell.

在iOS 10 中,系统会cell保存一段时间,也就是说当用户把cell滑出屏幕以后,如果又滑动回来,cell不用再走一遍生命周期了,只需要调用willDisplayCell方法就可以重新出现在屏幕中了.

iOS 10 中,系统是一个一个加载cell的,二以前是一行一行加载的,这样就可以提升很多性能;

iOS 10 新增加的Pre-Fetching预加载

3.7、UIRefreshControl

在iOS 10 中, UIRefreshControl可以直接在UICollectionView和UITableView中使用,并且脱离了UITableViewController.现在RefreshControl是UIScrollView的一个属性.

3.8、UserNotifications(用户通知)

iOS 10所有相关通知被统一到了UserNotifications.framework框架中。增加了撤销、更新、中途还可以修改通知的内容。通知不在是简单的文本了,可以加入视频、图片,自定义通知的展示等等。

iOS 10相对之前的通知来说更加好用易于管理,并且进行了大规模优化,对于开发者来说是一件好事。

iOS 10开始对于权限问题进行了优化,申请权限就比较简单了(本地与远程通知集成在一个方法中)。

四、iOS9(Xcode7)

4.1、Bitcode

Xcode7 默认启用 Bitcode,但是如果我们用到的第三方库编译时还没启用 Bitcode,主工程就会编译不过。Bitcode 是苹果 App Thinning 的机制之一,可以减少安装包的大小。App store 会将这个 Bitcode 编译为可执行的64位或32位程序。

解决办法一:

最简单的解决办法是先把 Bitcode 关掉:把 Build settings - Build Options - Enable Bitcode 改为 NO。
image.png

解决办法二:

移除不支持BitCode的平台SDK,或者寻找支持BitCode的替代品,或者联系SDK方支持BitCode。

4.2、HTTP 请求失败

iOS9 默认不支持 HTTP 请求,需要改用更安全的 HTTPS(默认用 TLS 1.2)。苹果还提供了配置,使得所有安全性更低的网络请求也能使用,解决方案就是在 info.plist 里面增加以下配置:

NSAppTransportSecurity NSAllowsArbitraryLoads

如果复杂一些,还可以指定白名单域名,声明所支持 TLS 的最低版本。另外需要注意的是,即使写了上述配置,在 HTTPS 页面中,HTTP 的 javascript 或 css 不会被加载,因为苹果认为这降低了页面的安全性。

4.3、canOpenUrl 限制

canOpenUrl 可以用来判断用户是否安装了某个 APP。也许是出于用户隐私的考虑,iOS9 上对 canOpenUrl 做了限制,最多只能对 50 个 scheme 做判断。如果是用 Xcode7 编译,需要在 plist 里面声明这些 scheme,没有声明的会直接返回 NO:

LSApplicationQueriesSchemes weixin wechat

4.4、UIStatusBar的问题

iOS9中废弃的方法

// 修改状态栏的样式为白色

// 'setStatusBarStyle(_:animated:)' was deprecated in iOS 9.0: Use -[UIViewController preferredStatusBarStyle]

UIApplication.shared.setStatusBarStyle(.lightContent, animated: ``true``)

// 隐藏状态栏

// 'setStatusBarHidden(_:with:)' was deprecated in iOS 9.0: Use -[UIViewController prefersStatusBarHidden]

UIApplication.shared.setStatusBarHidden(``true``, ``with``: .fade)

复制代码用下面两个方法替换

-[UIViewController preferredStatusBarstyle]

-[UIViewController preferredStatusBarHidden]

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容