适配 iOS13(持续更新)

21,878 阅读6分钟

最后更新时间:2019-11-5

不久前,苹果WWDC19开发者大会在美国加州圣何塞举行。这次大会上,苹果公布了 iOS13 的更新内容,今天我们来看看如何适配 iOS13.

Sign in with Apple

苹果更新了审核规则以后要求所有使用第三方登录的应用必须向用户提供以苹果账号登录的选项, 并且要放前边。但苹果同样举出了几种特例的情况:

  • 仅使用公司内部账号登陆。

  • 教育或者企业应用,需要使用现有的教育和企业帐号登录。

  • 应用需要使用政府或者行业背景的共名身份系统或者 电子ID 进行登录。

  • 应用是特定的第三方客户服务客户端,需要使用邮箱,社交帐号,或者其他的三方服务来获取他们的内容。

  • Sign in with Apple 设计规范

  • App Store Review Guidelines

黑夜模式

Apps on iOS 13 are expected to support dark mode Use system colors and materials Create your own dynamic colors and images Leverage flexible infrastructure

// 模式强制切换
if (darkMode) {
    if (@available(iOS 13.0, *)) {
        [UIApplication sharedApplication].keyWindow.overrideUserInterfaceStyle = UIUserInterfaceStyleDark;
    }
} else {
    if (@available(iOS 13.0, *)) {
        [UIApplication sharedApplication].keyWindow.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
    }
}

已知问题:

  • YYLabel 如果使用了 textLayout属性,切换模式的时候 无法自动修改layout文本的颜色(已解决,后续会单独出文章)
  • 内嵌WebView,需要手动修改css样式(可以使用css3中的@media来解决)
  • CGColor无法根据模式切换 [参考]

KVC 限制

iOS13 以后已经不能肆无忌惮的通过 KVC 来修改一些没有暴露出来的属性了。

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

已知:

// UITextField 的 _placeholderLabel
[textField setValue:[UIColor xxx] forKeyPath:@"_placeholderLabel.textColor"];

// UISearchBar 的 _searchField
[searchBar valueForKey:@"_searchField"];

模态弹出默认交互改变

/*
 Defines the presentation style that will be used for this view controller when it is presented modally. Set this property on the view controller to be presented, not the presenter.
 If this property has been set to UIModalPresentationAutomatic, reading it will always return a concrete presentation style. By default UIViewController resolves UIModalPresentationAutomatic to UIModalPresentationPageSheet, but other system-provided view controllers may resolve UIModalPresentationAutomatic to other concrete presentation styles.
 Defaults to UIModalPresentationAutomatic on iOS starting in iOS 13.0, and UIModalPresentationFullScreen on previous versions. Defaults to UIModalPresentationFullScreen on all other platforms.
 */
@property(nonatomic,assign) UIModalPresentationStyle modalPresentationStyle API_AVAILABLE(ios(3.2));

iOS 13presentViewController 默认有视差效果,模态出来的界面现在默认都下滑返回。 一些页面必须要点确认才能消失的,需要适配。如果项目中页面高度全部是屏幕尺寸,那么多出来的导航高度会出现问题。

// Swift
self.modalPresentationStyle = .fullScreen

// Objective-C
self.modalPresentationStyle = UIModalPresentationFullScreen;

UISegmentedControl 默认样式改变

默认样式变为白底黑字,如果设置修改过颜色的话,页面需要修改

UITabbar 层次发生改变,无法通过设置 shadowImage去掉上面的线

可以参考 腾讯 QMUIKit 里面的实现

App启动过程中,部分View可能无法实时获取到frame

可能是为了优化启动速度,App 启动过程中,部分View可能无法实时获取到正确的frame

// 只有等执行完 UIViewController 的 viewDidAppear 方法以后,才能获取到正确的值,在viewDidLoad等地方 frame Size 为 0,例如:
 [[UIApplication sharedApplication] statusBarFrame];

标记为 API_DEPRECATED 部分类被移除

  • MPMoviePlayerController ==> AVPlayerViewController
  • UISearchDisplayController ==> UISearchController
*** Terminating app due to uncaught exception 'NSGenericException', reason: 'UISearchDisplayController is no longer supported when linking against this version of iOS. Please migrate your application to UISearchController.'

DeviceToken 获取

DeviceToken 获取到的格式发生变化

#include <arpa/inet.h>
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    if (![deviceToken isKindOfClass:[NSData class]]) return;
    const unsigned *tokenBytes = [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);
}

参考:developer.umeng.com/docs/66632/…

CNCopyCurrentNetworkInfo 变化

iOS13 以后只有开启了 Access WiFi Information capability,才能获取到 SSID 和 BSSID

 An app that fails to meet any of the above requirements receives the following return value:

- An app linked against iOS 12 or earlier receives a dictionary with pseudo-values. In this case, the SSID is Wi-Fi (or WLAN in the China region), and the BSSID is 00:00:00:00:00:00.
- An app linked against iOS 13 or later receives NULL.

参考:CNCopyCurrentNetworkInfo

即将废弃的 LaunchImage

iOS 8 之前我们是在 LaunchImage 来设置启动图,但是随着苹果设备尺寸越来越多,我们需要在对应的 aseets 里面放入所有尺寸的启动图,这是非常繁琐的一个步骤。因此在 iOS 8 苹果引入了 LaunchScreen.storyboard,支持界面布局用的 AutoLayout + SizeClass ,可以很方便适配各种屏幕。

需要注意的是,苹果在 Modernizing Your UI for iOS 13 section 中提到 ,从2020年4月开始,所有支持 iOS 13 的 App 必须提供 LaunchScreen.storyboard,否则将无法提交到 App Store 进行审批。

使用蓝牙需要添加权限描述

iOS 13以前,使用蓝牙时可以直接用,不会出现权限提示,iOS13以后使用就会提示。并且需要在info.plist里增加 NSBluetoothAlwaysUsageDescription

Your app's code references one or more APIs that access sensitive user data. The app's Info.plist file should contain a NSBluetoothAlwaysUsageDescription key with a user-facing purpose string explaining clearly and completely why your app needs the data. Starting Spring 2019, all apps submitted to the App Store that access user data are required to include a purpose string. If you're using external libraries or SDKs, they may reference APIs that require a purpose string. While your app might not use these APIs, a purpose string is still required. You can contact the developer of the library or SDK and request they release a version of their code that doesn't contain the APIs. Learn more (developer.apple.com/documentati…).

ps:如果你的应用里面没有用到蓝牙,却提示这个问题,可以检查下 个推SDK 是否更新到最新版本

废弃UIWebview APIs

iOS 有 UIWebviewWKWebview 两种Webview。从 iOS13 开始苹果将 UIWebview 列为过期API。 目前提交苹果应用市场(App Store)会反馈以下邮件提示:

ITMS-90809: Deprecated API Usage - Apple will stop accepting submissions of apps that use UIWebView APIs .
See developer.apple.com/documentati… for more information.

查找哪些SDK包含了 UIWebView

find . -type f | grep -e ".a" -e ".framework" | xargs grep -s UIWebView

目前常用的SDK中,已知更新移除 UIWebView 的版本有:

  • QQ登录 (v3.3.6)
  • ShareSDK (v4.3.2)
  • 极验证 (v0.12.5)
  • 新浪微博(v3.2.5)
  • 微信开放平台 (v1.8.6.1)

暂未更新移除 UIWebView 版本的 SDK :

  • 谷歌广告

部分关于 UIWebView 审核问题的讨论:

dcloud Cocos2d-x ShareSDK

Non-Public API usage

苹果更新了 Non-public API usage 扫描的库, 导致很多知名第三方库被误伤:

  • fmdb
  • SSZipArchive
  • CocoaLumberjack

ITMS-90338: Non-public API usage - The app references non-public selectors in {APPName}: _clearBackgroundViews, databasePool:didAddDatabase:, databasePool:shouldAddDatabaseToPool:, ddSetLogLevel:, zipArchiveDidUnzipFileAtIndex:totalFiles:archivePath:unzippedFilePath:, zipArchiveProgressEvent:total:. If method names in your source code match the private Apple APIs listed above, altering your method names will help prevent this app from being flagged in future submissions. In addition, note that one or more of the above APIs may be located in a static library that was included with your app. If so, they must be removed. For further information, visit the Technical Support Information at developer.apple.com/support/tec…

模拟器问题

Xcode 11.1 如果碰到 模拟器启动的时候卡住的话,可以把 模拟器 -> Edit-> Automatically sync pastaBoard 关掉

MJExtension 问题

Stack overflow in +[NSObject(Property) mj_properties] 升级 MJExtension 至 3.1.0版本以上,弃用老方法,涉及到所有方法添加 mj_ 前缀。