iOS13适配

随着iPhone 11的发布,iOS 13适配也提上了日程,刚好最近在做项目适配,顺便总结一下:
首先升级Xcode11,iOS13版本,因为Xcode11出现了一些新的API。废话不多说,直接上菜:

一、私有KVC

在iOS13中,不在允许通过KVC的方式去访问私有属性,需要通过其他方式去修改;之前如果使用到,会造成崩溃。

在网上看到有人说 私有KVC崩溃与系统版本无关,与Xcode版本有关,Xcode11编译会崩溃。
我个人觉得这个说法是错的;通过我的验证,我认为私有KVC在Xcode11---iOS12以下的系统不会崩溃,Xcode11---iOS13的会崩溃;大家也可以自己验证一下。

目前我找到的会触发 KVC 访问权限异常崩溃的方法有:

  • UITabBarButton -> _info
  • UITextField -> _placeholderLabel
  • _UIBarBackground -> _shadowView
  • _UIBarBackground -> _backgroundEffectView
  • UISearchBar -> _cancelButtonText
  • UISearchBar -> _cancelButton
  • UISearchBar -> _searchField

目前我项目中,主要用到UITextFieldUISearchBar的私有属性,现在我就拿这两个分析一下:

1、UITextFiled 修改根据kvc提示文字的大小和颜色,

这样写:

[self.onePwdField setValue:color_cccccc forKeyPath:@"_placeholderLabel.textColor"];

在Xcode11--iOS13会直接崩溃,修改方法为:

self.onePwdField.attributedPlaceholder = [self placeholder:@"请输入原来的密码"];

-(NSMutableAttributedString *)placeholder:(NSString *)text{
    if (text.length == 0) {
        return nil;
    }
    NSMutableAttributedString *att = [[NSMutableAttributedString alloc]initWithString:text attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15],NSForegroundColorAttributeName:color_cccccc}];
    return att;
}
2、获取UISearchBar的textField

在iOS13之前,我们通过"_searchField"来获取UISearchTextField来修改一些属性。

 UITextField *searchFiled = [self valueForKey:@"_searchField"];

在iOS13中,继续这样会崩溃,修改方法为:

 UITextField *searchFiled;
 if(@available(iOS 13.0, *)) {
    searchFiled =  self.searchTextField; 
 }else{
    searchFiled = [self valueForKey:@"_searchField"];
 }
3、UISearchBar 黑线处理导致崩溃

iOS13之前为了处理搜索框的黑线问题,通常会遍历 searchBar 的 subViews,找到并删除 UISearchBarBackground
在 iOS13 中这么做会导致 UI 渲染失败,然后直接崩溃,崩溃信息如下:

Terminating app due to uncaught exception'NSInternalInconsistencyException', reason: 'Missing or detached view for search bar layout'

修改方法为:设置 UISearchBarBackground 的 layer.contents 为 nil

 for (UIView *view in _searchBar.subviews.lastObject.subviews) {
   if ([view isKindOfClass:NSClassFromString(@"UISearchBarBackground")]) {
        view.layer.contents = nil;
        break;
    }
 } 
4、 设置UISearchBar 的searchTextField.attributedPlaceholder无效问题。

在 iOS13中需要把设置的代码写在viewDidAppear,亲测可以.

5、获取状态栏视图,以下两种方法在iOS13导致崩溃。
UIView *statusBar = [[UIApplication sharedApplication] valueForKey:@"statusBar"];
或:
UIView *statusBar = [[[UIApplication sharedApplication] valueForKey:@"statusBarWindow"] valueForKey:@"statusBar"];

改为:

if(@available(iOS 13.0, *)) {
        
}else{
    UIView *statusBar = [[UIApplication sharedApplication] valueForKey:@"statusBar"];
    statusBar.transform = CGAffineTransformIdentity;
}

二、presentViewController的问题(模态弹出默认样式改变)

在 iOS 13,使用 presentViewController 方式打开视图,会跟导航栏有部分视觉差,这里就不上图了,可以自行试一下。
原因是:苹果将 UIViewControllermodalPresentationStyle 属性的默认值改成了新加的一个枚举值 UIModalPresentationAutomatic,对于多数 UIViewController,此值会映射成 UIModalPresentationPageSheet

  • 解决办法: 可以在vc present之前设置modalPresentationStyle 为 UIModalPresentationFullScreen

  • 另外,present的vc用户下拉可以dissmiss控制器,如果不想要这效果,可以这样设置

/*当该属性为 false 时,用户下拉可以 dismiss 控制器,为 true 时,下拉不可以 dismiss控制器*/

xxVC.isModalInPresentation = true;
  • 还有一点需要注意,原来以UIModalPresentationFullScreen样式弹出页面,那么这个页面弹出 ViewController 会依次调viewWillDisappear和 viewDidDisappear。然后在这个页面被 dismiss 的时候,将他弹出的那个 ViewController 的 viewWillAppear 和 viewDidAppear会被依次调用。然而使用默认的视差效果弹出页面,将他弹出的那个 ViewController 并不会调用这些方法,原先写在这四个函数中的代码以后都有可能会存在问题。

三、蓝牙权限更新

在 iOS 13 中,苹果将原来蓝牙申请权限用的 NSBluetoothPeripheralUsageDescription 字段,替换为 NSBluetoothAlwaysUsageDescription 字段。

蓝牙权限.png

四、废弃UIWebview 改用 WKWebView

iOS13 开始苹果将 UIWebview 列为过期API(支持iOS2.0-iOS12)。 目前提交苹果应用市场(App Store)会发送邮件提示你在下一次提交时将应用中UIWebView 的 api 移除。

暂时没有强制使用WKWebView,但是在iOS13开始UIWebView已是废弃的API,以后更高的版本中防止出现问题,尽早移除是上上之策。

五、UISegmentedControl 默认样式改变。

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

六、WKWebView 中测量页面内容高度的方式变更

iOS 13以前 document.body.scrollHeight iOS 13中 document.documentElement.scrollHeight 两者相差55 应该是浏览器定义高度变了。

七、关于暗黑模式和切换

1、暗黑模式是iOS13的一大亮点,下面来看看模式切换的设置
(1) 切换 修改当前 UIViewController 或 UIView的模式。只要设置了控制器为暗黑模式,那么它子view也会对应的修改。

即:只会影响当前的视图,不会影响前面的 controller 和后续 present 的 controller。

if (@available(iOS 13.0, *)) {
   self.overrideUserInterfaceStyle =  UIUserInterfaceStyleDark;//UIUserInterfaceStyleLight
} else {
        // Fallback on earlier versions
}

注意啦⚠️,但是当我们在 window 上设置 overrideUserInterfaceStyle 的时候,就会影响 window 下所有的 controller, view,包括后续推出的 controller。

(2) 获取当前的模式
if (@available(iOS 12.0, *)) {
     if (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark ){
            // Dark
          NSLog(@"是dark模式、。。。");
     } else  if (self.traitCollection.userInterfaceStyle == UIUserInterfaceStyleLight) {
            // Light
          NSLog(@"是light模式、。。。");
     } else {
            //unspecified
          NSLog(@"是unspecified模式、。。。");
     }
}
(3) 监听模式的变化
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
    [super traitCollectionDidChange:previousTraitCollection];
// trait发生了改变
    if (@available(iOS 13.0, *)) {
        if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection]) {
            // 执行操作
        }
    } else {
        // Fallback on earlier versions
    }
}
2、适配暗黑模式
(1)将同一个资源,创建出两种模式的样式。系统根据当前选择的样式,自动获取该样式的资源
(2)每次系统更新样式时,应用会调用当前所有存在的元素调用对应的一些重新方法,进行重绘视图,可以在对应的方法做相应的改动。
(3)资源文件适配
  • 1.创建一个Assets文件(或在现有的Assets文件中)
    详情请看:iOS中创建多个Assets.xcassets文件
  • 2.新建一个图片资源文件(或者颜色资源文件、或者其他资源文件)
  • 3.选中该资源文件, 打开 Xcode ->View ->Inspectors ->Show Attributes Inspectors (或者Option+Command+4)视图,将Apperances 选项 改为Any,Dark
  • 4.执行完第三步,资源文件将会有多个容器框,分别为 Any Apperance 和 Dark Apperance. Any Apperance 应用于默认情况(Unspecified)与高亮情况(Light), Dark Apperance 应用于暗黑模式(Dark)
  • 5.代码默认执行时,就可以正常通过名字使用了,系统会根据当前模式自动获取对应的资源文件

注意啦⚠️,同一工程内多个Assets文件在打包后,就会生成一个Assets.car 文件,所以要保证Assets内资源文件的名字不能相同.

  • 步骤如图:
    资源文件适配暗黑模式.png
资源文件适配暗黑模式.png
3、全局关闭黑暗模式
  • 方式一 配置plist文件: 在Info.plist 文件中,添加UIUserInterfaceStyle key 名字为 User Interface Style 值为String,将UIUserInterfaceStyle key 的值设置为 Light。


    全局关闭黑暗模式.png

在开发中,如果用的系统控件(如cell、tableview的背景色)未设置背景色(或者为透明),则进入暗黑模式后,控件背景色变为黑色。

可以每一个页面设置,当然也可以整体设置, 一般我们的APP都是在一个window下的,那就整体设置APP里的window

  • 方式二 :代码关闭黑暗模式 强制关闭暗黑模式
#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
if(@available(iOS 13.0,*)){
    self.window.overrideUserInterfaceStyle = UIUserInterfaceStyleLight;
}
#endif
4、单个界面不遵循暗黑模式
  • UIViewController与UIView 都新增一个属性 overrideUserInterfaceStyle
  • 将 overrideUserInterfaceStyle 设置为对应的模式,则强制限制该元素与其子元素以设置的模式进行展示,不跟随系统模式改变进行改变

1、设置 ViewController 的该属性, 将会影响视图控制器的视图和子视图控制器采用该样式。
2、设置 View 的该属性, 将会影响视图及其所有子视图采用该样式。
3、设置 Window 的该属性, 将会影响窗口中的所有内容都采用样式,包括根视图控制器和在该窗口中显示内容的所有演示控制器(UIPresentationController)

更详细的暗黑模式设置请看:iOS适配暗黑模式

八、即将废弃的 LaunchImage(iOS 7.0–13.0)

从 iOS 8 的时候,苹果就引入了 LaunchScreen.storyboard,我们可以设置 LaunchScreen来作为启动页。当然,现在你还可以使用LaunchImage来设置启动图。不过使用LaunchImage的话,要求我们必须提供各种屏幕尺寸的启动图,来适配各种设备,随着苹果设备尺寸越来越多,这种方式显然不够 Flexible。而使用 LaunchScreen的话,情况会变的很简单, LaunchScreen是支持AutoLayout+SizeClass的,所以适配各种屏幕都不在话下。

注意啦⚠️,从2020年4月开始,所有使⽤ iOS13 SDK 的 App 将必须提供 LaunchScreen.storyboard,LaunchImage即将退出历史舞台,否则将无法提交到 App Store 进行审批。

九、StatusBar 与之前版本不同

目前状态栏也增加了一种模式,由之前的两种,变成了三种, 其中default由之前的黑色内容,变成了会根据系统模式,自动选择当前展示lightContent还是darkContent。

十、iOS13 获取window适配

    UIWindow* window = nil;
     
    if (@available(iOS 13.0, *)) {
        for (UIWindowScene* windowScene in [UIApplication sharedApplication].connectedScenes)
        {
           if (windowScene.activationState == UISceneActivationStateForegroundActive)
           {
                window = windowScene.windows.firstObject;
     
                break;
           }
        }
    }else{
        window = [UIApplication sharedApplication].keyWindow;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容

  • 1.私有KVC [self setValue:baseTabBar forKey:@"tabBar"]; //正常...
    小和大大阅读 794评论 0 1
  • 1.私有KVC 在Xcode10上编译不会有问题,但是在Xcode11上编译的会崩溃。并且- (void)setV...
    iOS亮子阅读 916评论 0 2
  • ios13 UISegmentedControl 的 setTintColor 属性失效, 新增了一个setSe...
    海利昂阅读 9,166评论 3 5
  • iOS13适配 1.私有KVC 在Xcode10上编译不会有问题,但是在Xcode11上编译的会崩溃。并且- (v...
    轻重缓急阅读 577评论 0 1
  • 1. 暗黑模式 iOS13使用暗黑模式时,UIView默认背景色会变成暗黑色。适配暗黑模式的工作量较大,改为强制使...
    大斌小姜阅读 6,108评论 0 3