- 实现Initializer组件
- AndroidManifest文件添加声明
4.1 添加依赖
4.2 实现Initializer组件
实现Initializer接口要求重写两个方法:
- create()方法中,我们可以把原先在ContentProvider中初始化的代码,放在这里。
- 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代码如
- 自定义FileProvider
2. AndroidManifest文件中注册FileProvider
- res/xml文件夹新建toutiao.xml文件
- 调用安装程序
我们可以看到它们的区别在于分别使用Uri.fromFile()和FIleProvider.getUriFromFile()获取文件的Uri。
打印结果对应的值如下表:
方式 | 值 |
---|---|
Uri | file:///storage/emulated/0/toutiao/toutiao.apk |
FileProvider | content://com.toutiao.install/bytedance/toutiao.apk |
Uri方式获取到的文件路径很容易被猜出文件所在位置,这样暴露给第三方程序,可能会带来风险。而FileProvider获取到的文件路径就不容易暴露文件所在位置。引入FileProvider机制的原因就是为安全考虑。
5.2 xml的tag对应的文件存储位置
下图表示各种tag对应的文件路径
NAME | VALUE | PATH |
---|---|---|
TAG_ROOT_PATH | root-path | / |
TAG_FILES_PATH | files-path | /data/user/0/com.xxx/files |
TAG_CACHE_PATH | cache-path | /data/user/0/com.xxx/cache |
TAG_EXTERNAL | external-path | /storage/emulated/0 |
TAG_EXTERNAL_FILES | external-files-path | /storage/emulated/0/Android/data/com.xxx/files |
TAG_EXTERNAL_CACHE | external-cache-path | /storage/emulated/0/Android/data/com.xxx/cache |
5.3 xml中Uri和路径的映射表
- FileProvider的sCache
FileProvider有一个静态变量sCache。key存放的是FileProvider的authority,value存放的PathStrategy代表的是FileProvider对应的xml中的内容。
- 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过程
- FileProvider自动安装后调用attachInfo
- 调用parsePathStrategy解析xml
- getPathStrategy方法将解析的PathStrategy放入sCache
6. 合并FileProvider
合并FileProvider,我们需要将第三方sdk定义的FileProvider从AndroidManifest文件中移除掉。但是这样做我们将面临两个问题。
- xml中的Uri和文件路径映射无法写入到FileProvider的sCache中
- 进程间文件共享,是通过寻找到Uri中的authority对应的ContentProvider。调用它的openFile方法实现的,如果不声明ContentProvider会导致文件共享失败
解决方案如下:
- 通过反射,将xml中各项映射,硬编码的方式写入到FileProvider的sCache中
- 定义一个中转ContentProvider,将它声明在AndroidManifest文件中,接管所有FileProvider的openFile方法
- 通过Aspect插桩方式,将所有FileProvider的getUriForFile()返回的Uri的authority hook成中转ContentProvider的authority
6.1 反射硬编码写入映射
- 通过反射将映射关系写入sCache中
- 将本应该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行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!