iOS 13 兼容性适配检查
Last updated
Last updated
复制下面的关键字在 Xcode 中正则搜索
crash: [searchBar setValue:@”取消” forKey:@”_cancelButtonText”];
这种做法在 iOS 13 中会导致崩溃,崩溃信息如下 *** Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘Client error attempting to change layout margins of a private view’
解决方案 使用设置 frame 的方式,让 _UINavigationBarContentView 向两边伸展,从而抵消两边的边距。
[_textField setValue:[UIColor redColor] forKeyPath:@”_placeholderLabel.textColor”];///崩溃 [_textField setValue:[UIFont systemFontOfSize:14] forKeyPath:@”_placeholderLabel.font”];///崩溃解决方案 _textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@”姓名” attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:14],NSForegroundColorAttributeName:[UIColor redColor]}];在Xcode10上编译不会有问题,但在Xcode11上编译的会崩溃。并且- (void)setValue:(nullable id)value forKey:(NSString *)key方法没问题,- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath会崩溃
第三方 NSDictionary 扩展重名 打印日志:objc[5337]: REPLACED: -[NSDictionary boolForKey:] by category HMFoundation (IMP was 0x104ae8280 (/var/containers/Bundle/Application/B1486820-C2CC-4339-9D41-DBF1AC77EBF2/iHome4iPhone.app/iHome4iPhone), now 0x186d95a8c (/System/Library/PrivateFrameworks/HMFoundation.framework/HMFoundation))解决方案 Category 换名字
stringForKey 返回的是默认值是@“”并非nil. if([dict stringForKey:@”key”]){} 会发生逻辑错误解决方案 [dict stringForKey:@”key”].length > 0
见 <Category 私有函数>
在 iOS 13 中,这种方法已经失效,NSData类型的 deviceToken 转换成的字符串变成了: {length = 32, bytes = 0xd7f9fe34 69be14d1 fa51be22 329ac80d … 5ad13017 b8ad0736 }
解决方案
#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);
}
苹果将 UIViewController 的 modalPresentationStyle 属性的默认值改成了新加的一个枚举值 UIModalPresentationAutomatic,对于多数 UIViewController,此值会映射成 UIModalPresentationPageSheet。 这种效果弹出来的页面导航栏部分是会被砍掉的,在 storyboard 中也可以看到,页面布局时需要注意导航栏的内容不要被遮挡。注意,我们原来以全屏的样式弹出一个页面,那么将这个页面弹出的那个 ViewController 会依次调用 viewWillDisappear 和 viewDidDisappear。然后在这个页面被 dismiss 的时候,将他弹出的那个 ViewController 的 viewWillAppear 和 viewDidAppear 会被依次调用。然而使用默认的视差效果弹出页面,将他弹出的那个 ViewController 并不会调用这些方法,原先写在这四个函数中的代码以后都有可能会存在问题。解决方案:如果视差效果的样式可以接受的话,就不需要修改;如果需要改回全屏显示的界面,需要手动设置弹出样式:
或 self.modalPresentationStyle = .fullScreen
CNCopyCurrentNetworkInfo 文档说明,应用还需要符合下列三项条件中的至少一项才能得到正确的值:使用 Core Location 的应用, 并获得定位服务权限。 使用 NEHotspotConfiguration 来配置 WiFi 网络的应用。 目前正处于启用状态的 VPN 应用。解决方案: 获取 wift信息还要先获得位置授权
在 iOS 8 之前,我们在 UITableView 上添加搜索框需要使用 UISearchBar + UISearchDisplayController 的组合方式,而在 iOS 8 之后,苹果就已经推出了 UISearchController 来代替这个组合方式。在 iOS 13 中,如果还继续使用 UISearchDisplayController 会直接导致崩溃,崩溃信息如下: *** 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.’
解决方案: 使用 UISearchController 替换 UISearchBar + UISearchDisplayController 的组合方案。
UIWebView 将被禁止提交审核 如果开发者将包含 UIWebView api 的应用更新上传到 App Store 审核后,其将会收到包含 ITMS-90809 信息的回复邮件解决方案 用 WKWebView 替代 UIWebView,确保所有 UIWebView 的 api 都要移除,如果需要适配 iOS 7 的可以通过 openURL 的方式在 Safari 打开。
在 iOS 9 之前播放视频可以使用 MediaPlayer.framework 中的MPMoviePlayerController类来完成,它支持本地视频和网络视频播放。但是在 iOS 9 开始被弃用,如果在 iOS 13 中继续使用的话会直接抛出异常:*** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘MPMoviePlayerController is no longer available. Use AVPlayerViewController in AVKit.’
解决方案
使用 AVFoundation 里的 AVPlayer 作为视频播放控件。
使用 @available 导致旧版本 Xcode 编译出错 在 Xcode 11 的 SDK 工程的代码里面使用了 @available 判断当前系统版本,打出来的包放在 Xcode 10 中编译,会出现一下错误:Undefine symbols for architecture i386: “__isPlatformVersionAtLeast”, referenced from: … ld: symbol(s) not found for architecture i386复制代码从错误信息来看,是 __isPlatformVersionAtLeast 方法没有具体的实现,但是工程里根本没有这个方法。实际测试无论在哪里使用@available ,并使用 Xcode 11 打包成动态库或静态库,把打包的库添加到 Xcode 10 中编译都会出现这个错误,因此可以判断是 iOS 13 的 @available 的实现中使用了新的 api。 解决方案 如果你的 SDK 需要适配旧版本的 Xcode,那么需要避开此方法,通过获取系统版本来进行判断: if ([UIDevice currentDevice].systemVersion.floatValue >= 13.0) { … }另外,在 Xcode 10 上打开 SDK 工程也应该可以正常编译,这就需要加上编译宏进行处理:
#ifndef __IPHONE_13_0 #define __IPHONE_13_0 130000 #endif
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0 … #endif
UITextField *textField = [searchBar valueForKey:@”_searchField”]; // Crash
解决方案
// 替代方案 1,使用 iOS 13 的新属性 searchTextField searchBar.searchTextField.placeholder = @”search”;
[searchBar setValue:@”取消” forKey:@”_cancelButtonText”]; // Crash
解决方案
// 替代方案,用同上的方法找到子类中 UIButton 类型的属性,然后设置其标题
UIButton *cancelButton = [self findViewWithClassName:NSStringFromClass([UIButton class]) inView:searchBar];
[cancelButton setTitle:@”取消” forState:UIControlStateNormal];
类 | Category函数 | 系统Category仓库 |
NSObject | safeValueForKey | AccessibilityUtilities |
NSDictionary | boolForKey | HMFoundation |
NSDictionary | stringForKey | HMFoundation |
NSDictionary | arrayForKey | HMFoundation |
NSDictionary | dictionaryForKey | HMFoundation |
NSDictionary | dataForKey | HMFoundation |
NSDictionary | numberForKey | HMFoundation |
NSDictionary | mutableDictionaryForKey | HMFoundation |
NSDictionary | mutableArrayForKey | HMFoundation |
NSString | unsignedLongLongValue | HearingUtilities |
NSString | unsignedLongLongValue | HearingUtilities |
NSString | stdStringForString | libwebrtc |
NSString | stringForStdString | libwebrtc |
NSString | unsignedIntValue | IMFoundation |
NSString | stdString | GeoServices |
NSString | containsString | Foundation |
NSString | unsignedIntValue | IMFoundation |
NSString | hexValue | IMFoundation |
NSString | hasPrefixCaseInsensitive | CalendarFoundation |
NSString | urlEncodedString | Social |
NSMutableArray | nonRetainingArray | IMFoundation |