iOS 13适配

iOS 13适配

[toc]

私有属性的禁止访问

UITextField的私有属性 _placeholderLabel被禁止访问了

textColor

[self.textField setValue:self.placeholderColor forKeyPath:@"_placeholderLabel.textColor"];

font

[self.textField setValue:[UIFont boldSystemFontOfSize:14] forKeyPath:@"_placeholderLabel.font"];

崩溃日志如下

'Access to UITextField's _placeholderLabel ivar is prohibited. This is an application bug' 

只要是修改_placeholderLabel就会崩溃,所以我们要修改placeholderLabel需要用其他方法,有个富文本属性attributedPlaceholder可以使用,我们可以定义这个来达到我们的要求。
这里我直接是创建一个分类UITextField+placeholder来使用他
UITextField+placeholder.h

1
2
3
4
/// 修改text的placeholder 不需要访问私有属性
/// @param holder
/// @param text
- (void)changeplaceholde:(NSString *)holder text:(UITextField *)text;

UITextField+placeholder.m

1
2
3
4
5
6
7
8
9
10
- (void)changeplaceholde:(NSString *)holder text:(UITextField *)text{
NSMutableAttributedString *placeholder = [[NSMutableAttributedString alloc] initWithString:holder];
[placeholder addAttribute:NSForegroundColorAttributeName
value:hlla(0xC5C4C8,1.0)
range:NSMakeRange(0, holder.length)];
[placeholder addAttribute:NSFontAttributeName
value:[UIFont boldSystemFontOfSize:14]
range:NSMakeRange(0, holder.length)];
text.attributedPlaceholder = placeholder;
}

访问私有属性statusbar也会奔溃

UIView *statusBar = [[[UIApplication sharedApplication] valueForKey:@"statusBarWindow"] valueForKey:@"statusBar"];

奔溃日志如下

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'App called -statusBar or -statusBarWindow on UIApplication: this code must be changed as there's no longer a status bar or status bar window. Use the statusBarManager object on the window scene instead.'

意思是不能通过UIApplication来获取到statusBar,提示推荐用statusBarManager来获取,所以我们可以改一下

1
2
UIView *localStatusBar = [[UIApplication sharedApplication].keyWindow.windowScene.statusBarManager performSelector:@selector(createLocalStatusBar)];
UIView * statusBar = [localStatusBar performSelector:@selector(statusBar)];

searchBar的textfield

新的iOS 13SDK 给searchBar新加了一个属性searchtextfield,方便开发者修改里面的一些东西,例如placeholder,font,color等。但这个属性在iOS 12上没有的,就是说你再Xcode11添加了这些方法,如果用低于Xcode11版本打开工程是会报错的。所以就要适配

if (iOS13available) {
//        这个只在iOS 13使用
        [searchVC.searchBar.searchTextField changeSearchplaceholde:placeholder text:searchVC.searchBar.searchTextField];
        searchVC.searchBar.searchTextField.backgroundColor = [UIColor whiteColor];
    }

模态跳转默认方式改变

控制器的 modalPresentationStyle 默认值变了

1
2
3
4
5
6
7
8
9
10
11
12
13
typedef NS_ENUM(NSInteger, UIModalPresentationStyle) {
UIModalPresentationFullScreen = 0,
UIModalPresentationPageSheet API_AVAILABLE(ios(3.2)) API_UNAVAILABLE(tvos),
UIModalPresentationFormSheet API_AVAILABLE(ios(3.2)) API_UNAVAILABLE(tvos),
UIModalPresentationCurrentContext API_AVAILABLE(ios(3.2)),
UIModalPresentationCustom API_AVAILABLE(ios(7.0)),
UIModalPresentationOverFullScreen API_AVAILABLE(ios(8.0)),
UIModalPresentationOverCurrentContext API_AVAILABLE(ios(8.0)),
UIModalPresentationPopover API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(tvos),
UIModalPresentationBlurOverFullScreen API_AVAILABLE(tvos(11.0)) API_UNAVAILABLE(ios) API_UNAVAILABLE(watchos),
UIModalPresentationNone API_AVAILABLE(ios(7.0)) = -1,
UIModalPresentationAutomatic API_AVAILABLE(ios(13.0)) = -2,
};

只是默认跳转方式变了,不再是全屏覆盖,而是这样的效果

ED25BBA2-7020-46F5-82B3-0C300798B22B

如果你觉得这个好看就不用修改了,如果需求必须是全屏就修改跳转方式即可

self.modalPresentationStyle = UIModalPresentationOverFullScreen;
self.modalPresentationStyle = UIModalPresentationCustom;

以上两个都可以

MPMoviePlayerController 在iOS 13已经不能用了

'MPMoviePlayerController is no longer available. Use AVPlayerViewController in AVKit.' 

既然不能再用了,那只能换掉了。替代方案就是AVKit里面的那套播放器。

iOS 13 DeviceToken有变化

1
2
3
4
5
NSString *dt = [deviceToken description];
dt = [dt stringByReplacingOccurrencesOfString: @"<" withString: @""];
dt = [dt stringByReplacingOccurrencesOfString: @">" withString: @""];
dt = [dt stringByReplacingOccurrencesOfString: @" " withString: @""];
这段代码运行在 iOS 13 上已经无法获取到准确的DeviceToken字符串了,iOS 13 通过[deviceToken description]获取到的内容已经变了。

iOS 13这样获取

1
2
3
4
5
6
7
8
9
10
- (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);
}

Sign in with Apple -提供第三方登录的注意啦

如果你的应用使用了第三方登录,那么你可能也需要加下 「Sign in with Apple」
Sign In with Apple will be available for beta testing this summer. It will be required as an option for users in apps that support third-party sign-in when it is commercially available later this year.

苹果审核指南中明确在4.8 Sign In With 中指明,使用第三方登录。
官方新闻

黑夜模式

目前是苹果推荐使用黑夜模式,试了一下iOS 13系统下面,切换黑夜模式之后,部分界面背景颜色直接变成黑色,非常不友好,到时候如果审核会审核黑夜模式下的APP应用页面
52531DAB-C35D-488C-9E39-AD80C6AEDDA0

代码中适配颜色(UIColor)

iOS 13SDK提供了一个新的API,colorWithDynamicProvider这个方法在xcode 10以下没有,xcode11才会有,所以要使用这个方法,必须更新xcode。

+ (UIColor *)colorWithDynamicProvider:(UIColor * (^)(UITraitCollection *))dynamicProvider API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);
- (UIColor *)initWithDynamicProvider:(UIColor * (^)(UITraitCollection *))dynamicProvider API_AVAILABLE(ios(13.0), tvos(13.0)) API_UNAVAILABLE(watchos);

用这个方法即可在两种模式下切换颜色,我直接创建一个UIColor+Collection分类来方便使用它
UIColor+Collection.h

1
2
3
4
/// 自定义颜色
/// @param drakValue 暗黑模式颜色 0x000000
/// @param LightValue 浅色模式颜色 0xffffff
+(UIColor *)customColorWithDarkMode:(NSUInteger)drakValue AndLightMode:(NSUInteger)LightValue;

UIColor+Collection.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
+(UIColor *)customColorWithDarkMode:(NSUInteger)drakValue AndLightMode:(NSUInteger)LightValue
{
UIColor *custom_color = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull traitCollection) {
if ([traitCollection userInterfaceStyle] == UIUserInterfaceStyleDark) {
return [self customColor:drakValue];
}
else{
return [self customColor:LightValue];
}
}];
return custom_color;
}
+(UIColor *)customColor:(NSUInteger)value{
return [UIColor colorWithRed:((float)((value & 0xFF0000) >> 16))/255.0
green:((float)((value & 0xFF00) >> 8))/255.0
blue:((float)(value & 0xFF))/255.0 alpha:1.0];
}

全局关闭黑暗模式

  1. 在Info.plist 文件中,添加UIUserInterfaceStyle key 名字为 User Interface Style 值为String

  2. UIUserInterfaceStyle key 的值设置为 Light

UISearchBar显示问题

  1. 升级到iOS13,UISearchController上的SearchBar显示异常,查看后发现对应的高度只有1px,目前没找到具体导致的原因,解决办法是使用KVO监听frame值变化后设置去应该显示的高度

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

    2019.11.08补:iOS 13.1.3 UISearchBar 背景色问题

    iOS 13 SearchBar背景色不修改默认白色 到13.1之后会默认透明 并且有点灰暗的感觉
    所以这里需要适配SearchBar的颜色,iOS 13之后获取SearchBar的背景色简单了许多,
    它有了searchTextField属性,我们可以直接调用这个属性获取backgroundColor,然后给他赋值颜色。

    searchVC.searchBar.searchTextField.backgroundColor = [UIColor whiteColor];

TabBar红点偏移

如果之前有通过TabBar上图片位置来设置红点位置,在iOS13上会发现显示位置都在最左边去了。遍历UITabBarButtonsubViews发现只有在TabBar选中状态下才能取到UITabBarSwappableImageView,解决办法是修改为通过UITabBarButton的位置来设置红点的frame

第三方友盟需要更新

此次适配iOS 13 只需升级common部分即可 具体更新查看友盟官网

个推

​个推SDK需要更新,具体更新内容查看个推官网(预计9月1日之后可以更新)

UISegmentedControl 默认样式改变

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

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

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

使用 @available 问题​

使用新的XCode SDK 工程的代码里面使用了 @available 判断当前系统版本,他总是弹出让你使用这个属性的问题,旧版本

if ([UIDevice currentDevice].systemVersion.floatValue >= 13.0) {
    ...
}

或者写个宏更方便

//判断 iOS 13
#define iOS13available ([UIDevice currentDevice].systemVersion.floatValue >= 13.0 ? YES : NO)

即将废弃的 LaunchImage

从 iOS 8 的时候,苹果就引入了 LaunchScreen,我们可以设置 LaunchScreen来作为启动页。当然,现在你还可以使用LaunchImage来设置启动图。不过使用LaunchImage的话,要求我们必须提供各种屏幕尺寸的启动图,来适配各种设备,随着苹果设备尺寸越来越多,这种方式显然不够 Flexible。而使用 LaunchScreen的话,情况会变的很简单, LaunchScreen是支持AutoLayout+SizeClass的,所以适配各种屏幕都不在话下。
注意啦⚠️,从2020年4月开始,所有使⽤ iOS13 SDK的 App将必须提供 LaunchScreen,LaunchImage即将退出历史舞台。

获取不到wifiSSID(wifi名)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Dear Developer,

As we announced at WWDC19, we're making changes to further protect user privacy and prevent unauthorized location tracking. Starting with iOS 13, the CNCopyCurrentNetworkInfo API will no longer return valid Wi-Fi SSID and BSSID information. Instead, the information returned by default will be:

SSID: “Wi-Fi” or “WLAN” (“WLAN" will be returned for the China SKU)
BSSID: "00:00:00:00:00:00"

If your app is using this API, we encourage you to adopt alternative approaches that don’t require Wi-Fi or network information. Valid SSID and BSSID information from CNCopyCurrentNetworkInfo will still be provided to VPN apps, apps that have used NEHotspotConfiguration to configure the current Wi-Fi network, and apps that have obtained permission to access user location through Location Services.

Test your app on the latest iOS 13 beta to make sure it works properly. If your app requires valid Wi-Fi SSID and BSSID information to function, you can do the following:
For accessory setup apps, use the NEHotSpotConfiguration API, which now has the option to pass a prefix of the SSID hotspot your app expects to connect to.
For other types of apps, use the CoreLocation API to request the user’s consent to access location information.

Learn more by reading the updated documentation or viewing the the Advances in Networking session video from WWDC19. You can also submit a TSI for code-level support.

Best regards,
Apple Developer Relations

苹果为了隐私安全,不让直接获取WiFi名字了,如果需要获取WiFi名字,需要获取地理位置信息,这个就去info.plist里面配置地理位置权限即可。

1
2
3
4
5
6
#import <CoreLocation/CoreLocation.h>

if (iOS13available && [CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
self.locationManager = [[CLLocationManager alloc] init];
[self.locationManager requestWhenInUseAuthorization];
}

UITabBarItem底部字体颜色push时改变

1
2
3
4
[[UITabBarItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor colorWithHexString:@"999999"]} forState:UIControlStateNormal];
[[UITabBarItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor colorWithHexString:@"cc0000"]} forState:UIControlStateSelected];
// 修复tabbar点击颜色问题,iOS 13 才出现的o((⊙﹏⊙))o
self.tabBar.tintColor = hlla(0xcc0000, 1.0);

原因可能是push时

self.hidesBottomBarWhenPushed = YES;

UIActivityIndicatorView加载视图

iOS13.1.3对UIActivityIndicatorView的样式也做了修改
以前默认是白色,iOS 13.1.3中会变成黑色

之前有三种样式:

  • UIActivityIndicatorViewStyleGray 灰色
  • UIActivityIndicatorViewStyleWhite 白色
  • UIActivityIndicatorViewStyleWhiteLarge 白色(大型)

iOS13废弃了以上三种样式,而用以下两种样式代替:

  • UIActivityIndicatorViewStyleLarge (大型)
  • UIActivityIndicatorViewStyleMedium (中型)

iOS13通过color属性设置其颜色

@property (nonatomic, strong) UIActivityIndicatorView * activityIndicator;

配置属性

self.activityIndicator = [[UIActivityIndicatorView alloc] init];
[self.view addSubview:self.activityIndicator];
//设置小菊花的frame
self.activityIndicator.frame= CGRectMake(100, 100, 100, 100);
//设置小菊花颜色
self.activityIndicator.color = [UIColor redColor];
//设置背景颜色
self.activityIndicator.backgroundColor = [UIColor cyanColor];
//刚进入这个界面会显示控件,并且停止旋转也会显示,只是没有在转动而已,没有设置或者设置为YES的时候,刚进入页面不会显示
self.activityIndicator.hidesWhenStopped = NO; 
-------------本文结束感谢您的阅读-------------