公司的项目,临上线之前做了一下iOS10的适配,发现一大堆的坑,瞬间觉得苹果不友好了。
一、证书问题
打开xcode8.0时编译运行时出现下面问题:
这个问题刚开始估计大家都会碰到也是第一个要解决的问题这个问题就是一个证书的设置问题,下面看两张图正常我们会在BuildeSettings中设置证书:
但是在xcode8.0中我们看到下面的新特性:
相信大家都能看到在Genreal下面会有Siging,没错这就是新特性,为了方便用户来管理,大家可以选择Automatically manage signing。需要输入开发者账号!如果没有账号也没关系,在下面也可以选择Debug、Realease、inHouse模式下对应的证书也可以!
但是 但是 但是 如果你的证书如果是通配符类型的,但是你的app包含了比如推送、apple pay、他会报错提示你未报含xx.id的manteid等等。所以你要生成针对你app的bundleid对应的证书!
二、系统判断方法失效
在你的项目中,当需要判断系统版本的话,不要使用下面的方法:
#define isiOS10 ([[[[UIDevice currentDevice] systemVersion] substringToIndex:1] intValue]>=10)
它会永远返回NO,substringToIndex:1
在iOS 10 会被检测成iOS 1
了,应该使用下面的这些方法:
Objective-C 中这样写:
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
或者使用:
if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_9_0) {
// do stuff for iOS 9 and newer
} else {
// do stuff for older versions than iOS 9
}
ps:
有时候会缺少一些常量,NSFoundationVersionNumber是在NSObjCRuntime.h中定义的,作为Xcode7.3.1的一部分,我们设定常熟范围从iPhone OS 2到#define NSFoundationVersionNumber_iOS_8_4 1144.17,在iOS 10(Xcode 8)中,苹果补充了缺少的数字,设置有未来的版本.
#define NSFoundationVersionNumber_iOS_9_0 1240.1
#define NSFoundationVersionNumber_iOS_9_1 1241.14
#define NSFoundationVersionNumber_iOS_9_2 1242.12
#define NSFoundationVersionNumber_iOS_9_3 1242.12
#define NSFoundationVersionNumber_iOS_9_4 1280.25
#define NSFoundationVersionNumber_iOS_9_x_Max 1299
三、隐私数据访问问题
你的项目中访问了隐私数据,比如:相机,相册,联系人等,在Xcode8中打开编译的话,统统会crash,控制台会输出下面这样的日志:
这是因为iOS对用户的安全和隐私的增强,在申请很多私有权限的时候都需要添加描述,但是,在使用Xcode 8之前的Xcode还是使用系统的权限通知框.
要想解决这个问题,只需要在info.plist添加NSContactsUsageDescription的key, 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>
四、UIColor的问题
官方文档中说:大多数core开头的图形框架和AVFoundation都提高了对扩展像素和宽色域色彩空间的支持.通过图形堆栈扩展这种方式比以往支持广色域的显示设备更加容易。现在对UIKit扩展可以在sRGB的色彩空间下工作,性能更好,也可以在更广泛的色域来搭配sRGB颜色.
如果你的项目中是通过低级别的api自己实现图形处理的,建议使用sRGB,也就是说在项目中使用了RGB转化颜色的建议转换为使用sRGB,在UIColor
类中新增了两个api:
- (UIColor *)initWithDisplayP3Red:(CGFloat)displayP3Red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha NS_AVAILABLE_IOS(10_0);
+ (UIColor *)colorWithDisplayP3Red:(CGFloat)displayP3Red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha NS_AVAILABLE_IOS(10_0);
五、真彩色的显示
真彩色的显示会根据光感应器来自动的调节达到特定环境下显示与性能的平衡效果,如果需要这个功能的话,可以在info.plist里配置(在Source Code模式下):
<key>UIWhitePointAdaptivityStyle</key>
它有五种取值,分别是:
<string>UIWhitePointAdaptivityStyleStandard</string> // 标准模式<string>UIWhitePointAdaptivityStyleReading</string> // 阅读模式<string>UIWhitePointAdaptivityStylePhoto</string> // 图片模式<string>UIWhitePointAdaptivityStyleVideo</string> // 视频模式<string>UIWhitePointAdaptivityStyleStandard</string> // 游戏模式
也就是说如果你的项目是阅读类的,就选择UIWhitePointAdaptivityStyleReading
这个模式,五种模式的显示效果是从上往下递减,也就是说如果你的项目是图片处理类的,你选择的是阅读模式,给选择太好的效果会影响性能.
六、ATS的问题
WWDC 15 提出的 ATS (App Transport Security) 是 Apple 在推进网络通讯安全的一个重要方式。在 iOS 9 和 OS X 10.11 中,默认情况下非 HTTPS 的网络访问是被禁止的。当然,因为这样的推进影响面非常广,作为缓冲,我们可以在 Info.plist 中添加 NSAppTransportSecurity字典并且将 NSAllowsArbitraryLoads设置为YES来禁用 ATS。
不过,WWDC 16 中,Apple 表示将继续在 iOS 10 和 macOS 10.12 里收紧对普通 HTTP 的访问限制。从 2017 年 1 月 1 日起,所有的新提交 app 默认是不允许使用 NSAllowsArbitraryLoads来绕过 ATS 限制的,也就是说,我们最好保证 app 的所有网络请求都是 HTTPS 加密的,否则可能会在应用审核时遇到麻烦。
但是我们可以选择使用NSExceptionDomains设置白名单的方式对特定的域名开放HTTP内容来通过审核,比如说你的应用集成了第三方的登录分享SDK,可以通过这种方式来做,下面以新浪SDK作为示范(Source Code 模式下):
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>sina.cn</key>
<dict>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.0</string>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
<key>NSIncludesSubdomains</key>
<true/>
</dict>
</dict>
</dict>
ps:
一般不建议这么做,对于 API 请求,基本上是必须使用 HTTPS 的,可能需要后端的同学尽快升级到 HTTPS,只有这样,才能确保数据在传输时的安全,同时也避免了应用审核时遇到麻烦。
七、Xcode 8 运行一堆没用的logs解决办法
上图我们看到,自己新建的一个工程啥也没干就打印一堆烂七八糟的东西,我觉得这个应该是Xcode 8的问题,具体也没细研究,解决办法是设置OS_ACTIVITY_MODE : disable
如下图:
从网上找到的答案:
Try this:
1- From Xcode menu open: Product > Scheme > Edit Scheme
2- On your Environment Variables set OS_ACTIVITY_MODE = disable
八、推送
自从Notification被引入之后,苹果就不断的更新优化,但这些更新优化只是小打小闹,直至现在iOS 10开始真正的进行大改重构,这让开发者也体会到UserNotifications的易用,功能也变得非常强大。
九、字体变化
苹果的默认字体会随着iOS系统版本的不同而不同,iOS10中字体变大了。导致了原来的显示有问题,会造成...的出现。暂时没有好的解决办法,需要自己在一个个适配一下!
十、UIStatusBar的问题
在你的viewController重写我们还没用的新的方法
- (BOOL)prefersStatusBarHidden{
return YES;
}
- (UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleDefault;
}
ps:
上面这个新方法在UIViewController.h文件中,这说明什么?当然说明这是viewController的属性和方法了,只需要在viewController里调用修改即可
UIStatusBarStyle 和 prefersStatusBarHidden这两个属性是readonly readonly readonly也就是说我们如果调用下面 肯定是报错的:
self.preferredStatusBarStyle = UIStatusBarStyleDefault;
和
self.prefersStatusBarHidden = YES;
这么写是错误的。
这是我在项目中遇到的问题,如果你还遇到其他的问题,请评论我,咱们一起完善。