CC安卓組件化框架
CC : ComponentCaller (使用簡單但功能強大的安卓組件化框架)
| 模塊 | CC | AutoRegister |
| 最新版本 |
原理介紹:Wiki
Demo演示
demo下載(包含主工程demo和demo_component_a組件)
demo_component_b組件單獨運行的App(Demo_B)下載
以上2個app用來演示組件打包在主app內(nèi)和單獨以app運行時的組件調(diào)用,都安裝在手機上之后的運行效果如下圖所示
快速理解CC
定義組件:將自身的業(yè)務(wù)(頁面跳轉(zhuǎn)及服務(wù)調(diào)用等)封裝起來提供給外部調(diào)用,并返回執(zhí)行的結(jié)果
調(diào)用組件:根據(jù)組件名稱、業(yè)務(wù)名稱及其它參數(shù)調(diào)用指定組件的指定業(yè)務(wù),并獲得執(zhí)行的結(jié)果
組件將業(yè)務(wù)完全隔離在自身內(nèi)部,僅暴露組件名稱(ComponentName)、業(yè)務(wù)名稱(actionName)、參數(shù)列表及返回值等信息給外部調(diào)用
使用CC的理由
- 集成簡單,僅需4步即可完成集成:
1. 在根目錄build.gradle中添加自動注冊插件
2. 添加apply cc-settings.gradle文件
3. 實現(xiàn)IComponent接口創(chuàng)建一個組件
4. 使用CC.obtainBuilder("component_name").build().call()調(diào)用組件
- 完全的代碼隔離:CC支持跨app調(diào)用組件,開發(fā)時組件之間無需互相依賴
組件以app方式獨立運行時不需要依賴任何其它組件,從源頭上隔離代碼
無需擔(dān)心與主app的相互調(diào)用,從一開始組件化改造就可以單組件運行
跟打包在主app中運行是一樣的效果,能大大降低組件化改造的難度
- 改造成本低:接入時可基本不改原有代碼,原有組件的拆分工作不影響整體組件化改造,參考文章
- 組件層面的AOP支持:可以在組件內(nèi)部AOP完成登錄驗證和權(quán)限驗證等功能,調(diào)用方無需關(guān)注,參考文章
- Fragment/View的組件化支持:支持組件調(diào)用方式獲取及后續(xù)的功能調(diào)用,業(yè)務(wù)完全內(nèi)聚,參考文章
- 對Push及jsBridge友好:直接轉(zhuǎn)發(fā)對組件的調(diào)用即可,參考文章
- 免維護組件列表:使用gradle插件實現(xiàn)組件的自動注冊,插拔組件只需修改dependencies依賴即可
- 極低的學(xué)習(xí)成本,便于推廣使用:只需了解一個接口和一個靜態(tài)方法即可定義組件,只需了解一個鏈式調(diào)用即可調(diào)用組件
- 統(tǒng)一的定義方式和調(diào)用方式:面向協(xié)議來實現(xiàn)和調(diào)用組件,類似于移動端跟服務(wù)端的通信協(xié)議
了解業(yè)界開源的一些組件化方案:多個維度對比一些有代表性的開源android組件化開發(fā)方案
CC功能列表
1. 支持組件間相互調(diào)用(不只是Activity跳轉(zhuǎn),支持任意指令的調(diào)用/回調(diào))
2. 支持組件調(diào)用與Activity、Fragment的生命周期關(guān)聯(lián)
3. 支持app間跨進程的組件調(diào)用(組件開發(fā)/調(diào)試時可單獨作為app運行)
4. 支持app間調(diào)用的開關(guān)及權(quán)限設(shè)置(滿足不同級別的安全需求,默認打開狀態(tài)且不需要權(quán)限)
5. 支持同步/異步方式調(diào)用
6. 支持同步/異步方式實現(xiàn)組件
7. 調(diào)用方式不受實現(xiàn)方式的限制(例如:可以同步調(diào)用另一個組件的異步實現(xiàn)功能。注:不要在主線程同步調(diào)用耗時操作)
8. 支持添加自定義攔截器(按添加的先后順序執(zhí)行)
9. 支持超時設(shè)置
10. 支持手動取消
11. 編譯時自動注冊組件(IComponent),無需手動維護組件注冊表(使用ASM修改字節(jié)碼的方式實現(xiàn))
12. 支持動態(tài)注冊/反注冊組件(IDynamicComponent)
13. 支持組件間傳遞Fragment、自定義View等(組件在同一個app內(nèi)時支持、跨app傳遞非基礎(chǔ)類型的對象暫不支持)
13.1 不僅僅是獲取Fragment、自定義View的對象,并支持后續(xù)的通信。
14. 盡可能的解決了使用姿勢不正確導(dǎo)致的crash,降低產(chǎn)品線上crash率:
14.1 組件調(diào)用處、回調(diào)處、組件實現(xiàn)處的crash全部在框架內(nèi)部catch住
14.2 同步返回或異步回調(diào)的CCResult對象一定不為null,避免空指針
集成(共4步)
下面介紹在Android Studio中進行集成的詳細步驟
1. 添加引用
在工程根目錄的build.gradle中添加組件自動注冊插件
buildscript {
dependencies {
classpath 'com.billy.android:autoregister:x.x.x'
}
}
2. 在每個module(包括主app)的build.gradle中:
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
3. 實現(xiàn)IComponent接口創(chuàng)建組件
創(chuàng)建組件(實現(xiàn)IComponent接口,需要保留無參構(gòu)造方法)
public class ComponentA implements IComponent {
//需保留無參構(gòu)造方法
@Override
public String getName() {
//組件的名稱,調(diào)用此組件的方式:
// 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)) {
//調(diào)用方?jīng)]有設(shè)置context或app間組件跳轉(zhuǎn),context為application
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);
//發(fā)送組件調(diào)用的結(jié)果(返回信息)
CC.sendCCResult(cc.getCallId(), CCResult.success());
//返回值說明
// false: 組件同步實現(xiàn)(onCall方法執(zhí)行完之前會將執(zhí)行結(jié)果CCResult發(fā)送給CC)
// true: 組件異步實現(xiàn)(onCall方法執(zhí)行完之后再將CCResult發(fā)送給CC,CC會持續(xù)等待組件調(diào)用CC.sendCCResult發(fā)送的結(jié)果,直至超時)
return false;
}
}
4. 調(diào)用組件
//同步調(diào)用,直接返回結(jié)果
CCResult result = CC.obtainBuilder("ComponentA").build().call();
//或 異步調(diào)用,不需要回調(diào)結(jié)果
String callId = CC.obtainBuilder("ComponentA").build().callAsync();
//或 異步調(diào)用,在子線程執(zhí)行回調(diào)
String callId = CC.obtainBuilder("ComponentA").build().callAsync(new IComponentCallback(){...});
//或 異步調(diào)用,在主線程執(zhí)行回調(diào)
String callId = CC.obtainBuilder("ComponentA").build().callAsyncCallbackOnMainThread(new IComponentCallback(){...});
更多使用方式請戳這里
狀態(tài)碼清單
| 狀態(tài)碼 | 說明 |
|---|---|
| 0 | CC調(diào)用成功 |
| 1 | CC調(diào)用成功,但業(yè)務(wù)邏輯判定為失敗 |
| -1 | 保留狀態(tài)碼:默認的請求錯誤code |
| -2 | 沒有指定組件名稱 |
| -3 | result不該為null。例如:組件回調(diào)時使用 CC.sendCCResult(callId, null) 或 interceptor返回null |
| -4 | 調(diào)用過程中出現(xiàn)exception,請查看logcat |
| -5 | 指定的ComponentName沒有找到 |
| -6 | context為null,通過反射獲取application失敗,出現(xiàn)這種情況可以用CC.init(application)來初始化 |
| -7 | 跨app調(diào)用組件時,LocalSocket連接出錯 |
| -8 | 已取消 |
| -9 | 已超時 |
| -10 | component.onCall(cc) return false, 未調(diào)用CC.sendCCResult(callId, ccResult)方法 |
混淆配置
不需要額外的混淆配置
自動注冊插件
源碼:AutoRegister
原理:android掃描接口實現(xiàn)類并通過修改字節(jié)碼自動生成注冊表
