本文主要讲述iOS8.0系统至iOS14系统的变化差异,博主踩坑历程

一、iOS8.0

1、UIActionSheet 和 UIAlertView 的升级

在iOS8里面,官方提供了新的类UIAlertController来替换UIActionSheet 和 UIAlertView。

UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"My Alert"message:@"This is an alert."preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction * _Nonnull action) {}];
[self presentViewController:alert animated:YES completion:nil];

2、定位功能使用改变

// 判断定位操作是否被允许
if([CLLocationManager locationServicesEnabled]) {    locationManager = [[CLLocationManager alloc] init];    locationManager.delegate = self;    [locationManager startUpdatingLocation];
}else {    //提示用户无法进行定位操作
}

如果在iOS8下用这样的方式,你会发现无法定位,那是因为iOS8下添加了新的方法

//表示使用应用程序期间  开启定位
- (void)requestWhenInUseAuthorization;//表示始终 开启定位
- (void)requestAlwaysAuthorization;

两者区别在于,从iOS7 开始,有更强大的后台运行功能,如果用 requestAlwaysAuthorization 方法,则表示后台运行时也会用到定位

iOS8 下使用系统定位如下:

// 判断定位操作是否被允许
if([CLLocationManager locationServicesEnabled]) {  locationManager = [[CLLocationManager alloc] init];  locationManager.delegate = self;  //兼容iOS8定位  SEL requestSelector = NSSelectorFromString(@"requestWhenInUseAuthorization");  if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined && [locationManager respondsToSelector:requestSelector]) {  [locationManager requestWhenInUseAuthorization];  } else {[locationManager startUpdatingLocation];  }  return YES;
}else {//提示用户无法进行定位操作
}
return NO;

除了这些,你还需要在 info.plist 里面添加新的键值,否则 也是无法定位的

持续获取地理位置 NSLocationAlwaysUsageDescription
使用时获取地理位置 NSLocationWhenInUseUsageDescription

3、解决跳转到系统设置里自己App的页面

在iOS5.0时时可以跳转到系统的设置页的。但是在5.1之后就不可以了。

下面说下iOS8是如何跳转的,以下是代码:

NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
if ([[UIApplication sharedApplication] canOpenURL:url]) {[[UIApplication sharedApplication] openURL:url];
}

二、iOS 9.0

1、安装不受信任的开发者应用

在Xcode7后,开发者可以不用花99dollars去购买开发者账号而可以联调自己的iPhone进行测试。在安装这些应用时,iOS9系统不再向以前那样,再安装时提示一个信任的按钮。

2、iOS9网络适配_ATS:改用更安全的HTTPS

为了强制增强数据访问安全, iOS9 默认会把 所有的http请求 所有从NSURLConnection 、 CFURL 、 NSURLSession发出的 HTTP 请求,都改为 HTTPS 请求:iOS9.x-SDK编译时,默认会让所有从NSURLConnection 、 CFURL 、 NSURLSession发出的 HTTP 请求统一采用TLS 1.2 协议。因为 AFNetworking 现在的版本底层使用了 NSURLConnection ,众多App将被影响(基于iOS8.x-SDK的App不受影响)。服务器因此需要更新,以解析相关数据。如不更新,可通过在 Info.plist 中声明,倒退回不安全的网络请求。

而这一做法,官方文档称为ATS,全称为App Transport Security,是iOS9的一个新特性。

<key>NSAppTransportSecurity</key><dict><key>NSAllowsArbitraryLoads</key><true/></dict>

3 BitCode的配置

BitCode是app的一种中间形式,在iOS9系列专题的前几篇,有对其的简单介绍,举个例子,我们可以在提交app时提交app的bitcode形式,如此一来,apple会对我们的app进行二次优化,在用户下载时根据所需再进行编译打包。在Xocde7中,新建的项目是默认开启BitCode的,如果我们用Xcode7编译提交应用,这里有需要注意适配的地方。

如果要支持BitCode,需要保证所有的SDK都支持BitCode,如果要更新旧的SDK,只需要在Xcode7上开启BitCode重新制作一遍即可。

如果不能使所有SDK都支持BitCode,可以在项目中关闭BitCode,在building Setting中搜索BitCode,将enable设置为NO。

4 URL Scheme白名单

在iOS9中,apple引入了白名单这个概念,其好处是对app应用内安全进行了加强。在iOS9的适配中,如果我们用到canOpenURL这样的方法,则需要配置白名单。

首先,我们创建一个测试工程,什么都不用做,只需要添加一个URL Scheme

在另一个工程中,我们写如下代码:

BOOL can= [[UIApplication sharedApplication]canOpenURL:[NSURL URLWithString:@"weixin://"]];
[[UIApplication sharedApplication]openURL:[NSURL URLWithString:@"weixin://"]]

5、后台定位类app适配点

在iOS8中,APP的定位服务apple就做了一些修改,需要用户申请相应的权限,并在info.plist文件中添加对应的键值

在iOS9系统中,定位服务的做法基本没有改变,对于前台的定位没有影响,但app中如果需要后台定位,那么还需要多做一些操作,例如:

manager = [[CLLocationManager alloc]init];
//申请后台定位权限
[manager requestAlwaysAuthorization];
manager.delegate=self;//下面这个是iOS9中新增的方法 开启后台定位
manager.allowsBackgroundLocationUpdates = YES;
[manager startUpdatingLocation];

通过上面简单的配置直接运行的话,程序会崩溃掉,还需要在plist文件中做一些配置

三、iOS 10.0

1、iOS 10 隐私权限设置

自2018年10月3日起,App Store Connect 将要求所有的新 App 和 App 更新提供隐私政策,才可提交至 App Store 或通过 TestFlight 外部测试进行分发。此外,您只有在提交 App 的新版本时,才能编辑 App 的隐私政策链接或文本。
若要为通过 TestFlight 外部测试进行分发的 App 添加隐私政策链接
有关更多信息,请参见《App Store 审核指南》。

iOS 10 开始对隐私权限更加严格,如果你不设置就会直接崩溃,现在很多遇到崩溃问题了,一般解决办法都是在info.plist文件添加对应的Key-Value就可以了。

权限名称 Key值
通讯录 NSContactsUsageDescription
麦克风 NSMicrophoneUsageDescription
相册 NSPhotoLibraryUsageDescription
相机 NSCameraUsageDescription
添加图片到相册 NSPhotoLibraryAddUsageDescription
持续获取地理位置 NSLocationAlwaysUsageDescription
使用时获取地理位置 NSLocationWhenInUseUsageDescription
蓝牙 NSBluetoothPeripheralUsageDescription
语音转文字 NSSpeechRecognitionUsageDescription
日历 NSCalendarsUsageDescription

2、ATS的问题

iOS 9中默认非HTTS的网络是被禁止的,当然我们也可以把NSAllowsArbitraryLoads设置为YES禁用ATS。不过iOS 10从2017年1月1日起苹果不允许我们通过这个方法跳过ATS,也就是说强制我们用HTTPS,如果不这样的话提交App可能会被拒绝。但是我们可以通过NSExceptionDomains来针对特定的域名开放HTTP可以容易通过审核。

3、Notification(通知)

所有相关通知被统一到了UserNotifications.framework框架中

增加了撤销、更新、中途还可以修改通知的内容

通知不在是简单的文本了,可以加入视频、图片,自定义通知的展示等等。

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

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

4、iOS 10 UICollectionView 性能优化

随着开发者对UICollectionView的信赖,项目中用的地方也比较多,但是还是存在一些问题,比如有时会卡顿、加载慢等。所以iOS 10 对UICollectionView进一步的优化。

UICollectionView cell pre-fetching预加载机制

UICollectionView and UITableView prefetchDataSource 新增的API

针对self-sizing cells 的改进

5UITextContentType

在iOS 10 UITextField添加了textContentType枚举,指示文本输入区域所期望的语义意义。

使用此属性可以给键盘和系统信息,关于用户输入的内容的预期的语义意义。例如,您可以指定一个文本字段,用户填写收到一封电子邮件确认uitextcontenttypeemailaddress。当您提供有关您期望用户在文本输入区域中输入的内容的信息时,系统可以在某些情况下自动选择适当的键盘,并提高键盘修正和主动与其他文本输入机会的整合。

6字体随着手机系统字体而改变

当我们手机系统字体改变了之后,那我们App的label也会跟着一起变化,这需要我们写很多代码来进一步处理才能实现,但是iOS 10 提供了这样的属性adjustsFontForContentSizeCategory来设置。因为没有真机,具体实际操作还没去实现,如果理解错误帮忙指正。

UILabel *myLabel = [UILabel new];
/*UIFont 的preferredFontForTextStyle: 意思是指定一个样式,并让字体大小符合用户设定的字体大小。*/myLabel.font =[UIFont preferredFontForTextStyle: UIFontTextStyleHeadline]; /*Indicates whether the corresponding element should automatically update its font when the device’s UIContentSizeCategory is changed.For this property to take effect, the element’s font must be a font vended using +preferredFontForTextStyle: or +preferredFontForTextStyle:compatibleWithTraitCollection: with a valid UIFontTextStyle.*///是否更新字体的变化
myLabel.adjustsFontForContentSizeCategory = YES;

7系统版本判断方法失效

我们之前的系统版本方法如下

当系统版本到iOS10.0的时候 9.0和10.0比较的话是降序而不是升序,这样会导致iOS10.0是最早的版本,这样后面要走的iOS10的方法可能都不会走而出现问题

#define IOS9_OR_LATER ([[[UIDevice currentDevice] systemVersion] compare:@"9.0"] != NSOrderedAscending)#define IOS8_OR_LATER ([[[UIDevice currentDevice] systemVersion] compare:@"8.0"] != NSOrderedAscending)#define IOS7_OR_LATER ([[[UIDevice currentDevice] systemVersion] compare:@"7.0"] != NSOrderedAscending)#define IOS6_OR_LATER ([[[UIDevice currentDevice] systemVersion] compare:@"6.0"] != NSOrderedAscending)

下面这样也不行它会永远返回NO,substringToIndex:1在iOS 10 会被检测成 iOS 1了,

#define isiOS10 ([[[[UIDevice currentDevice] systemVersion] substringToIndex:1] intValue]>=10)

正确的打开方式应该是:

#define IOS10_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0)#define IOS9_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 9.0)#define IOS8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)#define IOS7_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)#define IOS6_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0)

8Xcode8 debug输出不相关信息

升级到Xcode8时,我们在debug的时候控制台输出了很长很长的信息,看着比较烦,怎么屏蔽呢?

需要edit Scheme添加一个键值对就ok了。

添加 key:​OS_ACTIVITY_MODE​ value:​disable​

9、App跳转设置

openUrl:

openURL: options: completionHandler:

prefs:root=某项服务

若要跳转系统设置,需先再URL type中添加一个prefs值,如下图:

10判断版本方法

[[UIDevice currentDevice] systemVersion]

11、推送xcode适配开关

在targets的Capabiliies内Push Notifications选项开关打开

然后Background Modes打开如下几个选项

General内导入UserNotifications.framework

12、Xib文件

(1)使用Xcode8 打开xib文件是会出现“choose an initial device view”的提示,直接选择蓝色的 choose Device 就可以了。

(2)如果布局混乱,在xib的右下角更新一下,即 Update Frame。

13、代码及API

(1)UIView的代理方法可能会出现报错,删除NSError前面的 nullable就行了。

(2)UIStatusBar的方法过期了,如果项目中设置了statusBar,那就像下面这样写:

- (UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleDefault;
}

四、iOS 11.0

1、XCode9运行访问系统相册崩溃问题

现象:如图保存图片功能,在XCode9下运行会崩溃

原因:info.plist新增了权限配置

解决:info.plist新增一条权限:

Privacy - Photo Library Additions Usage Description

2、无法获取定位信息,第一次打开app也无法弹出定位权限提示框

iOS11 定位相关的权限做了更改,在iOS11上使用了新的定位权限key

解决方案:

如果原来申请的权限是始终允许NSLocationAlwaysUsageDescription,需要在保留原来的key的基础上增加NSLocationWhenInUseUsageDescription和NSLocationAlwaysAndWhenInUsageDescription。

持续获取地理位置 NSLocationAlwaysUsageDescription
使用时获取地理位置 NSLocationWhenInUseUsageDescription

3、无线真机测试

这是WWDC2017的新功能,iOS11以上,Xcode9这是刚性要求;但是速度真的不是很干恭维的。注意手机和电脑必须在同一个局域网内

iOS11UI方面的适配较多,如启动图、tabbar、刘海儿、导航栏、启动图等适配这些UI方面的适配后续更新

五、iOS 12.0

1、代码中判断是否是iPhone X方法

之前很多人判断手机是否是iPhone X的方法是根据手机尺寸来的.因为需要对刘海做特殊处理.现在这种方法可能不行了.

可以根据其他的方法,比如StatusBar或者底部安全距离来判断

#define rmStatusBarH ([UIApplication sharedApplication].statusBarFrame.size.height)//(44/20)#define KIsiPhoneX ((rmStatusBarH == 44.0) ? YES : NO)也可以:#define isIPhoneXSeries     ([UIScreen instancesRespondToSelector:@selector(currentMode)] ?\
(\
CGSizeEqualToSize(CGSizeMake(375, 812),[UIScreen mainScreen].bounds.size)\||\
CGSizeEqualToSize(CGSizeMake(414, 896),[UIScreen mainScreen].bounds.size)\
)\
:\
NO)

2、升级Xcode10后项目报错

项目中如果使用Cocoapods引用了第三方的库,有可能会升级之后导致编译失败.

由于我项目中没有使用cocoapods,所以没有遇到,网上查了一下资料,大概是因为:

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

多个 info.plist 会引起崩溃.

可以将多余的info.plist删除

建议方案:

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

3、Multiple commands produce 'xxx/Info.plist'

升级​Xcode 10​之后,编译之前的项目,发生编译错误:​Multiple commands produce 'xxx/Info.plist'​,项目中存在重复命名的info.plist文件。

解决方案:

(1)标准方案:删除所有重复命名的文件。

(2)临时方案:

​xcworkspace​项目:Xcode菜单栏​File​ -> ​Workspace Settings​ -> ​Build System​ -> ​Legacy Build System​;

​xcodeprj​项目:Xcode菜单栏​File​ -> ​Project Settings​ -> ​Build System​ -> ​Legacy Build System​。

4、​iOS 12​系统​WiFi​获取​SSID​(wifi名称)和​BSSID​(mac地址)失败

在​iOS 12​系统之后,苹果提升了获取​WiFi​名称和​mac​地址的权限控制,要获取这些信息,需要手动为应用打开获取WiFi信息的权限。

解决方案:

在开发者账号中,勾选项目的​App ID​的​Access WiFi Infomation​选项;

在Xcode的​Capabilities​中,勾选项目的​Access WiFi Infomation​选项。

5、Xcode 10​中​#import​的时候闪退或导入头文件不提示

在​Xcode 10​中出现输入​#import​引入文件/类库头文件的时候​Xcode​闪退。或者输入​#import​导入头文件时不提示。

解决方案:

​xcworkspace​项目:Xcode菜单栏​File​ -> ​Workspace Settings​ -> ​Build System​ -> ​Legacy Build System​;

​xcodeprj​项目:Xcode菜单栏​File​ -> ​Project Settings​ -> ​Build System​ -> ​Legacy Build System​。

6、webView​播放视频返回后状态栏消失

视频播放完成主​window​成为​KeyWindow​的时候仍隐藏着​UIStatusBar​。

解决方案:

- (void)videoPlayerFinishedToShowStatusBar
{if (@available(iOS 12.0, *)) {[[NSNotificationCenter defaultCenter] addObserverForName:UIWindowDidBecomeKeyNotificationobject:self.windowqueue:[NSOperationQueue mainQueue]usingBlock:^(NSNotification * _Nonnull note) {                                                        [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];}];}
}

7、Xcode 10  imageNamed: 不能正常加载Assets里面的图片

imageNamed:加载Assets中的图片出来是nil,将图片放到bundle中即可。

六、iOS 13.0

1、私有KVC

iOS不允许​valueForKey​、​setValue: forKey​获取和设置私有属性,需要使用其它方式修改

如:

[textField setValue:[UIColor red] forKeyPath:@"_placeholderLabel.textColor"];//替换为textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"输入"attributes:@{NSForegroundColorAttributeName: [UIColor red]}];

2、黑线处理crash

之前为了处理搜索框的黑线问题会遍历后删除​UISearchBarBackground​,在iOS13会导致UI渲染失败crash;解决办法是设置​UISearchBarBackground​的layer.contents为nil

   public func clearBlackLine() {for view in self.subviews.last!.subviews {if view.isKind(of: NSClassFromString("UISearchBarBackground")!) {view.backgroundColor = UIColor.whiteview.layer.contents = nilbreak;}}}

3、模态跳转(modal present)

iOS13模态跳转出来的界面,不再像之前版本是全屏的了

如果将此属性设置为​UIModalPresentationAutomatic​,则读取该属性将始终返回具体的呈现样式。 默认情况下,​UIViewController​将​UIModalPresentationAutomatic​解析为​UIModalPresentationPageSheet​,但是系统提供的子类可以将​UIModalPresentationAutomatic​解析为其他具体的呈现样式。 保留​UIModalPresentationAutomatic​的分辨率供系统提供的视图控制器使用。从iOS 13.0开始,在iOS上默认为​UIModalPresentationAutomatic​,在以前的版本上默认为​UIModalPresentationFullScreen​。 在所有其他平台上,默认为​UIModalPresentationFullScreen​。

​UIModalPresentationPageSheet​就是下面的样子

知道了原因,我们做适配也简单了,就是设置下属性的事:

let second = SecondViewController()
second.modalPresentationStyle = .fullScreen
present(second, animated: true, completion: nil)

4、暗黑模式

iOS13使用暗黑模式时,UIView默认背景色会变成暗黑色。适配暗黑模式的工作量较大,改为强制使用正常模式。

处理方案:在plist文件中增加配置项UIUserInterfaceStyle,值为Light。

5、蓝牙权限更新

上传App Store时,如果引用了CoreBluetooth.framework,则需要添加描述配置​NSBluetoothAlwaysUsageDescription​,否则无法提交。旧版本的个推SDK引入时依赖CoreBluetooth,后续版本已修改不再依赖CoreBluetooth。

处理方案:检查其他第三方库并未依赖CoreBluetooth.framework,删除对该库的引用。

6、废弃UIWebview改为WKWebView

暂时没有强制修改,但是已经发邮件提示,需要做一下修改,否则可能无法上架哈

7、KVC限制

在iOS13上通过KVC来修改系统API私有属性时会报错

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Access to xxx's _xxx ivar is prohibited. This is an application bug'

处理方案:

1、全局搜索KVC的使用方法,未发现使用KVC方式修改私有属性的代码

2、平时开发时注意KVC的使用

8、第三方登录支持苹果登录(Sign In with Apple)

苹果更新了审核指南,要求所有专门使用第三方登录的App,2020 年 4 月之前,都必须接入 Sign in with Apple。符合以下条件的App,可以不接入:

使用自建账户和登录系统;

要求用户使用现有的教育或企业账户登录的教育、企业或商业类应用;

使用政府或行业支持的公民身份识别系统或电子 ID 来验证用户;

应用特定于第三方服务,用户需要使用邮箱、社交媒体或其它第三方账户才能访问其内容的应用;

9、使用MJExtension 中处理NSNull的不同

这个直接会导致Crash的在将服务端数据字典转换为模型时,如果遇到服务端给的数据为NSNull时,

mj_JSONObject,其中 class_copyPropertyList方法得到的属性里,多了一种EFSQLBinding类型的东西,而且属性数量也不准确,

那就没办法了,

我只能改写这个方法了,这个组件没有更新的情况下,写了一个方法swizzling掉把当遇到 NSNull时,直接转为nil了。

10、WKWebView 中测量页面内容高度的方式变更

iOS 13以前

document.body.scrollHeight

iOS 13中

document.documentElement.scrollHeight

两者相差55 应该是浏览器定义高度变了

11、友盟消息推送,获取deviceToken适配

- (void)application:(UIApplication*)applicationdidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {if(![deviceToken isKindOfClass:[NSData class]]) return;                  const unsigned *tokenBytes = (constunsigned *)[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])];      pushDeviceToken = hexToken;      NSLog(@"deviceToken:%@",hexToken);
}

12、获取Wi-Fi名

iOS12之前

id info = nil;
NSArray *ifs = (__bridge_transfer id)CNCopySupportedInterfaces();
for (NSString *ifnam in ifs) {info = (__bridge_transfer id)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);NSString *str = info[@"SSID"];//name
}

iOS 12之后以上方法获取不到,需要在Xcode中TARGET-->Capabilities打开Access WiFi Information选项

iOS 13之后以上方法获取Wi-Fi名返回的都是固定值"WLAN",这里可能是因为苹果保护用户隐私而产生的问题,因为通过wifi信息可以定位到用户地理位置。所以iOS13以后如果想要继续获取WiFi名称,需要在调用接口前判断用户是否同意App使用地理位置信息。可以在程序一启动时请求用户权限,调用的方法如下:

#import <CoreLocation/CoreLocation.h>@property (strong, nonatomic) CLLocationManager *locationManager;NSString* phoneVersion = [[UIDevice currentDevice] systemVersion];CGFloat version = [phoneVersion floatValue];// 如果是iOS13 未开启地理位置权限 需要提示一下
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined && version >= 13) {self.locationManager = [[CLLocationManager alloc] init];[self.locationManager requestWhenInUseAuthorization];
}

如果用户拒绝了授权,在需要获取Wi-Fi名的界面加上提示:

NSString* phoneVersion = [[UIDevice currentDevice] systemVersion];CGFloat version = [phoneVersion floatValue];//如果开启地理位置权限未开启 需要提示一下if (([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined ||[CLLocationManager authorizationStatus] == kCLAuthorizationStatusRestricted ||[CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied  )&& version >= 13) {[PracticalTools showAlertViewWithTitle:@"提示" message:@"您的位置权限尚未授权,将无法获取当前Wi-Fi进行配置网络,请前往“设置”-“****App”-“位置”进行授权!" doneText:@"确定" cancelText:nildoneHandle:nil cancelHandle:nil vc:self];
}

13、iOS13 正确的获得Devicetoken

#include <arpa/inet.h>- (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);
}

14、Xcode 11 创建的工程在低版本设备上运行黑屏

使用 Xcode 11 创建的工程,运行设备选择 iOS 13.0 以下的设备,运行应用时会出现黑屏。这是因为 Xcode 11 默认是会创建通过 UIScene 管理多个 UIWindow 的应用,工程中除了 AppDelegate 外会多一个 SceneDelegate. 

可参考文章iOS-Xcode11: 删除默认Main.storyBoard, 自定义UIWindow不能在AppDelegate中处理,新增SceneDelegate代理

这是为了 iPadOS 的多进程准备的,也就是说 UIWindow 不再是 UIApplication 中管理。但是旧版本根本没有 UIScene,因此解决方案就是在 AppDelegate 的头文件加上:

@property (strong, nonatomic) UIWindow *window;

15、NSAttributedString优化

对于UILabel、UITextField、UITextView,在设置NSAttributedString时也要考虑适配Dark Mode,否则在切换模式时会与背景色融合,造成不好的体验

不建议的做法

NSDictionary *dic = @{NSFontAttributeName:[UIFont systemFontOfSize:16]};NSAttributedString *str = [[NSAttributedString alloc] initWithString:@"富文本文案"attributes:dic];

推荐的做法

// 添加一个NSForegroundColorAttributeName属性
NSDictionary *dic = @{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor labelColor]};NSAttributedString *str = [[NSAttributedString alloc] initWithString:@"富文本文案"attributes:dic];

七、iOS 14.0

1、刘海屏statusBarFrame.size.height 有所改变

刘海屏手机出来之前,iOS App的顶部状态栏高度为20pt,导航栏的可布局区域高度为44pt,整个导航栏高度为64pt,底部安全距离为0。
在刘海屏手机出来后,刘海屏机型iOS App的顶部状态栏高度为44pt,导航栏的可布局区域高度为44pt,整个导航栏高度为88pt,底部安全距离为34pt。
Swift:

//获取状态栏的高度,全面屏手机的状态栏高度为44pt,非全面屏手机的状态栏高度为20pt
//状态栏高度
let statusBarHeight = UIApplication.shared.statusBarFrame.height;
//导航栏高度
let navigationHeight = (statusBarHeight + 44)
//tabbar高度
let tabBarHeight = (statusBarHeight==44 ? 83 : 49)
//顶部的安全距离
let topSafeAreaHeight = (statusBarHeight - 20)
//底部的安全距离,全面屏手机为34pt,非全面屏手机为0pt
let bottomSafeAreaHeight = (tabBarHeight - 49)

OC同上原理

double statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;

2、UITableViewCell上控件不响应点击事件

iOS14中 UITableViewCell 如果子控件是加到cell上的会被 cell的contentView所遮挡,contentView会在最上层。

解决办法: 将子控件加到contentView上或者隐藏cell的contentView

[self.contentView addSubview:self.showLabel];
[self.contentView addSubview:self.btn];

3、UICollectionView的scrollToItemAtIndexPath失效,设置滚动没有效果
换成 如下方法:

UICollectionViewLayoutAttributes *layoutAttributes = [self.collectView.collectionViewLayout layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0]];
[self.collectView setContentOffset:layoutAttributes.frame.origin animated:YES];

4、UIPickerView / UIDatePicker

(1)iOS14中UIPickerView的subviews只有2个元素,强行访问会导致崩溃;可参考论坛UIPickerView change separator color | Apple Developer Forums

[pickerView.subviews[1] setHidden:YES];
[pickerView.subviews[2] setHidden:YES];

(2)iOS13.4之后,UIDatePicker修改了默认的显示样式,如想用之前的样式可以添加如下设置

if (@available(iOS 13.4, *)) {_datePickerView.preferredDatePickerStyle = UIDatePickerStyleWheels;
} else {// Fallback on earlier versions
}

5、UIWebView 消除大作战

ITMS-90809:废弃API用法- 2020年12月将不再接受使用UIWebView的应用程序更新。相反,使用WKWebView来提高安全性和可靠性

基本上每次上线都能看到这个东西,近期听说集团有App上线已经因为这个UIWebView被拒了。所以来次大检查吧
1、检测源码中是否有UIWebView,或者UIWebViewDelegate
这个直接在搜索框中搜索即可
2、源码中没有UIWebView不代表安全了,通过Mach-O来全面查找吧
otool -oV [Mach-O路径] | tee [检测结果日志文件名称].log

otool -oV /Users/a58/Desktop/Tools/XXX.app/XXX  | tee classInfo.log

解释
otool -oV [Mach-O路径]
是获取所有的类结构及其定义的方法
| tee classInfo.log
由于打印的东西较多,我们在终端中显示不下,可以将终端打印的东西搞到文件中

直接在.log中查询UIWebView即可

通过该方法可以找到相关的三方库中的UIWebView和相关.a
.framework
中的UIWebView,然后进行相关的升级和替换

6、Xcode12 跑真机特别慢,目测直接在Xcode11上更新成xcode12的好像会有这个问题,可以参考下这篇文章链接地址,还是不行的可以尝试卸载Xcode完全重新安装,笔者在重新安装后就不卡了

八、iOS 15.0

1、NavigationBar

问题:导航栏问题比较明显,有的变白色,有的变黑色。(我们项目里有navigationBar原本白色现在变成灰色)

原因:UINavigationBar 部分属性的设置在 iOS15 上是无效的。

解决办法:查看导航栏API,iOS15的导航栏属性需用UINavigationBarAppearance(iOS13更新的API)来实现

Swift

        if #available(iOS 13.0, *) {let appearance = UINavigationBarAppearance()// 设置导航栏背景色appearance.backgroundColor = .white// 去除导航栏阴影(如果不设置clear,导航栏底下会有一条阴影线)appearance.shadowColor = UIColor.clear// 字体颜色appearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white]// 带scroll滑动的页面navigationController?.navigationBar.scrollEdgeAppearance = appearance// 常规页面navigationController?.navigationBar.standardAppearance = appearance }

OC

    if (@available(iOS 13.0, *)) {UINavigationBarAppearance * appearance = [[UINavigationBarAppearance alloc] init];// 背景色appearance.backgroundColor = [UIColor whiteColor];// 去除导航栏阴影(如果不设置clear,导航栏底下会有一条阴影线)appearance.shadowColor = [UIColor clearColor];// 字体颜色appearance.titleTextAttributes = @{NSForegroundColorAttributeName: [UIColor redColor]};// 带scroll滑动的页面self.navigationController.navigationBar.scrollEdgeAppearance = appearance;// 常规页面self.navigationController.navigationBar.standardAppearance = appearance;}

2、UITabBar

Swift

        if #available(iOS 13.0, *) { let appearance = UITabBarAppearance()// 背景色appearance.backgroundColor = .whitetabBar.standardAppearance = appearanceif #available(iOS 15.0, *) {tabBar.scrollEdgeAppearance = appearance}} 

Objective-C

    if (@available(iOS 13.0, *)) { UITabBarAppearance * appearance = [[UITabBarAppearance alloc] init];// 背景色appearance.backgroundColor = [UIColor whiteColor];self.tabBar.standardAppearance = appearance; if (@available(iOS 15.0, *)) {self.tabBar.scrollEdgeAppearance = appearance;}}

3、TableView

(1)初始化 UITableView用UITableViewStylePlain样式,发现 sectionHeader 增高了 22px

(这个问题在我们项目里也是有遇到的)

原因:iOS 15 的 UITableView 新增了一条新属性:sectionHeaderTopPadding, 默认会给每一个 sectionHeader 增加一个高度

解决办法:

//swift代码if #available(iOS 15.0, *) {tableView.sectionHeaderTopPadding = 0}
//Objective-C代码if (@available(iOS 15.0, *)) { tableView.sectionHeaderTopPadding = 0;}

(2)初始化 UITableView用UITableViewStylePlain样式,默认不显示灰色,上滑置顶时最上面的sectionHeader才有颜色。

解决办法:在viewForHeaderInSection代理方法返回自带灰色的section header

(3)设置 tableHeaderView 后,底部会增加一段高度 (需验证)

解决方案:在设置tableHeaderView时同时设置一个高度为0.01的tableFooterView即可:

tableView?.tableFooterView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 0.01))

b)storyboard里的tableView,适配屏幕尺寸改tableHeaderView高度,调layoutIfNeeded不生效,只高度改了,布局没改

DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
if let headerView = self.tableView?.tableHeaderView, let lastSubView = headerView.subviews.last {
if #available(iOS 15.0, *) {
headerView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: lastSubView.frame.origin.y + lastSubView.frame.size.height)
self.tableView?.tableHeaderView = headerView} else {
self.tableView?.tableHeaderView?.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: lastSubView.frame.origin.y + lastSubView.frame.size.height)
self.tableView?.tableHeaderView?.layoutIfNeeded()}}
}

4、UILabel

(1) NSBaselineOffsetAttributeName属性的值导致虽然约束没有问题但label内的文字位置不对

(这个问题在我们项目里有遇到的)

现在是以控件最上面的线为基准的偏移。所以用到这个属性的可以检查下。

(2)NSMutableParagraphStyle的lineSpacing属性失效 解决办法加上换行符 \b或\n等

Xcode12打的包在iOS15显示无效,而Xcode13打的包在iOS15有效

if (@available(iOS 15,*)) {NSAttributedString *placeholderChractor = [[NSAttributedString alloc] initWithString:@"\b"];[as insertAttributedString:placeholderChractor atIndex:0];}[as addAttributes:@{NSParagraphStyleAttributeName: style} range:NSMakeRange(0, as.length)];

(这个问题在我们项目里有遇到的)

(3)增加高度解决

iOS15计算的正好显示完Label文字高度,在IOS15显示不全,增加高度可解决。设置adjustsFontSizeToFitWidth为true时,高度不能与设置的font一样大,增加高度即可。(应该是Beta的问题 目前看正式版已修复)

5、检查用到的第三方库

如:第三方播放器框架ZFPlayer横屏出现问题,没有正确渲染布局,且无法切回竖屏页面
有几率闪退。第三方BRPickerView文字选择器内容布局错误。Facebook的跨平台框架React中的fishhook闪退。

解决办法:修改源码或看作者有没有适配

修改fishhook.c源码,参考 https://github.com/facebook/fishhook/issues/85 中的XuweiQT的方案,将链接中的fishhook.c替换项目中fishhook.c文件

6、H5在WKWebView的显示问题
部分链接在iOS15的WKWebView、微信、QQ、Safari中出现空白页about:blank

(应该是Beta的原因,目前正式版没有遇到)

以上iOS15正式版有的适配问题,除NSMutableParagraphStyle的lineSpacing属性失效问题,和标记为Beta的外,其他用Xcode12编译打的包在IOS15设备使用不出现,而用Xcode13编译会出现问题

参考以下文章,感谢

iOS - iOS8.0 至 iOS15.0 版本变化相关推荐

  1. Android高级进阶--插曲-从Android5.0到Android10各版本变化

    从Android5.0到Android10 一.Android5 1.ANDROID 5.0 行为变更: 声音和振动 (1)如果您当前使用 Ringtone.MediaPlayer 或 Vibrato ...

  2. IOS真机调试包 iOS15.0

    最新 iOS 真机调试包15.0 最近一不小心升级IOS15.0,我滴个乖乖! 由于xcode还是用的12.0,也不算太旧,就不想升级(因为升级xcode14要12.4G,然后还需要更新mac系统,当 ...

  3. 淘客基地:拾牛IOS版更新至1.0.5版本

    拾牛IOS版更新至1.0.5版本 主要更新:修复商品详情页打不开问题.在APP store中,底部导航栏"更新"中,下拉进行刷新,点击更新即可.

  4. (转)Android高级进阶--插曲-从Android5.0到Android9.0各版本变化

    原文:https://blog.csdn.net/gaoxiaoweiandy/article/details/83216001 从Android5.0到Android9.0 自从公司提出了一些出其不 ...

  5. 0.54与0.55版本react-native的TextInput在iOS上无法输入中文日文韩文的bug

    更新最新版本的react-native,发现最近两版本的TextInput终于出现对ios的不友好.在官网查了下发现 0.54与0.55版本react-native的TextInput在iOS上无法输 ...

  6. ios15.0.1正式版耗电吗 ios15.0.1正式版值得升级吗

    最近,ios15.0.1正式更新了,而很多用户关心的是 ios15.0.1正式版的耗电情况,那么,ios15.0.1正式版耗电吗? ios15.0.1正式版值得升级吗?下面就一起来看看吧. ios15 ...

  7. 读懂微信:从1.0到7.0版本,一个主流IM社交工具的进化史...

    本文由作者沈星佑原创发表于公众号"知晓程序",由即时通讯网整理并转载至此,感谢原作者的文字. 1.引言 12 月 30 日,微信 7.0 for Android 正式版上线,继 9 ...

  8. 读懂微信:从1.0到7.0版本,一个主流IM社交工具的进化史

    本文由作者沈星佑原创发表于公众号"知晓程序",由即时通讯网整理并转载至此,感谢原作者的文字. 1.引言 12 月 30 日,微信 7.0 for Android 正式版上线,继 9 ...

  9. 了解Android已发布的各种版本(即1.0、2.0、3.0、4.0、5.0、6.0、7.0、8.0)

    Android操作系统 是一个由Google 和开放手持设备联盟 共同开发发展的移动设备操作系统. 最早的一款系统是2008年9月,谷歌正式发布的Android 1.0系统,也就是Android最早的 ...

  10. android 5.0 ios 8,iOS 8与Android 5.0大比拼:功能相同 体验不同

    过去半年,Android和iOS的移动大战已经发生了一些有趣的变化.过去,两款移动操作系统的差别主要体现在功能和精致方面.传统上,Android以更多功能和更高的可定制性见长,iOS则更为精致. 但是 ...

最新文章

  1. 前端每周清单第 33 期:React 16 发布与特性介绍,Expo AR 教程,ExtJS 从崛起到沉寂...
  2. massive_record exmple
  3. mysql 命令 g_MySQL命令行的几个用法
  4. 美团数据仓库-数据脱敏
  5. Spring集成Mybatis多数据源配置
  6. C#:winform开发的System.AccessViolationException错误,已解决
  7. SPH(光滑粒子流体动力学)流体模拟实现二:SPH算法(4)-算法实现2
  8. linux symbol文件,[转] Linux文件系统之hard linksymbol link
  9. 音频播放IOS:AVAudioPlayer音频播放器
  10. Dubbo视频教程《基于Dubbo的分布式系统架构视频教程》----课程列表
  11. 测试驱动开发(TDD)的理论基础
  12. 给 TA 的一封匿名信-匿名信箱,一封来信,你的一封来信,一封Ta的来信,爆火的匿名信H5源码功能开发和分析,表白祝福道歉短信发送系统
  13. Python基础入门篇【26】--python基础入门练习卷B
  14. C语言程序设计入门教程
  15. 记一个小工具——font-spider(字蛛-css压缩中文字体字体)
  16. Delphi SM2/SM4国密算法
  17. [CODE【VS】]江哥的DP题d
  18. JSON.parse() 和 JSON.stringify()
  19. UE4之Spline
  20. Mac OS系统进不去,重装也不行,只能抹盘安装,如何备份电脑数据资料?

热门文章

  1. unity2019汉化
  2. 2019美赛M(一等/优异)奖,给想参加美赛的同学们的干货建议
  3. sqlserver卸载不完全导致安装失败
  4. 关于RDP报表工具参数配置
  5. QCC300x hello world
  6. 大一c语言作业操作题库,c语言题目(大一c语言编程题库)
  7. u盘修复计算机系统,用u盘修复win7系统
  8. 我们应当怎样做需求分析
  9. Android:使用keytool修改数字证书中字段(应用签名信息)
  10. 数控机床的十大数控系统,学了这么多年终于全了!