2019-10-02 00:49:04 +08:00
2019-10-02 00:49:04 +08:00
2019-10-02 00:49:04 +08:00
2019-09-30 20:09:11 +08:00
2019-09-30 20:09:11 +08:00
2019-09-30 20:09:11 +08:00
2019-09-29 14:32:16 +08:00
2019-09-03 20:01:46 +08:00
2019-07-16 20:09:32 +08:00
2019-07-16 20:09:32 +08:00
2019-10-02 00:49:04 +08:00
2019-07-29 15:20:08 +08:00

ModulePlugin

android modular plugin.

初衷android 9.0之后插件基本已经告别。随着android版本越来稳定封闭开发逐步偏向模块化开发。 并有没有一个支持代码隔离,支持独立调试,且不对任何现有代码进行改动的插件。

本工程主要解决以下 4 个问题:

  1. 如何解决接口api和实现impl代码隔
  2. 如何解决工程模块独立调试?
  3. 如何解决动态依赖接口api和impl实现在Sync场景下依赖接口api而在其他场景下动态添加impl实现
  4. 如何解决模块的绑定和卸载接口api的暴露和回收

现实场景中,有很多优秀的开源库如 DDComponentForAndroid 提供了独立的调试思路但其配置繁琐,不利于开发。Mis 提供了如何实现工程上代码隔离但是无法针对单一模块进行调试等等。 在希望解决上述 4 个核心问题的前提下只需要在项目添加一份独立的gradle脚本且不需要修改任何已有的代码工程结构实现 "代码隔离独立调试api注入"。

如何解决接口api和实现impl代码隔

早在 17 年微信发布过 微信Android模块化架构重构实践 一文中涉及到通过接口保护形式(.api化拉实现分离模块的功能并生成对应的 'SDK' 工程,其他工程依赖编译的只是这个生成的工程。 曾把模块提供的接口独立为一个工程并打包成sdk但这样就会导致 sdk 和 impl 分为两个模块,不好维护和不雅观。业界优秀开源项目 Mis 提供了一种代码隔离的思路,大致为:

  • 通过修改 sourceSet 把接口文件放到 aidl 文件中,并接口打包成 sdk
  • 实现工程依赖打包的 sdk

通过研究源码参考作者编写的思路确实是一种好用的方法细节逻辑见源码。值得一提的是sdk 是一个 jar不仅仅可以包含业务 api也可以包含数据接口 bean等。

如何解决工程模块独立调试

不仅仅是 DDComponent 提供的方案,很多现有的文章推荐都方法都是通过修改 sourceSet 的内容,在已有工程下新增一个独立的调试资源目录,然后配置代码和资源,指定 AndroidManifest 来达到提供 App 入口的手段。也就说,在 Debug 模式下我们只需要把我们的调试目录编进去即可。但是如何在对应的插件 Project 被加载之前读取提前读取到配置信息呢 ?很多方案都使用了 gradle.properties 来配置,实际上没有必要,也可以在 gradle 脚本中配置,但是要改变配置读取的时间。我们可以在 root Project 提前读取子 Project 的手段来解决。这样更聚合配置信息。

如何解决动态依赖接口api和impl实现在Sync场景下依赖接口api而在其他场景下动态添加impl实现

在解决第一个问题的前提下我们已经把接口api打成 sdk 把实现打成 impl一般我们在 Sync阶段只需要编译 sdk 即可,但我们总不能一直修改 gradle 脚本。可以通过修改 Dependence 的 Scope 来自定义获取依赖的值。比如

    //只需要这个
    implementation component(':library')

    //等价于
    同步时
    implementation ':library-sdk'
    非同步时
    implementation ':library-impl'
    implementation ':library-sdk'

细节逻辑请参考源码

如何解决模块的绑定和卸载接口api的暴露和回收

按照业务把工程划分为一下几层:

  • Base层 - 基础类库,存放精简的代码高复用性一般其他模块直接引用即可比如一些utils一些baseActivity等
  • Service层 - 支持某类基础业务功能的独立模块比如登陆服务换肤服务一般介于基础类库Base层和业务组件Component层中间也可以直接被App层调用
  • Component层 - 聚合多中基础业务功能的复杂业务模块比如朋友圈附近的人一般可能使用多个Service服务
  • App层 - App的入口聚合多个业务模块

从功能上看Service层和Component最大的区别是Service功能更纯粹而Component耦合多功能多场景逻辑但是从工程上看两者都可进行代码隔离。比如登陆Service需要登陆相关的接口朋友圈需要提供入口等等。 所以这两者都工程构建上,都需要支持代码隔离。

在解决代码隔离场景下,需要解决一个问题 "Service层和Component如何在合适的时机注入impl模块并维护impl的生命周期。" 这里的接口指的是模块需要暴露出来的api一般一个模块可对应多个api接口所以接口注入模块的绑定和卸载可以有一个清晰的生命周期

模块绑定 -> 接口注入 -> 接口卸载 -> 模块卸载

而在实现完全被隔离的情况下,如何实现解决这个问题呢 Transform + annotation + asm 技术。通过自定义插件注册自定义的 transform 完成 Class 文件中 annotation 的扫描可收集目的信息(注解内容,注解类等), 用 asm 封装好的字节码指令完成对目标类字节内容的修改达到注入代码的目的。

为了最大化兼容调试,废除dd方案完全往原生靠拢 未来规划: 支持sdk及impl maven仓库存储

Description
No description provided
Readme 11 MiB
Languages
Groovy 76.3%
Java 19.6%
Kotlin 4%
Shell 0.1%