组件化框架 CC 的源码解读

概述

CC 框架是一个面向协议的组件化框架,相较于其他面向接口和数据结构的组件化框架(得到的框架等),面向协议的意思是通过开发者自己定义 ActionName 和数据 Map 等来进行调用。因此不需要开发者再重新定义清晰的接口,而是将这个调用转变为协议,因此能够提供跨平台的功能。

同步调用

CCResult result = CC.obtainBuilder(COMPONENT_NAME_A)
.setActionName("getInfo")
.build()
.call();

异步调用

CC.obtainBuilder("demo.lifecycle")
.build()
.callAsyncCallbackOnMainThread(printResultCallback);

调用时序图

点击查看原图,可看到清晰的时序图

CC框架时序图.png

代码依赖隔离

CC 通过编译的手段实现代码隔离。在主工程的 gradle 中,通过如下语句将各个组件编译进来:

addComponent 'demo_component_a'
addComponent 'demo_component_kt'
addComponent 'demo_component_jsbridge'

addComponent 是一个自定义的 lamda 表达式,源码在 cc-settings.gradle 中。

  1. 通过过滤筛选出 assembleinstall 的 task,表明此刻进行的 task 是生成 apk 的 task(而不是 sync 之类的)
  2. addComponent 替换为 apicompile

通过 addComponent 就实现了编写代码阶段不能随意使用其他模块的代码和资源,在编译时再换成依赖,实现代码隔离

编译时依赖注入

CC 通过编译的手段实现依赖注入。在主工程的 cc-settings-demo.gradle 中,通过如下语句将实例编译阶段注入:

ccregister.registerInfo.add([
//在自动注册组件的基础上增加:自动注册组件B的processor
'scanInterface'             : 'com.billy.cc.demo.component.b.processor.IActionProcessor'
, 'codeInsertToClassName'   : 'com.billy.cc.demo.component.b.ComponentB'
, 'codeInsertToMethodName'  : 'initProcessors'
, 'registerMethodName'      : 'add'
])

ComponentB 中我们可以看到:

private void initProcessors() {
}

private void add(IActionProcessor processor) {
    map.put(processor.getActionName(), processor);
}

initProcessors() 方法中没有任何代码。add(IActionProcessor processor) 方法接收一个实现了 IActionProcessor 接口的实例。编译后的代码如下:

Dependency Inject.png

可以看到编译后,initProcessors() 方法中注入了 add() 方法,并且传入了各个 Processor 的实例。

实践

我们可以运用代码隔离和依赖注入来实现模块的完全解耦。

  • 所有模块相互之间不可见,编译 apk 时,才打包进 apk
  • 编写代码阶段不可见的模块之间如何进行通信呢?在最底层模块实现一个类,像 ComponentB 中一样持有一个 类名 - 实例 的 map。编写代码阶段,一个模块需要与另个一个模块通信时,就从这个 map 中取出另一个模块的 interface,面向接口进行通信。打包时,通过依赖注入将各个模块的实例加入到 map 中,这样运行时就是各个模块的实例了。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容