因为各个应用市场要求,须要在 2019年5月1日 以前把 target 升级到 26。因此对本公司全网的 App 和可能影响到的相关 SDK 作一个升级。本文主要记录这次升级的过程和解决的一些问题。html
其实升级 target 技术含量不是很高,可是由于涉及到库(100 多个 SDK)和人员,依赖有点多,涉及到公司全部业务的 App, 并且改动的地方和细节也有多,很容易出现考虑不全,致使线上问题。android
主要过程为如下几步:git
由于公司的 App、组件、模块都是基于 target 22 和 support 24 进行开发的,因此要看下官方文档 releases/platforms 和 libraries/support-library 相关的文档,从中找到影响点。咱们受影响主要有 2 个方面:github
由于第一个权限问题是比较广泛的,因此应该有相关的开源项目支持,为了效率,咱们就不重复制造轮子。参考各个比较流行的开源方案,作了一下对比:工具
相关库 | 须要修改 Activity 或者 Fragment | 设置界面跳转 | 备注 | star 数 |
---|---|---|---|---|
AndPermission | 不须要 | 有, 能够参考 | 改动小 | 4911 |
Permissions4m | 须要 | 有,能够参考 | 改动多 | 1594 |
RxPermissions | 须要,不支持 Application 请求传入请求 | 无,须要本身实现 | 改动多 | 7911 |
FcPermissions | 须要,须要继承 FcPermissionsCallbacks | 无,须要本身实现 | 改动多 | 406 |
EasyPermission | 须要 | 无 | 改动多 | 7526 |
PermissionHelper | 须要继承 BasePermissionActivity | 无 | 改动多 | 1191 |
经过以上对比,咱们决定使用 AndPermission 的方案,由于这个对于咱们现有 App 的侵入是最少的,改动点比较少,并且支持 Appliction 传入(其实当使用 Application 传入时候,会有问题,后面再说)。测试
当时的考虑点是咱们公司不少 SDK 设计的时候是没有 Activity 的引用。可是咱们的 SDK, 基本有个 Application 这个引用的,因此选择了一个可以支持传入 Applicaiton 就可以判断权限回调的库。为何 AndPermission 可以支持呢?由于 AndPermission 在权限校验的时候会启动 PermissionActivity,而且加上了 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
,全部的权限请求都是在这个 PermissionActivity 处理,并且改动也比较少。优化
AndPermission 这个库的动态权限请求具体过程大伙能够看下 AndPermission 这个库的源码。使用方式以下:ui
从 API 调用来看是十分简单好用的。而后我又仔细看了一下它的实现过程,发现了有些不符合咱们产品需求的地方:.net
这样咱们就须要在 AndPermission 基础上进行改造,作出适合本身的动态权限库。咱们自定义了默认的 onDenied (申请权限失败后的回调)。 这样业务方就不须要关心失败后怎么提示了,只要关心成功后把以前的业务逻辑放到成功后这里执行就行了。权限申请失败提示框,用来启动一个 Activity 来 show 这个 Dialog,这样即便在前面传入的是 Application 的 context 也是没有问题了。对于屡次请求权限致使屡次弹框的问题,咱们在 AndPermission 的基础上添加的请求队列,只有上一个权限请求处理完成后,才进行下一次权限请求,这样的话,即便用户一次行为的方法链过程当中有不少次请求也不会屡次弹框。 而后当我用队列管理请求权限的时候,很怕某个权限阻塞了,或者出了未知异常,因此我对每次权限加入过程作了超时处理。以上几点是对于本身业务场景的几点考虑,进行的改造。插件
U51AndPermission SDK 已经生成了,那接下来就是怎么集成到各个 SDK 和 App 中了。首先咱们要知道,咱们的 App 哪些地方有可能调用到了须要权限请求的 API。若是要人工去看效率实在是过低了。咱们有 100 多个库,不可能把库看完且不出错。因此咱们使用了以前同事的一个插件去扫描相关的 API,用来定位到可能出现权限的类在哪里,用的是哪一个库。这样就提升了准确率和效率。
这个是咱们插件须要搜索的 API
如下是部分搜索结果
按照这种方法,咱们本须要处理 100 多个类库的,如今只有 20 个不到。一会儿少了 4 倍的工做量,并且相对准确。
不少 App 启动的时候须要一些必选权限的,咱们的 App 也是同样的,须要在 App 启动的时候验证一个必选权限。若是有必选权限,那么提示用户受权,若是不受权,那么就不可以继续使用咱们的产品了。因此进入 App 主要功能前,须要一个前置的拦截。考虑过 2 种方案:
方案1、在 Applicaiton 的 onCreate 方法中去申请必选权限,让启动 Activity 等待 Application 中权限申请好了,再用消息(EventBus) 通知 启动 Activity 继续走下去的流程
方案2、新建一个新的 启动 Activity,在这个 Activity 中作申请权限,申请完后再去启动以前老的启动 Activity
和对接的业务方讨论,他们选择了第一种方案, 这么作的缘由也是由于咱们不少 SDK 的初始化代码在 Appliction 中,咱们必需要在初始化 SDK 以前就应该把必要权限拿到。若是选择第二种,那么咱们的初始化代码须要移动到新的启动 Activity 中,这样改动风险有点高。
接入代码以下:
对接完后有几个咱们遇到的问题须要提下:
问题1、 由于在 App 启动的时候,若是没有必要权限,那么就会有弹框让用户设置权限,这时候用户点击 "设置",就会跳转到 App 设置权限页面,当用户受权回来的时候,有部分手机会出现黑屏。致使黑屏的缘由是 U51Permission 传入进去的 context 是 Application。若是是 Activity 就不会黑屏。因此解决方法是使用 Activity 去请求权限,回调方式是使用 Application.registerActivityLifecycleCallbacks
,以下:
问题2、 由于咱们有些逻辑是放到先后台切换的代码里面的,先后切换的主要用主要用到 Application.registerActivityLifecycleCallbacks
这个回调,根据 Activity 的生命周期统计来切换先后台(先后台的切换逻辑是使用统计 activity 的个数来实现的);因此 Application.registerActivityLifecycleCallbacks
这个操做应该是在 启动 Activity 以前就应该被注册。可是在申请必要权限的时候,我先启动 Activity 后再去注册这个 callback 的,因此致使启动 Activity 不在计算范围内,致使先后台的调用逻辑不许确,业务逻辑处理时机不对的问题。后来咱们使用一个本身的 registerActivityLifecycleCallbacks
,命名 MyActivityLifecycleCallbacks
,在 Application 一开始启动的时候就注册了,而后把后面其余须要注册的地方放到 MyActivityLifecycleCallbacks
中,由它统一通知其余须要先后台的回调。
替换以前
替换以后
能够看出来替换后改动代码不多,并且全部的先后台切换都会统一到本身的 MyActivityLifecycleCallbacks
里面进行集中管理。
还有其余相关问题,网上都可以找到,我就列举一下,你们本身注意一下就行了:
android.os.FileUriExposedException
的异常,文件共享的限制和第 1 条同样Sevices.startService
有些手机会奔溃,这个咱们的 App 以前就处理过了以上就是本次升级须要的修改点了,剩下的还有测试、灰度和正式上线。从整个适配过程来看,这个需求其实不是很难,可是从改动的点来讲,沟通协调能力要求仍是很高的,会涉及到大部分客户端开发、测试和产品。
对于改造升级大范围的基础库,每一个环节尽可能多思考和团队成员多讨论,切记不要一我的闷头就是干。但也不要过多的担忧,须要胆大心细,这样才能把事情推动下去。好了,target 28 的适配也立刻要来了。