android_jsbridge,讓你和前端愉快的互動

zlove發表於2019-03-01

android_js

前言

作為開發人員都知道,客戶端的版本更新對於使用者來說代價是很大的。為了滿足客戶端能夠快速更新迭代的要求,許多app都內嵌入了H5,比如很多電商平臺,淘寶、京東、
聚划算等等。這類技術的關鍵就是在於Android客戶與Web前端之間的互動。很多大型專案的介面為了防止Spammer的侵入,都是要求只能由客戶端發起請求的。所以本專案
就封裝了一個module,實現客戶端接收前端的呼叫,然後由客戶端發起Http請求的功能。
複製程式碼
開始介紹專案之前,先來快速回顧一下Android客戶端與Web前端之間互動的幾種方式。
複製程式碼

1. Android呼叫JS方法

1.1 通過WebView的loadUrl()

android客戶端程式碼:

 private void initWebView() {
    WebSettings webSettings = webView.getSettings();
    webSettings.setJavaScriptEnabled(true); // 設定與Js互動的許可權
    webSettings.setJavaScriptCanOpenWindowsAutomatically(true); // 設定允許JS彈窗

    webView.loadUrl("file:///android_asset/javascript.html");
    webView.setWebChromeClient(new WebChromeClient() {

        @Override
        public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
            AlertDialog.Builder b = new AlertDialog.Builder(SimpleWebViewActivity.this);
            b.setTitle("Alert");
            b.setMessage(message);
            b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    result.confirm();
                }
            });
            b.setCancelable(false);
            b.create().show();
            return true;
        }
    });
}

private void setListener() {
    btnLoadUrl.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            webView.post(new Runnable() {
                @Override
                public void run() {
                    // 此處的callJS方法名與JS中的function方法名必須要一致
                    webView.loadUrl("javascript:callJS()");
                }
            });
        }
    });
}
複製程式碼

javascript前端程式碼:

  <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>Carson_Ho</title>
        // JS程式碼
        <script>
            // Android需要呼叫的方法
           function callJS() {
              alert("Android呼叫了JS的callJS方法");
           }

        </script>
    </head>
    </html>
複製程式碼
執行結果如圖
複製程式碼
android_jsbridge,讓你和前端愉快的互動

    android客戶端程式碼:

 btnEvaluateJavascript.setOnClickListener(new View.OnClickListener() {

        @TargetApi(19)
        @Override
        public void onClick(final View v) {
            webView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
                @Override
                public void onReceiveValue(String value) {
                    //此處為 js 返回的結果
                    Log.d(TAG, "value---" + value);
                }
            });
        }
    });
複製程式碼
執行結果跟上圖是一樣的。
複製程式碼
兩種互動方式的比較
複製程式碼
呼叫方式 優點 缺點 使用場景
使用loadUrl() 方便簡潔 效率低;獲取返回值麻煩 不需要使用返回值,對效能要求較低
使用evaluateJavascript() 效率高 向下相容性差(僅Android 4.4以上可用) Android 4.4及以上

1.3 使用建議

// Android版本變數
final int version = Build.VERSION.SDK_INT;
// 因為該方法在 Android 4.4 版本才可使用,所以使用時需進行版本判斷
if (version < 18) {
    webView.loadUrl("javascript:callJS()");
} else {
    webView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
        @Override
        public void onReceiveValue(String value) {
            //此處為 js 返回的結果
        }
    });
}
複製程式碼

2. JS呼叫Android方法

2.1 通過WebView的addJavascriptInterface()進行物件對映

程式碼不再貼出,詳細程式碼請參見:程式碼地址
   執行結果如下:

android_jsbridge,讓你和前端愉快的互動

2.2 通過 WebViewClient 的方法shouldOverrideUrlLoading()回撥攔截 url

程式碼不再貼出,詳細程式碼請參見:程式碼地址
   執行結果如下:

android_jsbridge,讓你和前端愉快的互動

2.3 通過 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回撥攔截JS對話方塊alert()、confirm()、prompt()訊息

程式碼不再貼出,詳細程式碼請參見:程式碼地址
   執行結果如下:

android_jsbridge,讓你和前端愉快的互動
2.3.1 onJsAlert()、onJsConfirm()、onJsPrompt()三者之間的比較
方法 作用 返回值
alert() 彈出警告框 沒有
confirm() 彈出確認框 兩個返回值(true或false)
prompt() 彈出輸入框 任意設定返回值
2.3.2 總結
常用的攔截是:攔截 JS的輸入框(即prompt()方法),因為只有prompt()可以返回任意型別的值,操作最全面方便、更加靈活,
而alert()對話方塊沒有返回值,confirm()對話方塊只能返回兩種狀態(確定 / 取消)兩個值。
複製程式碼

2.4 三種Android Call Js 方式的對比以及使用場景

呼叫方式 優點 缺點 使用場景
通過WebView的addJavascriptInterface()
進行物件對映
方便簡潔 Android 4.2以下存在漏洞問題 Android 4.2以上相對簡單的互調場景
通過 WebViewClient 的方法shouldOverrideUrlLoading()
回撥攔截 url
不存在漏洞問題 有協議約束,客戶端向前端傳值繁瑣 不需要返回值的互調場景
通過 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法
回撥攔截JS對話方塊alert()、confirm()、prompt()訊息
不存在漏洞問題 有協議約束 能滿足大多數情況下的互調場景

附:WebView的addJavascriptInterface()方法在Android 4.2以下存在的漏洞

以上都是對基礎知識的回顧,下面的才是本專案的解釋說明。注意了,以下才是本專案的解釋說明!!

先來看一下專案執行的效果圖:
複製程式碼
android_jsbridge,讓你和前端愉快的互動
大家會說,這個不是跟攔截JS的prompt()方法一樣麼,沒錯,js和android之間的互動,也無非上面提到的幾種方法,這裡做的封裝採用的是:
js調android:通過WebView的addJavascriptInterface()進行物件對映
android回撥js:android 4.4以上採用WebView的evaluateJavascript()方法,android 4.4以下采用loadUrl()方法
複製程式碼
android端程式碼:
複製程式碼

JsBridgeWebView 這是一個繼承WebView的類,它裡面向JS注入了一個物件供JS呼叫,JS可以通過這個物件呼叫Native的方法,調哪個方法,傳哪些引數,完全由JS決定,方法名必須兩端協議,Native通過反射找到對應的方法。傳遞過來的引數重包含了JS回撥方法的方法名,客戶端執行完相應的操作之後再去執行JS的方法。

js程式碼:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
        <title>Carson</title>
        <script>
            function callAndroid(){
                // 由於物件對映,所以呼叫jsCallback物件等於呼叫Android對映的物件
                var json = "{"name": "zlove", "_dscbstub": "callback"}"
                _jsbridge.call("testAsync", json);
             }
             function callback(result) {
                alert("客戶端返回的結果是:" + result)
             }
        </script>
</head>
<body>
<!-- 點選按鈕則呼叫callAndroid函式 -->
<button type="button" id="button1" style="font-size:30px" onclick="callAndroid()">Call Android</button>
</body>
</html>
複製程式碼
var json = "{"name": "zlove", "_dscbstub": "callback"}" 
_jsbridge.call("testAsync", json);
_jsbridge表示客戶端注入的物件,testAsync是方法名,json是引數,而_dscbstub對應的callback是js的回撥方法。
複製程式碼

end

本來以為要寫很多,事實上其實把基礎原理寫清楚了,也就這麼多???。
I hope this will help you!
複製程式碼

附:原始碼地址

相關文章