性能优化之合并多个FileProvider_android 移除第三方sdk中注册的contentprovider(1)

  1. 实现Initializer组件
  2. AndroidManifest文件添加声明

4.1 添加依赖

4.2 实现Initializer组件

实现Initializer接口要求重写两个方法:

  1. create()方法中,我们可以把原先在ContentProvider中初始化的代码,放在这里。
  2. dependencies()方法表示当前初始化,是否依赖其它的Initializer组件,如果依赖的话,会先初始化它们。

4.3 AndroidManifest文件添加声明

使用还是蛮简单的。更多信息请查看官方文档。developer.android.com/topic/libra…

4.4 移除第三方sdk中存在的ContentProvider

假设第三方sdk的AndroidManifest文件中声明了一个名叫ShareContentProvider的Provider

要移除它,需要在app项目中的AndroidManifest中声明一个相同的Provider,并加上tools:node=“remove”。

5. FileProvider浅析

5.1 从调用安装界面讲起

  • Android6.0以及之前版本安装apk代码如下

  • Android7.0+安装apk代码如
  1. 自定义FileProvider

2. AndroidManifest文件中注册FileProvider

  1. res/xml文件夹新建toutiao.xml文件

  1. 调用安装程序

我们可以看到它们的区别在于分别使用Uri.fromFile()和FIleProvider.getUriFromFile()获取文件的Uri。

打印结果对应的值如下表:

方式
Urifile:///storage/emulated/0/toutiao/toutiao.apk
FileProvidercontent://com.toutiao.install/bytedance/toutiao.apk

Uri方式获取到的文件路径很容易被猜出文件所在位置,这样暴露给第三方程序,可能会带来风险。而FileProvider获取到的文件路径就不容易暴露文件所在位置。引入FileProvider机制的原因就是为安全考虑。

5.2 xml的tag对应的文件存储位置

下图表示各种tag对应的文件路径

NAMEVALUEPATH
TAG_ROOT_PATHroot-path/
TAG_FILES_PATHfiles-path/data/user/0/com.xxx/files
TAG_CACHE_PATHcache-path/data/user/0/com.xxx/cache
TAG_EXTERNALexternal-path/storage/emulated/0
TAG_EXTERNAL_FILESexternal-files-path/storage/emulated/0/Android/data/com.xxx/files
TAG_EXTERNAL_CACHEexternal-cache-path/storage/emulated/0/Android/data/com.xxx/cache

5.3 xml中Uri和路径的映射表

  1. FileProvider的sCache

FileProvider有一个静态变量sCache。key存放的是FileProvider的authority,value存放的PathStrategy代表的是FileProvider对应的xml中的内容。

  1. SimplePathStrategy的mRoots

mRoots也是hashMap,key对应的是xml中的name节点。value对应的是tag+path的组合。

<files-path name="apk" path="."/>
复制代码

key: apk

value: /data/user/0/com.xxx/files

sCache和mRoots对应关系如下图:

5.4 FileProvider解析xml过程

  1. FileProvider自动安装后调用attachInfo
  2. 调用parsePathStrategy解析xml
  3. getPathStrategy方法将解析的PathStrategy放入sCache

6. 合并FileProvider

合并FileProvider,我们需要将第三方sdk定义的FileProvider从AndroidManifest文件中移除掉。但是这样做我们将面临两个问题。

  1. xml中的Uri和文件路径映射无法写入到FileProvider的sCache中
  2. 进程间文件共享,是通过寻找到Uri中的authority对应的ContentProvider。调用它的openFile方法实现的,如果不声明ContentProvider会导致文件共享失败

解决方案如下:

  1. 通过反射,将xml中各项映射,硬编码的方式写入到FileProvider的sCache中
  2. 定义一个中转ContentProvider,将它声明在AndroidManifest文件中,接管所有FileProvider的openFile方法
  3. 通过Aspect插桩方式,将所有FileProvider的getUriForFile()返回的Uri的authority hook成中转ContentProvider的authority

6.1 反射硬编码写入映射

  1. 通过反射将映射关系写入sCache中

  1. 将本应该AndroidManifest中注册的FileProvider的authority信息和xml信息硬编码注册到sCache中

6.2 定义中转ContentProvider

authorities是com.peter.dispatch。主要是中转作用

6.3 Aspect hook authority

6.3.1 根目录build.gradle添加aspectjx

6.3.2 app/build.gradle应用Aspect插件

6.3.3 hook FileProvider.getUriFromFile

将 content://com.toutiao.install/bytedance/toutiao.apk

转换成

content://com.peter.dispatch/com.toutiao.install/bytedance/toutiao.apk

6.3.4 重写中转CP的openFile

最后

针对Android程序员,我这边给大家整理了一些资料,包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

  • Android前沿技术大纲

  • 全套体系化高级架构视频

Android高级架构资料、源码、笔记、视频。高级UI、性能优化、架构师课程、混合式开发(ReactNative+Weex)全方面的Android进阶实践技术,群内还有技术大牛一起讨论交流解决问题。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

roid进阶实践技术,群内还有技术大牛一起讨论交流解决问题。**

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 19
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值