您现在的位置是:首页 > 文章详情

Rubik:基于 Kotlin 的 Android 组件化开发框架开源!

日期:2022-12-06点击:391

前言

    随着Android平台的飞速发展,许多老牌App,都发展成了所谓的“超级应用”,不但功能模块众多、代码量巨大,团队规模更是扩大到了几十人甚至上百人的规模。一线大厂的旗舰应用,甚至可能涉及到多个部门的协同开发。
    在这个过程里,必然的产生了一些“代码复用”和“协同效率”方面的问题。所以,组件化开发逐渐被各个大厂提上了日程。如今,移动端开发除了要解决“代码”方面的问题,也需要关注“工程”方面的问题。
    2022年,百度网盘App迎来了10周年,在这10年的发展过程中,我们也遇到过各种各样的的“工程”问题,为了解决这些问题,我们引入了组件化开发,而Rubik就是在这个过程中诞生的。
 

关于Rubik

    Rubik由百度网盘团队出品,从2019年开始建设,至今已经迭代了两个大版本,并在多款线上产品中得到应用。
    Rubik是一套解决Android平台组件化的综合框架,也就是说,Rubik在帮助我们实现模块解耦的同时,还能能够提供一些组件管理能力。Rubik所提供的模块解耦能力是一种基于“函数路由”的组件间低耦合通讯方案。组件管理能力能够帮助我们实现组件的版本控制、maven发布、aar/jar与源码之间的切换等能力,Rubik还可以通过配置文件,更简便的把现有的组件,组合成不同的APK。
Rubik框架的工程结构
 
    换而言之,Rubik专注于解决Android应用开发过程中的组件化问题。但是,Rubik作为一个完全由Kotlin语言实现的开源框架,即使你没有组件化开发方面的需求,也非常欢迎关注Rubik的技术实现,欢迎阅读Rubik的代码,因为:
    首先,Rubik完全采用kotlin开发,并且大量应用了Kotlin的函数式编程、DSL等特性,非常适合正在学习Kotlin的小伙伴交流学习;
    另外,在Rubik的实现过程中,也应用到了Kotlin代码自动生成方面的技术。几乎尝试了目前全部Kotlin代码自动生成的相关方案,也用到了Tranform这样的传统的字节码修改技术。
    最后,作为一个贯穿于Android编译过程的工具链类项目,Rubik中有大量的,关于Gradle插件方面的实践,也封装了大量的Gradle方面的工具类。非常适合想要开发Gradle插件的小伙伴参考和借鉴。最重要的是,这一切都是基于Kotlin的。
 

关于组件化

    关于组件化开发,有很多不同的定义。在这里,定义并不重要,我们更应该关心,对于客户端开发而言,组件化开发所能解决的最核心的问题是什么。我们认为,组件化开发的核心,在于两点:
  • 隔离:让业务组件之间保持相对的独立性
  • 复用:复用业务组件形成可运行软件
 

怎样才算彻底的组件隔离?

让业务组件之间保持独立性,通常可以与代码层面上的“解耦”划上等号,如果两个业务的代码混杂在一起,缺乏对边界的定义,肯定是代码隔离不彻底的表现。
代码隔离不彻底的情况
 
另外,对于组件化来说,业务隔离的标准还要更苛刻一些,当两个模块,在业务上的关联并不强时,如果存在直接的代码调用,也要视作代码隔离不彻底。由于编译顺序的关系,在Android平台,模块之间是无法建立双向的代码依赖的,这显然与组件化的理念有出入,我们希望组件之间是平等、独立的,应该可以自由的在任何组件之间建立松耦合的依赖关系。像这种基于代码调用的单向依赖,本质上一种“剪不断”的“从属关系”。
代码隔离不彻底的情况

 

所以,在组件化开发中,组件之间应该保持没有代码耦合,在需要互相通信时,使用一种通过接口,间接的依赖的通信方式。
 
间接的依赖

 

    在实际的组件化开发过程中,隔离往往是最难以实际操作的,无论是面对难以维护的历史代码,还是在前期规划不足的新业务。但是,一旦清晰的划分出两个组件间的边界,把彼此的代码隔离开,就会带来一系列的工程方面的好处:
  • 明确开发人员的职责:由于对一个模块的修改不会直接影响另一个模块,所以负责开发不同模块的开发人员,只需要对约定好的接口负责,不需要关心其他组件的具体实现。
  • 降低测试成本:同样的,对于测试人员而言,如果能够保证对一个组件的修改,只影响组件本身和组件的接口,那么对于没有被修改过的组件,就没有回归测试的必要了。
  • 提升编译速度:在实际开发中,可以让大部分组件提前编译成二进制,只让少数经常变更的组件保持源码状态。
  • 故障隔离:当一个组件出现故障,能够做到不影响其他组件的正常运行。
 
    对于组件的隔离,可以总结成一句话:隔离代码不是目的,隔离变化才是最重要的!
    除此之外,隔离也是对组件进行复用的前提,只有隔离了一个业务组件对外部的全部隐式的影响,才能保证这个组件在被其他场景复用时是安全、可靠、无副作用的。
 

组件级别的复用应该做到什么程度?

    组件级别的复用,指的是在不同应用程序之间,复用已有的业务组件。这往往都是为了快速搭建新项目,并且最大限度的保证新老项目的代码的一致性,从而降低代码的维护成本。所以,组件化开发框架,应该能够做到对现有的组件进行储备,并且在新项目启动时,通过简单的配置,对已有的组件进行筛选,快速的生成新的应用程序。
 
组件的筛选复用
 
    在实际开发中,有可能会遇到同一个组件,给不同的应用复用时,存在一些功能差异的情况。所以,组件化框架也必须能够做到将同一套代码,差异化的编译成在功能上略有差异的组件变体,以便在不同需求下复用。
组件的变体复用
 

Rubik在组件化中的作用?

    Rubik由两部分组成,一部分是解决组件间低耦合通信的Rubik Router模块,另一部分是基于Gradle Plugin实现的Rubik工具链,负责解决组件管理和依赖管理方面的问题。
 

Rubik Router:基于Kotlin DSL的“函数”路由

    Rubik在依赖倒置与依赖注入的基础上,实现了一套基于Uri的路由通信方式,与一般的页面路由或四大组件路由不同,Rubik Router允许把Uri及参数,导航到组件内部任意的一个公开的Java或Kotlin函数的执行上。Rubik Router的选择以函数而非Android中的四大组件为路由的终点,主要基于三方面考虑:
  • 灵活性:在实际开发中,组件的边界通常不是简单的页面跳转,有可能是Api的调用或数据、实例的获取,相比于传统的页面路由,“函数”路由可以更加轻量级的满足这些需求。
  • 可扩展性:“函数”路由有更低的层次,使用者可以在函数的基础上延伸更多的用法。
  • 一致性:对于路由调用者而言,路由的终点无论是函数、页面还是数据,Rubik Router都提供一致的调用方式。
函数路由
 
另外,Rubik Router提供了基于Kotlin DSL的调用方式,提供了基于元注解的路由声明方式,让使用者可以更加简便、直观的调用其他组件提供的接口。
 
 @RRoute(path = "user") fun getUser(id : Int, name : String) : User? { … }

用元注解把函数注册到路由

 navigate { uri = "app://com.account/user" query { "id" with 400 "name" with "zhangsan01" } result<User?> { user -> // 通过泛型指定接收数据类型 … } } 

通过Kotlin DSL调用其他组件提供的接口

Rubik Plugins:基于Gradle Plugin的组件管理和依赖管理工具

    Rubik gradle plugins 提供了组件定义、版本控制、maven发布、二进制依赖与源码依赖切换等能力,包括4个gradle plugin:
  • rubik:
    • 提供全局定义组件的能力,并根据全局定义自动启用rubik-context、rubik-root等插件

      rubik插件工程结构

       rubik { component { uri "app://com.cloud-file" // uri 是组件的唯一 id,和路由根路径 dependencies { // 组件所依赖的其他组件uri uri ("app://com.local-file" ) uri ("app://com.upload" ) } source { // 定义的多种来源 project (":lib-cloud-file") maven { // 其他组件依赖自己的默认版本 version "0.2.0" variant "english-debug" } } } component { … } // 继续定义下一个组件 } 

      组件的定义方式

       

       

  • rubik-root:
    • 给App工程提供筛选组件能力,根据flavor、版本号筛选要打包进apk的业务组件
    • 提供组件的源码工程和aar切换的能力
组件的筛选与依赖方式切换

 

 rubik { packing { uri ("app://com.cloud-*") { // 筛选范围,uri表示用uri筛选,支持*匹配任意字符 projcetMode () // 筛选方式, projcetMode通过工程筛选一些组件 } uri ("app://com.preview-file") { mavenMode { // 筛选方式, mavenMode通过maven依赖aar筛选一些组件 version "0.2.0" variant "netdisk-english-debug" } } …… } } 

筛选组件的方式

 
  • rubik-context:
    • 提供把业务代码按flavor、版本号编译成aar 并发布到maven的能力
    • 提供辅助函数路由,把中间代码打包成context.jar ,并按版本号发布到maven的能力,并根据全局定义,为组件自动添加其他组件的中间代码依赖
组件及中间代码的发布和自动依赖
 
  • rubik-test:
    • 给工程提供单元测试环境

最后

    希望Rubik能够帮助大家更便捷的实现组件化开发,也欢迎大家进行代码和技术层面的交流,如果你觉得我们做的还不错,请小伙伴们不要吝惜star、fork和watching: https://github.com/baidu/Rubik

 

原文链接:https://www.oschina.net/news/220734
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章