CC
配置
- app中build.gradle配置
ext.mainApp = true//标明是主app
apply from :rootProject.file('cc-settings-2.gradle')//配置文件,集成了公共的引用
addComponent 'component_a' ,project (':component_a')
//引用,这样写是为了,子Module单独运行时,可以不用修改这里,只需要在工程根目录的local.properties添加如下配置,并重新打包运行主app
//module_name=true #module_name为具体每个module的名称,设置为true代表从主app的依赖列表中排除该组件module
addComponent 'component_b' ,project(':component_b')
addComponent 'component_jsbridge' ,project(':component_jsbridge')
- 普通的Module中build.gradle
ext.alwaysLib = true//标明只是普通module,不会被当作app运行
apply from :rootProject.file('cc-settings-2.gradle')
- 可运行的module中的build.gradle
apply from: rootProject.file('cc-settings-2.gradle')
android {
defaultConfig {
if (project.ext.runAsApp) {
applicationId "com.sohu.hy.ccrouter.component.jsbridge"
}
}
resourcePrefix "component_jsbridge_"//可选,为了资源不冲突
}
想要module可运行,还需要在main目录下建立debug目录,新建LauncherActivity和Application。
- 根目录build.gradle
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.4.0'
classpath 'com.billy.android:cc-register:1.1.1' //使用最新版,自动注册插件,自动插入需要的代码
}
}
- cc-settings-2.gradle
apply plugin :'cc-register'//应用自动插入代码的插件
dependencies {
implementation project(':component_base')//都需要引用的正常module
api "com.billy.android:cc:2.1.5"//都需要引用的cc api
//添加全局拦截器
if (project.ext.has('runAsApp') && project.ext.runAsApp) {
implementation project(':demo_interceptors')
}
}
//开启app内部多进程组件调用时启用下面这行代码
ccregister.multiProcessEnabled = true
//开启app内部多进程组件调用时,可以启用下方的配置排除一些进程
//ccregister.excludeProcessNames = [':pushservice', ':processNameB']
//按照如下格式添加自定义自动生成代码的信息,可添加多个(也可每次add一个,add多次)
ccregister.registerInfo.add([
//在自动注册组件的基础上增加:自动注册组件B的processor
'scanInterface' : 'com.sohu.hy.component_b.process.IActionProcessor'
, 'codeInsertToClassName' : 'com.sohu.hy.component_b.ComponentB'
, 'codeInsertToMethodName' : 'initProcessors'
, 'registerMethodName' : 'add'
])
使用
- 初始化
CC.enableVerboseLog(true)
CC.enableDebug(true)
CC.enableRemoteCC(true)//开启跨进程调用,子module可单独运行时需要开启
- module独立运行。
要显示界面时,还需要设置额外的Application,LauncherActivity。更新完module,运行app,是新的代码。主app不能包含此组件,local.properties里面加上module名称,要不然会找主app的引用,而不会找这个独立运行的module。为什么要独立运行module?只在module上面开发,主app来调用。最大作用缩小编译时间,主app也能调用。 - component 组件对外接口,根据名称找到接口,根据不同action执行不同的操作
//同步调用,直接返回结果
CCResult result = CC.obtainBuilder("ComponentA")
.setActionName("showActivity")
.build()
.call();
//或 异步调用,不需要回调结果
String callId = CC.obtainBuilder("ComponentA")
.setActionName("showActivity")
.build()
.callAsync();
//或 异步调用,在子线程执行回调
String callId = CC.obtainBuilder("ComponentA")
.setActionName("showActivity")
.build()
.callAsync(new IComponentCallback() {
@Override
public void onResult(CC cc, CCResult result) {
//此onResult在子线程中运行
}
});
//或 异步调用,在主线程执行回调
String callId = CC.obtainBuilder("ComponentA")
.setActionName("login")
.build()
.callAsyncCallbackOnMainThread(new IComponentCallback() {
@Override
public void onResult(CC cc, CCResult result) {
//此onResult在主线程中运行
String toast = "login " + (result.isSuccess() ? "success" : "failed");
Toast.makeText(MainActivity.this, toast, Toast.LENGTH_SHORT).show();
}
});
定义组件时,onCall方法的返回值,return true,代表异步执行,在未来某个时间会调用CC.sendResult,返回false代表同步调用,return false 之前调用CC.sendResult。
CC.sendResult每个action必须执行。CC.obtainBuilder(componentName)可异步可同步执行。
- IActionProcessor,自定义action处理类
interface IActionProcessor{
fun getActionName():String
/**
* action的处理类
* @param cc cc
* @return 是否异步调用 [CC.sendCCResult] . true:异步, false:同步调用
*/
abstract fun onActionCall(cc: CC): Boolean
}
利用插件auto-register来处理action,避免if else的分支,往某个类中某个方法中添加一些语句,固定的写法。
配置方法:
ccregister.registerInfo.add([
//在自动注册组件的基础上增加:自动注册组件B的processor
'scanInterface' : 'com.sohu.hy.component_b.process.IActionProcessor'
, 'codeInsertToClassName' : 'com.sohu.hy.component_b.ComponentB'
, 'codeInsertToMethodName' : 'initProcessors'
, 'registerMethodName' : 'add'
])
public class ComponentB implements IComponent, IMainThread {
private AtomicBoolean initialized = new AtomicBoolean(false);
private final HashMap<String, IActionProcessor> map = new HashMap<>(4);
private void initProcessors() {
add(new CheckAndLoginProcessor());
add(new LoginProcessor());
add(new GetDataProcessor());
}
private void add(IActionProcessor processor) {
map.put(processor.getActionName(), processor);
}
- IMainThread
指定某些action的oncall方法回调时的线程。打破默认的线程调用状态。需要注意和onCall返回值的异同,onCall返回值只是标记是否立即调用CC.sendResult。
/**
* 指定是否在主线程运行
* @author billy.qi
* @since 18/9/19 11:31
*/
public interface IMainThread {
/**
* 根据当前actionName确定组件的{@link IComponent#onCall(CC)} 方法是否在主线程运行
* @param actionName 当前CC的action名称
* @param cc 当前CC对象
* @return 3种返回值: <br>
* null:默认状态,不固定运行的线程(在主线程同步调用时在主线程运行,其它情况下在子线程运行)<br>
* true:固定在主线程运行<br>
* false:固定子线程运行<br>
*/
Boolean shouldActionRunOnMainThread(String actionName, CC cc);
}
-
IParamJsonConverter跨进程传递自定义类型,Json的转换类。
-
ICCInterceptor
可以用业修改参数,修改结果或者中断执行
public interface ICCInterceptor {
/**
* 拦截器方法
* chain.getCC() 来获取cc对象
* 调用chain.proceed()来传递调用链
* 也可通过不调用chain.proceed()来中止调用链的传递
* 通过cc.getParams()等方法来获取参数信息,并可以修改params
* @param chain 链条
* @return 调用结果
*/
CCResult intercept(Chain chain);
}
//增加拦截器
CC.obtainBuilder("componentName")
.setActionName("actionName")
.addInterceptor(new MyInterceptor())
.build()
.call();
- ICCGlobalInterceptor
每次调用都会执行,实现接口后,auto-register会自动注册。 - IDynamicComponent
动态组件,不会自动注册,而IComponent会自动注册。
CC.registerComponent(dyComponent)
CC.unregisterConponent(dyComponent)
- 多进程
* 无注解 : 该组件类在主进程中运行
* @SubProcess(":web") : 该组件类运行在packageName:web子进程,
* @AllProcess : 该组件类在App内所有进程中都存在一个对象,调用该组件时,调用的是调用方所在进程中的组件类对象
@AllProcess注解可用于在多进程环境下提供:在调用方所在进程中创建自定义Fragment/View等对象的服务
异同
- 跳转页面时传递参数,获取方式不同,使用getNavigateParam,不能为页面自动赋值。
- cc可以异步请求,并返回传递丰富的数据类型,不公限于执行页面跳转,任何任务都可以执行,并获取返回结果。一个component就是一个处理任务的工厂。
- CC类似http请求,一对一主动调用,并有回调,可同步可异步。利用动态组件可以实现任务的接收与回调
网友评论