Rubik
软件简介
Rubik 是一套解决 Android 平台组件化的综合方案,提供 gradle project 之间的路由通讯能力,以及对 gradle project 的组件定义、版本控制、maven 发布、aar/jar 与源码之间的切换以及组件的自由组合等能力。
Rubik 由两部分组成:
- Rubik Router :即 Rubik 的函数级路由能力,与一般的页面路由不同,Rubik Router 允许把 Uri 及参数,导航到工程内部,任意的一个公开的 JVM 语言(Java/Kotlin)函数的执行上,以便于更灵活的进行 gradle project 之间不基于代码调用的通讯。
- Rubik 工具链 :提供组件上下文的定义、版本控制、maven 发布、aar/jar 与源码之间的切换等能力,包括 4 个 gradle plugin:
- rubik:
- 提供全局定义组件的能力,并根据全局定义自动启用 rubik-context、rubik-root 等插件
- rubik-context:
- 提供 task,自动生成镜像函数等中间代码,并把中间代码打包成 context.jar , 按版本号发布到 maven
- 提供 task,把业务代码按 flavor、版本号编译成 aar (包括代码、资源、内置 SDK) 发布到 maven
- 通过全局定义的组件,为组件所在子工程自动添加其他 context.jar 的依赖
- rubik-root:
- 给壳工程提供筛选组件等能力,根据 flavor、版本号筛选要打包进 apk 的业务组件
- 提供组件的源码工程和 aar 切换的能力
- rubik-test:
- 给工程提供单元测试环境
- rubik:
快速开始
1. 工程创建和组件声明:
(1) 创建或使用已有的一个或多个 android library module,作为 "组件工程"(如 demo 代码中的 demo_component_detail、demo_component_home 等),用于开发真正的业务逻辑。
(2) 在最外层工程(gradle root project) 的 build.gradle 或 gradle.properties 文件中配置 Rubik 版本号等初始化参数,并在最外层工程中启用 rubik 插件:
ext {
rubik_kapt_version = "com.rubik:kapt:1.9.1.1-K1_5"
rubik_router_version = "com.rubik:router:1.9.1.1-K1_5"
rubik_plugins_version = "com.rubik:plugins:1.9.1.1-AGBT4-K1_5"
}
apply plugin: 'rubik' // 启用rubik插件
(3) 在最外层工程的 build.gradle 文件或同级目录下的 rubik-*.gradle 文件中,配置组件信息:
rubik {
component { // 第一个组件
uri "app://com.myapp.home" // 组件的Uri
dependencies { // 组件需要依赖的其他组件
uri ("app://com.myapp.detail" ) {
version "0.1.1" // 依赖其他组件的版本
}
uri( … )
}
source { // 定义默认来源,如不需切换源码和aar,可以只声明project或maven
project (":demo_component_home")
}
}
component { … } //继续配置第二个组件
}
2. 让组件之间互相通信:
(1). 在接口提供者工程内,通过注解定义路由路径,作为组件暴露给其他组件的通信接口:
通过 RFunction 注解声明函数路由:
@RFunction(path = "account/user")
fun getUser(id : Int, name : String) : User? {
…
}
通过 RPage 注解声明页面路由:
@RPage(path = "page/main")
class HomeActivity : AppCompatActivity() {
…
}
(2). 执行接口提供者工程对应的 "publishRubikXxxRContextLib" 任务,发布组件上下文到云端或本地 maven 仓库。
(3). 执行接口提供者工程对应的 "publishRubikXxxRComponent" 任务,发布组件 aar 到云端或本地 maven 仓库。
(4). 在接口调用者工程内,调用上述接口提供者所提供的接口,可以选择两种方式:
通过 Kotlin DSL:
navigate {
uri = "app://com.myapp.detail/account/user" // 请求的uri
query { // 请求的参数
"id" with 400
"name" with "CuiVincent"
}
result<User?> { user ->
// 通过泛型指定接收数据类型,多次异步返回时,可以用多个result接收
…
}
}
通过自动生成的镜像函数:
DetailContext.Account.user(400, "CuiVincent" ) { user ->
… // 自动生成的镜像函数的参数类型、返回值类型都是明确的,比DSL方式更具有约束力
}
3. 筛选要打包的组件
(1). 创建或使用已有的 android application project,作为 "壳工程"(如 demo 代码中的 demo_root_app),用于把组件组装并编译成 Apk。
(2). 在 "壳工程" 的的 build.gradle 文件或同级目录下的 rubik-*.gradle 文件中,指定 "壳工程" 最终要将哪些组件,以哪种方式引入,并打包到最终的编译产物之中:
rubik {
packing {
projectMode { // projectMode,通过源码工程的方式引入组件
uri ("app://com.myapp.home")
uri ("app://com.myapp.*") // 支持通过*匹配任意字符
}
mavenMode { // mavenMode,通过maven上的aar的方式引入组件
uri ("app://com.myapp.detail") {
version "0.2.0"
}
}
}
}
测试
- 通过 rubik-test 插件,给当前工程的 androidTest variant 添加全部可 pick 组件的 context.jar 依赖,便于写测试用例。
@RunWith(AndroidJUnit4::class)
class RouterTestCase {
@Before
fun init() {
Rubik.init()
} // 初始化Rubik
@Test
fun usePerview() {
PerviewContext.preViewVideo(path) { success ->
log("preViewVideo success:${success}")
} // 测试用例
}
… // 继续写测试用例
}