CC框架實踐(3): 讓jsBridge更優雅

前言

今天給你們講一下在CC框架下如何讓咱們的jsBridge更加優雅。javascript

jsBridge是做爲js和java之間通訊的橋樑,自己它的職責只是完成通訊。java

本文不是介紹js與java通訊過程的實現,你可使用第三方庫(如:JsBridge),也能夠本身來實現,或者用addJavascriptInterface,均可以。本文的側重點是如何讓咱們的jsBridge不那麼臃腫,實現得更優雅,更利於維護。android

但在實際封裝過程當中,會發現須要咱們須要解決不少耦合的問題:git

  • js調用的功能在其餘module中,如何調用到這些功能,如何向jsbridge註冊這些功能?
  • jsbridge依賴了太多module,怎麼解耦?
  • 當js調用的功能是打開其它頁面獲取該頁面處理後的結果並回調給js,怎麼破? onResume? startActivityForResult? 一個常見的場景是:打開登陸界面,登陸成功後將用戶信息回調給js。你是否是想過這樣作?
    • jsBridge中封裝一個Activity/Fragment
    • 用startActivityForResult的方式來打開登陸頁面
    • 在onActivityResult方法中從登陸界面設置的result中獲取用戶登陸的信息(或者onResume或EventBus方式來獲取返回值)
    • 而後將用戶信息回調給js

將具體的業務邏輯寫在jsBridge模塊中,自己就是一個災難,並且隨着業務類型的增長,最後這個Activity/Fragment會變得很是臃腫,並且難以複用github

快速瞭解CC

  • 是一套基於組件總線的組件化實施方案
  • 一靜一動,開發時運行2個app,業務環境始終是完整的:
    • 靜:主App (經過跨App的方式調用單組件App內的組件)
    • 動:正在開發中的單組件App (經過跨App的方式調用主App內的組件)
  • 支持漸進式組件化改造
    • 解耦只是過程,而不是前提

CC框架下如何讓jsBridge更優雅?

CC框架爲全部組件提供了統一的調用入口和回調結果格式。web

因此,在CC框架下,js調用native變得很簡單:json

  • jsBridge僅暴露一個接口給js,那就是組件調用接口
  • js調用jsBridge的接口,將組件調用所需的參數傳給jsBridge
  • jsBridge將參數透傳去調用功能組件(全部功能實現均在各個組件內部完成)
  • jsBridge中接收到調用結果後,將結果轉換成json回調給js

流程圖:app

jsBridge調用流程

JsBridge的核心代碼以下:框架

public class JsBridge {

    private WeakReference<WebView> webViewWeakReference;

    public JsBridge(WebView webView) {
        this.webViewWeakReference = new WeakReference<WebView>(webView);
    }

    @JavascriptInterface
    public void callNativeCC(String componentName, String actionName, String dataJson, final String callbackId) {
        final WebView webView = webViewWeakReference.get();
        if (webView == null) {
            return;
        }
        Map<String, Object> params = null;
        if (!TextUtils.isEmpty(dataJson)) {
            try {
                JSONObject json = new JSONObject(dataJson);
                params = JsonUtil.toMap(json); //參數列表
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        //統一使用這種方式進行CC調用,不用關心具體組件是如何實現的
        CC cc = CC.obtainBuilder(componentName)
            .steActionName(actionName)
            .setContext(webView.getContext()) //可用於startActivity等須要Context的功能
            .setParams(params)
            .build();
        if (TextUtils.isEmpty(jsCallbackId)) {
            cc.callAsync(); //無需回調結果給js
        } else {
            cc.callAsyncCallbackOnMainThread(new IComponentCallback() {
                @Override
                public void onResult(CC cc, CCResult result) {
        			//將結果回調給js
                    webView.loadUrl("javascript: callback(" + callbackId + "," + result + ")"); 
                }
            });
        }
    }
}

複製代碼

是否是超級簡單?異步

這樣作的好處有:

  1. jsbridge迴歸初心:只是做爲一個橋樑。
  2. jsBridge支持的功能更全面,app內部幾乎全部組件的功能均可以給js調用,而無需添加額外的代碼
  3. 業務徹底在組件內部實現,jsbridge跟組件之間無耦合
  4. 不管功能是同步實現的仍是異步回調實現的,中間須要經歷什麼樣的流程,對於js和jsBridge來講調用方式徹底同樣。
  5. 支持組件的按需依賴:jsBridge再也不是全家桶,給多個app使用時,各app能夠按需選擇須要支持js調用的組件,添加gradle依賴到主module的依賴列表中便可。
  6. 同一個組件在不一樣的app內能夠有不一樣的實現,但須要保持接口協議一致,例如:不一樣app能夠有本身特定的登陸組件
  7. 後續添加新功能給js調用時,只要功能提供方實現一下,js中去調用便可,jsbridge組件無需修改

Tips


1. 有些功能必需要在onActivityResult中接收結果,如何在組件內部實現而不影響jsBridge?

確實有些功能必需要在onActivityResult中接收結果,例如:調用系統的選擇聯繫人、從系統相冊選擇圖片等。

其實,不止是onActivityResult,還有獲取權限的回調onRequestPermissionsResult

這些功能在組件內部實現時,能夠在組件中經過建立一個透明的Activity或Fragment來實現結果的接收,而後將結果發送給調用方: CC.sendCCResult(callId, result);

推薦使用Fragment方式實現

具體實現方式可參考以下開源庫:

2. js調用的有些功能須要用戶登陸後才能用,如何加入登陸條件判斷?

按照組件化開發的思想,是否須要登陸才能用應由各組件自行判斷。

須要在組件內部完成登陸狀態校驗、打開登陸界面、登陸完成後再執行組件實際功能。

具體實現可參考另外一篇文章: CC框架實踐(1):實現登陸成功再進入目標界面功能

3. 沒有使用CC框架的狀況下,如何讓jsBridge實現相似效果?

在沒有使用CC框架的狀況下,也能夠實現相似效果的。思路以下:

  1. 在工程的Common基礎庫中定義一套接口,例如: IJsCall/IJsCallback
public interface IJsCall {
    String name(); //功能的名稱,供js調用
    void handleJsCall(JSONObject params, IJsCallback callback);
}
public interface IJsCallback {
    void callback(String result);
}
複製代碼
  1. 在全部須要註冊給js調用的組件中實現IJsCall接口,實現具體的業務邏輯
  2. 在jsBridge中建立一個IJsCall的管理類JsCallMananger,示例代碼:
public class JsCallManager {
    private final Map<String, IJsCall> map = new HashMap<>();
    
    public static final String DEFAULT_RESULT = "{\"success\":false}";
    
    void init() {
        //用於IJsCall自動註冊到list
        //使用AutoRegister插件將生成以下代碼:
        // registerJsCall(new JsCallA());
        // registerJsCall(new JsCallB());
    }
    
    void registerJsCall(IJsCall call) {
        if (call != null) {
            map.put(call.name(), call);
        }
    }
    
    public void onJsCall(String name, JSONObject json, IJsCallback callback) {
        IJsCall jsCall = map.get(name);
        if (jsCall != null) {
            jsCall.handleJsCall(json, callback);
        } else {
            callback.callback(DEFAULT_RESULT);
        }
    }
}
複製代碼
  1. 使用AutoRegister來完成IJsCall接口的自動註冊, Github源碼原理介紹
  2. 在jsBridge中只暴露一個接口給js調用
  3. 在jsBridge中調用JsCallManager.onJsCall方法來實現統一的功能調用

總結


本文介紹了在CC框架下用組件調用的方式讓jsBridge實現跟具體業務徹底解耦。並給出了非CC框架環境下實現相似效果的思路。

系列文章


CC:可關聯生命週期的android組件化開發框架

CC框架實踐(1):實現登陸成功再進入目標界面功能

CC框架實踐(2):Fragment和View的組件化

CC框架實踐(3): 讓jsBridge更優雅

相關文章
相關標籤/搜索