原理介绍:Wiki
demo下载(包含主工程demo和demo_component_a组件)
demo_component_b组件单独运行的App(Demo_B)下载
以上 2个app 用来演示组件打包在主app内和 单独以app运行 时的组件调用, 都安装在手机上 之后的运行效果如下图所示
定义组件:将自身的业务(页面跳转及服务调用等)封装起来提供给外部调用,并返回执行的结果
调用组件:根据组件名称、业务名称及其它参数调用指定组件的指定业务,并获得执行的结果
组件将业务完全隔离在自身内部,仅暴露组件名称(ComponentName)、业务名称(actionName)、参数列表及返回值等信息给外部调用
1. 在根目录build.gradle中添加自动注册插件 2. 添加apply cc-settings.gradle文件 3. 实现IComponent接口创建一个组件 4. 使用CC.obtainBuilder(“component_name”).build().call()调用组件
组件以app方式独立运行时不需要依赖任何其它组件,从源头上隔离代码 无需担心与主app的相互调用,从一开始组件化改造就可以单组件运行 跟打包在主app中运行是一样的效果,能大大降低组件化改造的难度
了解业界开源的一些组件化方案:多个维度对比一些有代表性的开源android组件化开发方案
1. 支持组件间相互调用(不只是Activity跳转,支持任意指令的调用/回调) 2. 支持组件调用与Activity、Fragment的生命周期关联 3. 支持app间跨进程的组件调用(组件开发/调试时可单独作为app运行) 4. 支持app间调用的开关及权限设置(满足不同级别的安全需求,默认打开状态且不需要权限) 5. 支持同步/异步方式调用 6. 支持同步/异步方式实现组件 7. 调用方式不受实现方式的限制(例如:可以同步调用另一个组件的异步实现功能。注:不要在主线程同步调用耗时操作) 8. 支持添加自定义拦截器(按添加的先后顺序执行) 9. 支持超时设置 10. 支持手动取消 11. 编译时自动注册组件(IComponent),无需手动维护组件注册表(使用ASM修改字节码的方式实现) 12. 支持动态注册/反注册组件(IDynamicComponent) 13. 支持组件间传递Fragment、自定义View等(组件在同一个app内时支持、跨app传递非基础类型的对象暂不支持) 13.1 不仅仅是获取Fragment、自定义View的对象,并支持后续的通信。 14. 尽可能的解决了使用姿势不正确导致的crash,降低产品线上crash率: 14.1 组件调用处、回调处、组件实现处的crash全部在框架内部catch住 14.2 同步返回或异步回调的CCResult对象一定不为null,避免空指针
下面介绍在Android Studio中进行集成的详细步骤
在工程根目录的build.gradle中添加组件自动注册插件
buildscript { dependencies { classpath 'com.billy.android:autoregister:x.x.x' } }
apply plugin: 'com.android.library' //或 apply plugin: 'com.android.application' //替换成 apply from: 'https://raw.githubusercontent.com/luckybilly/CC/master/cc-settings.gradle' //注意:最好放在build.gradle中代码的第一行
默认组件为library,若组件module需要以app单独安装到手机上运行,有以下2种方式:
在工程根目录的 local.properties 中添加配置
module_name=true #module_name为具体每个module的名称
在module的build.gradle中添加
ext.runAsApp = true
创建组件(实现IComponent接口,需要保留无参构造方法)
public class ComponentA implements IComponent { //需保留无参构造方法 @Override public String getName() { //组件的名称,调用此组件的方式: // CC.obtainBuilder("ComponentA").build().callAsync() return "ComponentA"; } @Override public boolean onCall(CC cc) { Context context = cc.getContext(); Intent intent = new Intent(context, ActivityComponentA.class); if (!(context instanceof Activity)) { //调用方没有设置context或app间组件跳转,context为application intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } context.startActivity(intent); //发送组件调用的结果(返回信息) CC.sendCCResult(cc.getCallId(), CCResult.success()); //返回值说明 // false: 组件同步实现(onCall方法执行完之前会将执行结果CCResult发送给CC) // true: 组件异步实现(onCall方法执行完之后再将CCResult发送给CC,CC会持续等待组件调用CC.sendCCResult发送的结果,直至超时) return false; } }
4. 调用组件
//同步调用,直接返回结果 CCResult result = CC.obtainBuilder("ComponentA").build().call(); //或 异步调用,不需要回调结果 String callId = CC.obtainBuilder("ComponentA").build().callAsync(); //或 异步调用,在子线程执行回调 String callId = CC.obtainBuilder("ComponentA").build().callAsync(new IComponentCallback(){...}); //或 异步调用,在主线程执行回调 String callId = CC.obtainBuilder("ComponentA").build().callAsyncCallbackOnMainThread(new IComponentCallback(){...});
更多使用方式请戳这里
状态码清单
不需要额外的混淆配置
源码:AutoRegister 原理:android扫描接口实现类并通过修改字节码自动生成注册表