iOS13适配

2019-09-29  本文已影响0人  荷码人生
  1. 状态栏相关
    获取状态栏:
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
}
  1. 控制器的 modalPresentationStyle 默认值变了:
    UIModalPresentationStyle 新增加:UIModalPresentationAutomatic;
    原来效果的模式:
    self.modalPresentationStyle = UIModalPresentationFullScreen;
    注意:当modalPresentationStyle = UIModalPresentationAutomatic
    在关闭模态的时候,不会调用apper等方法。
  2. MPMoviePlayerController 在iOS 13更改为AVKit--->AVPlayerViewController
    可参考链接 Demo
  3. 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);
}
  1. Sign in with Apple (提供第三方登录的注意啦⚠️)
  2. 即将废弃的 LaunchImage-->launchScreen(AutoLayout+SizeClass)
    再补充一点,在使用 LaunchScreen的时候,里面用到的图片资源,最好别放在 xcassets 里面,不然在你修改图片后,你会发现真机上并不会生效。
  3. 注意⚠️,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;
/**************************************/
  1. TabBar的一些改动,小红点问题
    遍历UITabBarButton的subViews发现只有在TabBar选中状态下才能取到UITabBarSwappableImageView,解决办法是修改为通过UITabBarButton的位置来设置红点的frame。

  2. 黑线处理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
            }
        }
    }
  1. 黑夜模式:
UIColor *dynamicColor =  [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * provider) {
        //使用 provider 判断,有时会出问题
        if(keyWindow.isDark){
            return darkColor;
        }
        return lightColor;
}];
  1. 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 为正确的状态。

  1. UIScrollView 滚动条异常偏移
    屏幕旋转可能会触发系统对滚动条的自动修正
    如果没有修改需求,关闭该特性即可
/*******************代码***********************/
#ifdef __IPHONE_13_0
        if (@available(iOS 13.0, *)) {
            self.automaticallyAdjustsScrollIndicatorInsets = NO;
        }
#endif
  1. 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
  1. 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);
 }];
  1. WKWebView 暗黑适配
    要点:
    模式参数通过 UA 传递
    联调中出现加载闪白问题
 webView.opaque = false;
  1. 手势影响
    iOS13下,如果在UITextView上附加如拖动手势,会发现如果触点落在UITextView之上极易触发第一响应者。
    实际效果,可对比iOS12之前版本的表现。

** 注意这两项即使开启也不会有改善效果**
gesture.cancelsTouchesInView = YES;
gesture.delaysTouchesBegan = YES;

  1. NSMonthCalendarUnit 更改为 NSCalendarUnitMonth 的使用;

  2. 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

总结
以上是我在实际的适配中的遇到的问题,其他的问题,暂未发现。该文章会在实际工作中的持续更新,尽情期待吧...

上一篇下一篇

猜你喜欢

热点阅读