iOS13适配
- 状态栏相关
获取状态栏:
if (@available(iOS 13.0, *)) {
UIView *_localStatusBar = [[UIApplication sharedApplication].keyWindow.windowScene.statusBarManager performSelector:@selector(createLocalStatusBar)];
UIView * statusBar = [_localStatusBar performSelector:@selector(statusBar)];
// 注意此代码不生效
// [statusBar drawViewHierarchyInRect:statusBar.bounds afterScreenUpdates:NO];
[statusBar.layer renderInContext:context];
} else {
// Fallback on earlier versions
}
- 控制器的 modalPresentationStyle 默认值变了:
UIModalPresentationStyle 新增加:UIModalPresentationAutomatic;
原来效果的模式:
self.modalPresentationStyle = UIModalPresentationFullScreen;
注意:当modalPresentationStyle = UIModalPresentationAutomatic
在关闭模态的时候,不会调用apper等方法。 - MPMoviePlayerController 在iOS 13更改为AVKit--->AVPlayerViewController
可参考链接 Demo - iOS 13 DeviceToken有变化‼️
(第三方推送都是将DeviceToken原始数据丢进去,具体的解析都是第三方内部处理)
/**************不规范的做法***********************/
NSString *dt = [deviceToken description];
dt = [dt stringByReplacingOccurrencesOfString: @"<" withString: @""];
dt = [dt stringByReplacingOccurrencesOfString: @">" withString: @""];
dt = [dt stringByReplacingOccurrencesOfString: @" " withString: @""];
/**************解决犯法(1)***********************/
NSMutableString *deviceTokenString = [NSMutableString string];
const char *bytes = deviceToken.bytes;
NSInteger count = deviceToken.length;
for (int i = 0; i < count; i++) {
[deviceTokenString appendFormat:@"%02x", bytes[i]&0x000000FF];
}
/**************解决犯法(2)友盟提供***********************/
- (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 (提供第三方登录的注意啦⚠️)
- 即将废弃的 LaunchImage-->launchScreen(AutoLayout+SizeClass)
再补充一点,在使用 LaunchScreen的时候,里面用到的图片资源,最好别放在 xcassets 里面,不然在你修改图片后,你会发现真机上并不会生效。 - 注意⚠️,iOS 13 通过 KVC 方式修改私有属性,有 Crash 风险,谨慎使用!
(1)UISearchBar的更改
/*******************使用代码*******************/
[self setValue:@"xxx " forKey:@"_cancelButtonText"];
/*******************更换成*******************/
- (void)set_cancelButtonText:(NSString *)text
(2)TextField的属性 _placeholderLabel 被禁止访问了------->attributedPlaceholder
/*******************使用代码*******************/
[_textField setValue:self.placeholderColor forKeyPath:@"_placeholderLabel.textColor"];
/*******************错误提示*******************/
'Access to UITextField's _placeholderLabel ivar is prohibited. This is an application bug ''
/*****************解决方案*********************/
NSMutableAttributedString * placeholderString = [[NSMutableAttributedString alloc] initWithString:placeholder attributes:@{NSForegroundColorAttributeName : self.placeholderColor}];
_textField.attributedPlaceholder = placeholderString;
/**************************************/
-
TabBar的一些改动,小红点问题
遍历UITabBarButton的subViews发现只有在TabBar选中状态下才能取到UITabBarSwappableImageView,解决办法是修改为通过UITabBarButton的位置来设置红点的frame。 -
黑线处理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.white
view.layer.contents = nil
break
}
}
}
- 黑夜模式:
UIColor *dynamicColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * provider) {
//使用 provider 判断,有时会出问题
if(keyWindow.isDark){
return darkColor;
}
return lightColor;
}];
- Xcode 11 缺失文件导入位置变更
Xcode11下 这个目录不存在了
/****************Xcode11的位置**********************/
/Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/
【变更为】
/Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/
以下位置不需要变动
/Applications/Xcode-beta.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/
/Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/lib/
/Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/lib/
12 .友盟分享 注册新浪平台 崩溃【验证:仅在模拟器上出现】
这个应该是需要微博官方进行适配了,尝试模拟了 getUniqueStrByUUID 中的相关写法,无果。
+[_LSDefaults sharedInstance] 崩溃问题
暂时的处理手段
@implementation NSObject (Extend)
+ (void)load{
SEL originalSelector = @selector(doesNotRecognizeSelector:);
SEL swizzledSelector = @selector(sw_doesNotRecognizeSelector:);
Method originalMethod = class_getClassMethod(self, originalSelector);
Method swizzledMethod = class_getClassMethod(self, swizzledSelector);
if(class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))){
class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}else{
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
+ (void)sw_doesNotRecognizeSelector:(SEL)aSelector{
//处理 _LSDefaults 崩溃问题
if([[self description] isEqualToString:@"_LSDefaults"] && (aSelector == @selector(sharedInstance))){
//冷处理...
return;
}
[self sw_doesNotRecognizeSelector:aSelector];
}
13 . window 变更问题
在iOS13版本下,App 任意处生成YYTextView均会导致全局的scrollsToTop 回顶功能失效。最终追溯到YYTextEffectWindow类。
-[UICollectionView scrollViewShouldScrollToTop:]
-[UIScrollView _scrollToTopIfPossible:] ()
-[UIScrollView _scrollToTopFromTouchAtScreenLocation:resultHandler:] ()
-[UIWindow _scrollToTopViewsUnderScreenPointIfNecessary:resultHandler:]_block_invoke.796 ()
-[UIWindow _handleScrollToTopAtXPosition:resultHandler:] ()
//此处能看到有个新鲜的 UIStatusBarManager 是iOS13新增的类,可以看到状态栏的点击事件已经被其接管了。
//经过实践,出问题的时候该方法也能被正常调用故此排上以上调用栈方法。
-[UIStatusBarManager _handleScrollToTopAtXPositi
开始以为是多个UIScrollView共存时scrollsToTop的设置问题,还有UIScrollViewContentInsetAdjustmentNever的设置问题。结果都不是...
最终沿着UIScrollView 子类一直查找,找到了YYTextView 其中用到的 YYTextEffectWindow也进入了视野...
> static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (![UIApplication isAppExtension]) {
one = [self new];
one.frame = (CGRect){.size = kScreenSize};
one.userInteractionEnabled = NO;
//此处能看到 窗口等级是高于状态栏的,但多次尝试等级调整均无果。
one.windowLevel = UIWindowLevelStatusBar + 1;
//元凶在这里
//所以,即使关闭了用户交互 但是它竟能够阻挡状态栏的事件,但却对常规Window的事件无任何影响...
if (@available(iOS 13.0, *)) {
//费解的结果...
one.hidden = YES;
}else{
one.hidden = NO;
}
// for iOS 9:
one.opaque = NO;
one.backgroundColor = [UIColor clearColor];
one.layer.backgroundColor = [UIColor clearColor].CGColor;
}
});
return one;
在UIWindow 上使用addSubview添加子视图,需要注意 暗黑模式切换,并不会向子视图下发状态变更。
解决办法:
获取系统暗黑切换通知(自行实现),然后重写添加到 UIWindow 的子视图 overrideUserInterfaceStyle 为正确的状态。
- UIScrollView 滚动条异常偏移
屏幕旋转可能会触发系统对滚动条的自动修正
如果没有修改需求,关闭该特性即可
/*******************代码***********************/
#ifdef __IPHONE_13_0
if (@available(iOS 13.0, *)) {
self.automaticallyAdjustsScrollIndicatorInsets = NO;
}
#endif
- UICollectionView 异常API
该API 在iOS13下会强制将cell置中,导致上部留白。
推测,底部应该也会有留白的情况。
#pragma mark - 修复iOS13 下滚动异常API
#ifdef __IPHONE_13_0
- (void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated{
[super scrollToItemAtIndexPath:indexPath atScrollPosition:scrollPosition animated:animated];
//修复13下 图片滚动位置异常
//顶部
if(self.contentOffset.y < 0){
[self setContentOffset:CGPointZero];
return;
}
//底部
if(self.contentOffset.y > self.contentSize.height){
[self setContentOffset:CGPointMake(0, self.contentSize.height)];
}
}
#endif
- UITableViewCell 异常 【疑似iOS13beta4新出现】[marson 失效问题]
[self addSubView: viewObjA]
[self.contentView addSubview:viewObjB]
上面两种方式,在遇到折叠需求时。设置self.clipsToBounds=YES 可能会有布局异常
//保险的做法
self.clipsToBounds = YES; 【无效】
//此处很费解
self.layer.masksTobounds = YES; 【有效】
疑似布局引擎机制有调整 【有待确定】
在调试中发现,如果代码流是这样一种状态 可能会造成 【约束失效】
如果遇到诡异问题 需要排查下是否存在约束和绝对布局混用的情况
[viewMain addSubView:viewA];
[viewMain addSubView:viewB];
// 更新 viewA 的约束
[self.imageBackground mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(50);
}];
//立即更新约束
[viewA.superview setNeedsUpdateConstraints];
[viewA.superview updateConstraintsIfNeeded];
[viewA.superview layoutIfNeeded];
//更新容器约束
[viewMain mas_updateConstraints:^(MASConstraintMaker *make) {
make....
}];
....
其它处理逻辑
....
// 更新 viewA 的约束 【代码不会生效】
[self.imageBackground mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(100);
}];
- WKWebView 暗黑适配
要点:
模式参数通过 UA 传递
联调中出现加载闪白问题
webView.opaque = false;
- 手势影响
iOS13下,如果在UITextView上附加如拖动手势,会发现如果触点落在UITextView之上极易触发第一响应者。
实际效果,可对比iOS12之前版本的表现。
** 注意这两项即使开启也不会有改善效果**
gesture.cancelsTouchesInView = YES;
gesture.delaysTouchesBegan = YES;
-
NSMonthCalendarUnit 更改为 NSCalendarUnitMonth 的使用;
-
UISegmentedControl中tintColor失效问题:
之前的我们设置 tintColor 去除选择颜色以及背景色,在 iOS13 中失效了。
解决方案:
(1)selectedSegmentTintColor 设置 选中的颜色,只是更改选中的颜色。
(2) 去除背景色以及选中的颜色
#import "UISegmentedControl+Commen.h"
@implementation UISegmentedControl (Commen)
-(void)tintColorDidChange{
// UISegmentedControl has changed in iOS 13 and setting the tint
// color now has no effect.
if (@available(iOS 13, *)) {
UIColor * tintColor = [self tintColor];
UIImage *tintColorImage = [self imageWithColor:tintColor];
// Must set the background image for normal to something (even clear) else the rest won't work
[self setBackgroundImage:[self imageWithColor:self.backgroundColor ? self.backgroundColor : [UIColor clearColor]] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[self setBackgroundImage:tintColorImage forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[self setBackgroundImage:tintColorImage forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
[self setDividerImage:tintColorImage forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
}
}
- (UIImage *)imageWithColor: (UIColor *)color {
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, self.frame.size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return theImage;
}
@end
总结
以上是我在实际的适配中的遇到的问题,其他的问题,暂未发现。该文章会在实际工作中的持续更新,尽情期待吧...