Android 下载引擎的组件化源于应用场景的广泛性和存储字段的固定性。起初,下载引擎是通过 Module 的形式引入项目的,这种方式的引入在形式上起到了解耦作用,同时,也可针对项目个性化的存储字段进行增减。但随着下载引擎复用需求的增加和业务的积淀,Module 不再是下载引擎的最优引用方式了。首先,随着业务的积淀,存储字段的数量逐渐趋于稳定,这意味着下载引擎已经可以满足大部分的应用场景了;其次,Module 引入项目的方式不利于源码的维护。试想下,如果下载引擎出现了问题,并且修复过程异常复杂,那么每个以 Module 方式引入下载引擎的应用在修复同类问题的时候将会非常痛苦,如果再考虑个性化存储字段,这个修复过程将会变成一场灾难。所以,需要一种更加便捷的引用方式来改变现状,比如:AAR 或者 Maven。
引用方式的改变还是比较棘手的。为了理解这里的困惑,需要了解一下下载引擎的实现方式。下载引擎是通过服务启动下载线程来下载内容的,如果下载的信息有变更,这些信息在入库的同时会通知已注册的观察者,前台会通过内容提供者获取下载信息,并展示在界面上。这里需要注意的是内容提供者,也就是 ContentProvider,同一部手机上是不允许同时存在拥有相同 Authorities 的两个应用的。这意味着下载的引擎的内容提供者应该同时具备动态配置和动态读取 Authorities 的能力。下面,就通过改造让下载引擎来具备这些能力。
1. 改造下载引擎库
1.1 动态配置 Authorities
Authorities 的动态配置可通过 Manifest 占位符来实现,在下载引擎库清单文件的 provider
节点中进行配置即可,代码如下:
1 | <application> |
1.2 动态读取 Authorities
什么时候读取 Authorities 呢?我们将读取窗口选在了 ContentProvider 的 attachInfo 方法中,因为这个方法是内容提供者实例化完成后进行调用的,作用是返回内容提供者自身的信息,其中就包括 Authorities 信息。我们可以在这个方法中为 URI 匹配器设置匹配的权限和路径。代码如下:
1 | public final class DownloadProvider extends ContentProvider { |
1.3 源码分析
为什么选择 attachInfo 方法作为 Authorities 的读取窗口呢?先来看下 ContentProvider 的源码,attachInfo 方法的注释为:实例化完成后,将调用它来告诉内容提供者有关其自身的信息。这个方法会将内容提供者初始化时从清单文件读取到的信息返回来,并在最后调用自身的 onCreate 方法。如何证明这里的 ProviderInfo 就是从清单文件中读取的呢?可以查看 setAuthorities 方法的注释,这个方法用于更改 ContentProvider 的 Authorities,方法里的 Authorities 值通常是内容提供者首次创建时根据清单信息进行设置的。
1 | /** |
通过上面的内容,我们已经具备了动态配置和动态读取 Authorities 的能力,同时我们也从源码上得到了验证。下面,只需要在项目中进行配置,并验证结果就可以了。
2. 引用下载引擎库
在主项目 build.gradle
的 defaultConfig
节点下增加 Manifest 占位符配置,这里需要注意的是占位符的键要与 Provider 中预设的一致,这里的值通常是 applicationId,也可自行设定。
1 | android { |
3. 验证结果
运行程序,下载功能正常。转到 build 目录下输出的 APK 文件,查看 AndroidManifest.xml 会发现,上面设置的 Authorities 信息已经被整合到了 provider 节点内。至此,Authorities 的动态配置和动态读取能力验证完毕。
1 |
|