iOS12、iOS11、iOS10、iOS9常见适配

简介: iOS12、iOS11、iOS10、iOS9常见适配

iOS12、iOS11、iOS10、iOS9常见适配

@(IOS各个版本适配)

[TOC]

一、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

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

image.png

image

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

解决办法二:

删除其他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为UIViewControllerUIView增加了两个新的属性safeAreaInsetssafeAreaLayoutGuide

  • safeAreaInsets 适用于手动计算.
  • safeAreaLayoutGuide 适用于自动布局.
UIViewController中新增:
- (void)viewSafeAreaInsetsDidChange;
UIView中新增:
- (void)viewSafeAreaInsetsDidChange;
复制代码

Storyboard使用Safe Area最低只支持iOS9iOS8的用户就要放弃了

image.png

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

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

viewSafeAreaInsetsDidChange的调用时机如下:

  • 1、viewDidLoad
  • 2、viewWillAppear
  • 3、viewSafeAreaInsetsDidChange
  • 4、viewWillLayoutSubviews
  • 5、viewDidAppear

只有在调用viewSafeAreaInsetsDidChange后,才能获得view以及viewControllerSafeArea(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废弃了UIViewControllerautomaticallyAdjustsScrollViewInsets属性,新增了contentInsetAdjustmentBehavior属性,所以当超出安全区域时系统自动调整了SafeAreaInsets,进而影响了adjustedContentInset,在iOS11中决定tableView内容与边缘距离的是adjustedContentInset,所以需要设置UIScrollViewcontentInsetAdjustmentBehavior属性。

// 方式一:(不推荐)修改额外的安全区域
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``estimatedSectionHeaderHeightestimatedSectionFooterHeight三个高度估算属性由默认的0变成了UITableViewAutomaticDimension,如果不实现-tableView: viewForFooterInSection:-tableView: viewForHeaderInSection:,那么estimatedRowHeightestimatedSectionHeaderHeightestimatedSectionFooterHeight三个高度估算属性由默认的0变成了UITableViewAutomaticDimension,导致高度计算不对,会产生空白。解决方法是实现对应方法或吧这三个属性设为0。

2.4、LocalAuthentication 本地认证

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

#import <LocalAuthentication/LocalAuthentication.h>
/**
 检测TouchID是否可用
 */
- (void)checkBiometrics {
    LAContext *context = [[LAContext alloc] init];
    BOOL success = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
                                        error:nil];
    if ( success ) {
        NSLog(@"can use");
    }
    else {
        NSLog(@"can`t 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

<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

  • 给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(即使 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。需要输入开发者账号!如果没有账号也没关系,在下面也可以选择DebugRealeaseinHouse模式下对应的证书也可以!

3.3、隐私数据访问问题

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


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

<key>NSPhotoLibraryUsageDescription</key><string>App需要您的同意,才能访问相册</string>
<key>NSCameraUsageDescription</key><string>App需要您的同意,才能访问相机</string>
<key>NSMicrophoneUsageDescription</key><string>App需要您的同意,才能访问麦克风</string>
<key>NSLocationUsageDescription</key><string>App需要您的同意,才能访问位置</string>
<key>NSLocationWhenInUseUsageDescription</key><string>App需要您的同意,才能在使用期间访问位置</string>
<key>NSLocationAlwaysUsageDescription</key><string>App需要您的同意,才能始终访问位置</string>
<key>NSCalendarsUsageDescription</key><string>App需要您的同意,才能访问日历</string>
<key>NSRemindersUsageDescription</key><string>App需要您的同意,才能访问提醒事项</string>
<key>NSMotionUsageDescription</key><string>App需要您的同意,才能访问运动与健身</string>
<key>NSHealthUpdateUsageDescription</key><string>App需要您的同意,才能访问健康更新 </string>
<key>NSHealthShareUsageDescription</key><string>App需要您的同意,才能访问健康分享</string>
<key>NSBluetoothPeripheralUsageDescription</key><string>App需要您的同意,才能访问蓝牙</string>
<key>NSAppleMusicUsageDescription</key><string>App需要您的同意,才能访问媒体资料库</string>
复制代码
隐私数据 对应key值
相册 NSPhotoLibraryUsageDescription
相机 NSCameraUsageDescription
麦克风 NSMicrophoneUsageDescription
位置 NSLocationUsageDescription
在使用期间访问位置 NSLocationWhenInUseUsageDescription
始终访问位置 NSLocationAlwaysUsageDescription
日历 NSCalendarsUsageDescription
提醒事项 NSRemindersUsageDescription
运动与健身 NSMotionUsageDescription
健康更新 NSHealthUpdateUsageDescription
健康分享 NSHealthShareUsageDescription
蓝牙 NSBluetoothPeripheralUsageDescription
媒体资料库 NSAppleMusicUsageDescription

显示详细信息

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的的优化

  • <input checked="" disabled="" type="checkbox" style="font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; overflow: visible; box-sizing: border-box; padding: 0px;"> 在iOS 10 之前,cell只能从重用队列里面取出,再走一遍生命周期,并调用cellForItemAtIndexPath创建或者生成一个cell.
  • <input checked="" disabled="" type="checkbox" style="font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; overflow: visible; box-sizing: border-box; padding: 0px;"> 在iOS 10 中,系统会cell保存一段时间,也就是说当用户把cell滑出屏幕以后,如果又滑动回来,cell不用再走一遍生命周期了,只需要调用willDisplayCell方法就可以重新出现在屏幕中了.
  • <input checked="" disabled="" type="checkbox" style="font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; overflow: visible; box-sizing: border-box; padding: 0px;"> iOS 10 中,系统是一个一个加载cell的,二以前是一行一行加载的,这样就可以提升很多性能;
  • <input checked="" disabled="" type="checkbox" style="font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; overflow: visible; box-sizing: border-box; padding: 0px;"> iOS 10 新增加的Pre-Fetching预加载

3.7、UIRefreshControl

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

3.8、UserNotifications(用户通知)

  • <input checked="" disabled="" type="checkbox" style="font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; overflow: visible; box-sizing: border-box; padding: 0px;"> iOS 10所有相关通知被统一到了UserNotifications.framework框架中。增加了撤销、更新、中途还可以修改通知的内容。通知不在是简单的文本了,可以加入视频、图片,自定义通知的展示等等。
  • <input checked="" disabled="" type="checkbox" style="font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; overflow: visible; box-sizing: border-box; padding: 0px;"> iOS 10相对之前的通知来说更加好用易于管理,并且进行了大规模优化,对于开发者来说是一件好事。
  • <input checked="" disabled="" type="checkbox" style="font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; overflow: visible; box-sizing: border-box; padding: 0px;"> 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<figcaption style="display: block; text-align: center; font-size: 1rem; line-height: 1.6; color: rgb(144, 144, 144); margin-top: 2px;"></figcaption>

解决办法二: 移除不支持BitCode的平台SDK,或者寻找支持BitCode的替代品,或者联系SDK方支持BitCode。

4.2、HTTP 请求失败

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

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>
复制代码

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

4.3、canOpenUrl 限制

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

<key>LSApplicationQueriesSchemes</key>
<array>
    <string>weixin</string>
    <string>wechat</string>
</array>
复制代码

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]
复制代码

参考资料:

iOS12适配

iOS12AdaptationTips

关于iPhone X 的适配

iOS11适配iPhoneX总结

iOS 10 适配知识点总结

聊聊iOS 10更新以后跳转系统设置的几种方式

iOS 10 调用系统"设置"里的功能(全)

iOS TouchID验证和Keychain结合使用

iOS10AdaptationTips

适配iOS9

微信 iOS 9 适配总结

iOS9AdaptationTips


相关文章
|
4月前
|
IDE API Android开发
安卓与iOS开发环境的差异及适配策略
在移动应用开发的广阔舞台上,Android和iOS两大操作系统各据一方,各自拥有独特的开发环境和工具集。本文旨在深入探讨这两个平台在开发环境上的关键差异,并提供有效的适配策略,帮助开发者优化跨平台开发流程。通过比较Android的Java/Kotlin和iOS的Swift/Objective-C语言特性、IDE的选择、以及API和系统服务的访问方式,本文揭示了两个操作系统在开发实践中的主要分歧点,并提出了一套实用的适配方法,以期为移动开发者提供指导和启示。
|
6月前
|
iOS开发
SwiftUI适配iOS16导航控制器引起的闪退
SwiftUI适配iOS16导航控制器引起的闪退
72 0
|
6月前
|
监控 iOS开发
iOS15适配问题:viewForSupplementaryElementOfKind表头和表尾复用闪退,UITableView section header多22像素等问题
iOS15适配问题:viewForSupplementaryElementOfKind表头和表尾复用闪退,UITableView section header多22像素等问题
96 0
|
小程序 开发工具 Android开发
Donut多端框架小程序打包适配ios和安卓app
腾讯新出了一个 Donut 多端框架,可以直接将微信小程序转成 ios 和 安卓 app,小程序开发者工具里也集成了 app 相关升级、调试和打包的功能,终于可以一套代码开发出3个客户端了!
258 0
Donut多端框架小程序打包适配ios和安卓app
|
小程序 iOS开发
uniapp中IOS端小程序底部黑线适配的方法(整理)
uniapp中IOS端小程序底部黑线适配的方法(整理)
|
开发工具 iOS开发 开发者
iOS 暗黑模式的适配总结
iOS 暗黑模式的适配总结
|
安全 iOS开发
iOS小技能:下拉刷新控件的适配
1. 下拉顶部背景色设置: 往tableView的父控件添加拉伸背景视图 2. present 半屏适配 iOS13 modalPresentationStyle属性默认不是全屏样式`UIModalPresentationFullScreen`,而是半屏样式,需要根据需求手动设置。 present 半屏,会导致列表下拉刷新失效。
209 0
iOS小技能:下拉刷新控件的适配
|
Web App开发 移动开发 前端开发
HTML5 移动端页面适配 iOS 系统刘海屏
HTML5 移动端页面适配 iOS 系统刘海屏
1261 0
HTML5 移动端页面适配 iOS 系统刘海屏
iOS11 适配相关
刷新之后首页顶上去的问题怎么处理
41 0
|
iOS开发 Perl
iOS 屏幕比例适配
iOS 屏幕比例适配