热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

iosiphonex适配

一、前言iOS11发布也有一段时间了,每次版本升级,相关的适配工作当然是下个版本的核心工作之一。而且这次iOS11的更新,相对于iOS1

一、前言

iOS11发布也有一段时间了,每次版本升级,相关的适配工作当然是下个版本的核心工作之一。而且这次iOS11的更新,相对于iOS10的更新来说,改动点还是比较多的。除了iOS11系统的更新之外,iPhoneX刘海的打理工作也是必不可少。以前我们总是庆幸作为iOS开发者,不必像Android开发者需要考虑各种不同机型的适配问题。但是现在,随着iPhone各种历史版本的存在,各种花式的新版本产生,不同版本之间的适配问题,也是未来我们作为iOS开发者必然要考虑的重要问题之一。

这次我主要负责我们这边两款App(滴滴代驾司机端+驾管App)iOS11&iPhoneX适配工作。中间也躺过很多坑,一一记录了下来写成这篇文章,既是对自己工作的一次总结,也可以分享给其他iOS开发者,能够让大家少趟一些坑。

本文将分为三个部分,分别从三方库适配、UI适配、权限适配、补充知识等方面分别进行展开。

二、三方库适配问题。

2.1 CocoaLumberjack 编译出错

1.png

 

CocoaLumberjack编译报错

问题原因:

从错误提示可以看出在Xcode9中os_log_error的第二个参数format必须要为不可变的string类型,而不是char*。

解决方案:

我们只要改成如下形式就可以了


1

os_log_error(OS_LOG_DEFAULT, "%s", msg);

CocoaLumberjack的作者也在[issue883](https://github.com/Co coaLumberjack/CocoaLumberjack/issues/883)中解决了该问题。如果你的工程是pod依赖的话,将pod版本升级到3.3.0版本即可。

2.2 WebViewJavascriptBridge崩溃处理

我们代驾司机端web容器使用的是WKWebView,jsBridge使用的是WebViewJavascriptBridge这个三方库,更新到Xcode9之后,只要进入WKWebView容器,就会产生如下crash:

1.png

 

WebViewJavascriptBridge crash

问题原因:

当你使用WKWebView作为你的H5容器的时候,WKNavigationDelegate有个回调就是


1

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;

这个回调主要负责根据webView、navigationAction相关信息决定这次跳转是否可以继续进行。调用decisionHandler(WKNavigationActionPolicyAllow);响应这次跳转请求。调用decisionHandler(WKNavigationActionPolicyCancel);就是不响应这次跳转请求。

查看WebViewJavascriptBridge源码可以看出,在WKWebViewJavascriptBridge.m文件中

1.png

 

WKVebViewCrash.png

在Xcode9中,如果连续看了两次调用decisionHandler方法就会crash。这个问题在之前版本的Xcode均是没有问题的。

解决方案:


  • 方案一:修改源码

    在上面代码的149行和150行之间添加return;

  • 方案二:pod依赖,原作者没有修改此问题,无法修改源码,也可以在业务代码中进行规避。

    在你自己业务代码的对应对调中添加排除代码,如下:

 

1.png

WKWebViewCrash2.png

2.3 LumberjackConsole UI适配

1.png

 

问题原因:

iOS7之后,如何你设置self.edgesForExtendedLayout = UIRectEdgeNone的话,系统通过设置UIViewController的automaticallyAdjustsScrollViewInsets属性来自动调整UIScrollView的contentInset,使UIscrollView能够呈现在我们的可是范围之内,而不会被navBar挡住。这个属性在iOS11中被废弃掉了,在iOS11中代替该属性功能的则是UIScrollView类中的contentInsetAdjustmentBehavior和adjustedContentInset属性.在iOS11中用来决定scrollView超出安全区域与边缘距离的属性是adjustedContentInset而不是contentInset。当scrollView超出安全区域时系统会自动调整SafeAreaInsets值,进而影

响 adjustedContentInset,所以导致scrollView下移20pt或者64pt。当使用自定义的 navigationbar,并且scrollView的frame超出安全区域,SafeAreaInsets为(20,0,0,0);当使用系统的navigationbar,SafeAreaInsets为(64,0,0,0)。

解决方案:

在UIScrollView或者UITableView初始化的地方,加入如下代码即可。

针对LumberjackConsole这个开源库,我们可以在PTEConsoleTableView.m文件中的commonInit最后加入如下代码即可。

 


1

2

3

if([self respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]){

      [self setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];

}

三、UI适配

3.1 NavBar中右上角的customView产生偏移

1.png

 

问题原因:

在iOS11中,新的导航视图,使用了AutoLayout布局。而我们这边右上角的两个按钮组合成一个customView,然后把这个customView设置给setRightBarButtonItems而来。customView内部都是frame布局,所以在自动布局下面出错。

解决方案:

NavBar中的customView里面针对iOS11,均要采用自动布局。

1.png

3.2 NavBar中自定义TitleView产生偏移

1.png

问题原因:

同上

解决方案:

同上

这里需要注意一点,自动布局的UI是延迟设置frame的。如果aView采用自动布局。然后你马上调用它的aView.bounds是不正确的。

3.3 NavBar中按钮的响应区域都变小了。

1.png

问题原因:

iOS11之前,虽然我们设置了NavBar上每一个[btn sizeToFit]。苹果依然会帮我们把每一个按钮的点击区域扩大,可以点击区域如上图绿色区域所示。但是在iOS11中,你的按钮的bounds为多大,那你的点击区域就只有多大。估计这个改动也与这次NavBar的大概有关系。

解决方案:

扩大每一个btn的bounds,而不要使用sizeToFit方法。

3.4 NavBar的BarButtonItem无法贴边。有(非plus手机16pt,plus手机20pt)的区域浪费。造成UI偏移,并且最左侧和最右侧区域无法点击。

1.png

问题原因:

这个UINavigationBarContentView平铺在导航栏中作为iOS11的各个按钮的父视图,该视图的所有的子视图都会有一个layoutMargins被占用,也就是系统调整的占位。

解决方案:

去掉系统默认占位。

系统并没有提供我们直接去掉系统默认占位的方法,那怎么做呢?

我们新建一个UINavigationBar的分类,hook住UINavigationBar的layoutSubviews方法。然后遍历View,重新设置layoutMargin约束。

1.png

重新设置layoutMargin约束

3.5 UITableView 默认开启Self-Sizing,导致UI显示有问题。

1.png

问题原因:

在iOS11中UITableView会默认使 Self-Sizing,这会导致tableView

的 estimatedRowHeight 、 estimatedSectionHeaderHeight 、 estimatedSectionFooterHeight 的高度估算属性由默认的0变成 UITableViewAutomaticDimension ,reloadData时可能会导致最后显示的contentSize与预想的不一致;

同时在iOS11中如果不实现 -tableView: viewForHeaderInSection: 和 tableView: viewForFooterInSection: 方法,则 -tableView: heightForHeaderInSection: 和 - tableView: heightForFooterInSection: 不会被调用,而iOS11之前则没问题。上述都可能会导致界面出现错乱。

解决方案:

单独关闭摸一个UITableView的Self-Sizing。


1

2

3

    _tableView.estimatedRowHeight = 0.;

    _tableView.estimatedSectionFooterHeight = 0.;

    _tableView.estimatedSectionHeaderHeight = 0.;

关闭所有的UIScroolView、UITableView和UICollectionView的Self-Sizing:


1

2

3

4

   UIScrollView.appearance.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;

   UITableView.appearance.estimatedRowHeight = 0;

   UITableView.appearance.estimatedSectionFooterHeight = 0;

   UITableView.appearance.estimatedSectionHeaderHeight = 0;

3.6 keyWindow获取错误, 导致UI问题。

1.png

问题原因:

机器猫图标是一个UIWindow,windowLevel级别比UIWindowLevelStatusBar还高,所以可以常驻UI最上方。第一次进入该页面,点击“更多”,弹出popView,点击收藏,弹出系统UIAlertView,此时UIAlertView变成了keyWindow。当UIAlertView消失的时候,keyWindow会被谁接管呢?

iOS11之前,弹出UIAlertView之前的keyWindow是[[UIApplication sharedApplication].delegate window],那么消失的时候,keyWindow还是[[UIApplication sharedApplication].delegate window]。

iOS11, 弹出UIAlertView之前的keyWindow是[[UIApplication sharedApplication].delegate window],那么消失的时候,keyWindow变成z轴最高的UIWindow,即变成了机器猫那个window。所以导致popView被添加到机器猫window中,造成UI样式问题。

解决方案:

重写自定义UIWindow的becomeKeyWindow的方法,每次自定义window将会变为keyWindow的时候,把keyWindow改成[[UIApplication sharedApplication].delegate window]。

 


1

2

3

4

- (void)becomeKeyWindow{

    UIWindow *appWindow = [[UIApplication sharedApplication].delegate window];

    [appWindow makeKeyWindow];

}

3.7 状态栏高度写死为20pt,导致在iPhoneX上面遮挡住statusBar。

1.png

问题原因:

iPhoneX上的statusBar的高度为44pt,跟其他iPhone型号的20pt不一样。所以以后我们在以statusBar为定位点的时候,不能写死20pt。而要使用[UIApplication sharedApplication].statusBarFrame.size.height来获取,为了方便,可以定义为宏,放到pch文件中,如下:


1

#define kApplicationStatusBarHeight  [UIApplication sharedApplication].statusBarFrame.size.height //状态栏的高度

解决方案:

状态栏高度定位的时候不要写死20,要使用[UIApplication sharedApplication].statusBarFrame.size.height来获取。

补充

iOS11之前导航栏默认高度为64pt(这里高度指statusBar + NavigationBar),iOS11之后如果设置 prefersLargeTitles = YES则为96pt,默认情况下还是64pt,但在iPhoneX上由于刘海的出现 statusBar由以前的20pt变成 44pt,所以iPhoneX上高度变为88pt,如果项目里隐藏了导航栏加了自定义按钮之类的,这里需要注意适配一下。

3.8 通过遍历statusBar的subviews中的UIStatusBarDataNetworkItemView获取网络状态在iPhoneX上会crash。

问题原因:

之前我们采用遍历statusBar,获取UIStatusBarDataNetworkItemView实例,再获取网络状态的。代码如下:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

+ (NSNumber *) dataNetworkTypeFromStatusBar {

    UIApplication *app = [UIApplication sharedApplication];

    NSArray *subviews = [[[app valueForKey:@"statusBar"] valueForKey:@"foregroundView"] subviews];

    NSNumber *dataNetworkItemView = nil;

     

    @try {

        if ([subviews count] > 0) {

            for (id subview in subviews) {

                if([subview isKindOfClass:[NSClassFromString(@"UIStatusBarDataNetworkItemView"class]]) {

                    dataNetworkItemView = subview;

                    break;

                }

            }

        }

    }

    @catch (NSException *exception) {

    }

    @finally {

    }

     

    return [dataNetworkItemView valueForKey:@"dataNetworkType"];

}

但是在iphoneX的statusBar的内部结构已经改变,不能根据遍历获取UIStatusBarDataNetworkItemView的状态获取网络状态状态。

可以通过po [statusBar recursiveDescription]打印出来iphoneX内部结构了,可以看出变化非常的大。

解决方案:

使用AFNetworking中的AFNetworkReachabilityManager类,或者使用Reachability库获取网络连接状态。

四、权限适配

4.1 无法获取定位信息,第一次打开app也无法弹出定位权限提示框

问题原因:

iOS11 定位相关的权限做了更改,在iOS11上使用了新的定位权限key。

解决方案:

如果原来申请的权限是始终允许NSLocationAlwaysUsageDescription,那么需要在保留原来的key的基础上增加NSLocationWhenInUseUsageDescription和NSLocationAlwaysAndWhenInUsageDescription。

五、其他一些补充

5.1 如何判断该设备是不是iPhoneX

1.png

5.2 一些常用的宏定义


1

2

3

4

5

#define IS_IPHONE_X [KDDeviceHelper is_iPhone_X]

#define IPHONE_NAVIGATIONBAR_HEIGHT  (IS_IPHONE_X ? 88 64)

#define IPHONE_STATUSBAR_HEIGHT      (IS_IPHONE_X ? 44 20)

#define IPHONE_SAFEBOTTOMAREA_HEIGHT (IS_IPHONE_X ? 34 0)

#define IPHONE_TOPSENSOR_HEIGHT      (IS_IPHONE_X ? 32 0)

六、参考文献


推荐阅读
  • React基础篇一 - JSX语法扩展与使用
    本文介绍了React基础篇一中的JSX语法扩展与使用。JSX是一种JavaScript的语法扩展,用于描述React中的用户界面。文章详细介绍了在JSX中使用表达式的方法,并给出了一个示例代码。最后,提到了JSX在编译后会被转化为普通的JavaScript对象。 ... [详细]
  • 本文总结了Java中日期格式化的常用方法,并给出了示例代码。通过使用SimpleDateFormat类和jstl fmt标签库,可以实现日期的格式化和显示。在页面中添加相应的标签库引用后,可以使用不同的日期格式化样式来显示当前年份和月份。该文提供了详细的代码示例和说明。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文介绍了Java的集合及其实现类,包括数据结构、抽象类和具体实现类的关系,详细介绍了List接口及其实现类ArrayList的基本操作和特点。文章通过提供相关参考文档和链接,帮助读者更好地理解和使用Java的集合类。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了腾讯最近开源的BERT推理模型TurboTransformers,该模型在推理速度上比PyTorch快1~4倍。TurboTransformers采用了分层设计的思想,通过简化问题和加速开发,实现了快速推理能力。同时,文章还探讨了PyTorch在中间层延迟和深度神经网络中存在的问题,并提出了合并计算的解决方案。 ... [详细]
  • IT方面的论坛太多了,有综合,有专业,有行业,在各个论坛里混了几年,体会颇深,以前是论坛哪里人多 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • C++语言入门:数组的基本知识和应用领域
    本文介绍了C++语言的基本知识和应用领域,包括C++语言与Python语言的区别、C++语言的结构化特点、关键字和控制语句的使用、运算符的种类和表达式的灵活性、各种数据类型的运算以及指针概念的引入。同时,还探讨了C++语言在代码效率方面的优势和与汇编语言的比较。对于想要学习C++语言的初学者来说,本文提供了一个简洁而全面的入门指南。 ... [详细]
author-avatar
安安1
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有