hybrid(H5)與客戶端通訊

什麼是hybrid?

就是嵌入在客戶端的H5頁面, 也就是咱們常說的webview.它跟瀏覽器中的html頁面區別不大.由於大都是由webkit渲染引擎渲染出來的.javascript

webkit渲染引擎主要由下面幾個部分組成html

  1. js引擎線程
  2. GUI渲染線程
  3. 定時器線程
  4. 異步http線程
  5. 事件觸發線程

異步事件處理都是經過Event Loop. 因此webview瀏覽器頁面對於前端開發者來講根本沒啥區別。可是webview是運行在AndroidIOS系統裏面,那它們之間是如何進行通訊的呢?下面我將以Android爲例來探究他們之間的通訊方式前端

先搭建環境

第一步

android新建一個簡單的項目java

第二步

建一個簡單html頁面以下,放在android項目的src/main/assets目錄裏面jquery

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>shop</title>
</head>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" type="text/javascript">
</script>
<body>
<div>我是webview</div>
<div id="cs">測試JavascriptInterface</div>
</body>
<script>
    let i = 0;
    $("#cs").on("click", function(){
        android.showToast("我是彈窗");
    })
</script>
</html>
複製代碼

第三步

載入webviewandroid

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 開始webview調試模式
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        WebView.setWebContentsDebuggingEnabled(true);
    }
    WebView webView = (WebView)findViewById(R.id.shop);
    webView.getSettings().setJavaScriptEnabled(true);
    webView.loadUrl("file:///android_asset/shop.html");
}
複製代碼

頁面就出來了 git

hybridAndroid通訊方式

第一種 JavascriptInterface

就是在js上下文注入一個JavascriptInterface.假設這個JavascriptInterface名爲AndroidIn. 那麼在webview裏面能夠直接調用Androidgithub

android代碼web

WebView webView = (WebView)findViewById(R.id.shop);
webView.getSettings().setJavaScriptEnabled(true);
 class JsInterface {
    @JavascriptInterface
    public void showToast(String toast) {
        Toast.makeText(MainActivity.this, toast, Toast.LENGTH_SHORT).show();
    }
}
webView.addJavascriptInterface(new JsInterface(), "AndroidIn");
複製代碼

html代碼json

<div>我是webview</div>
<div id="cs">測試JavascriptInterface</div>
</body>
<script>
    let i = 0;
    $("#cs").on("click", function(){
        AndroidIn.showToast("我是彈窗");
    })
</script>
複製代碼

點擊以後出現我是彈窗

第二種 onJsAlert, onJsConfirm, onJsPrompt

android能夠攔截js調用警告框,輸入框,和確認框

android代碼

WebView webView = (WebView)findViewById(R.id.shop);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebChromeClient(new WebChromeClient(){
    @Override
    public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
        new AlertDialog.Builder(MainActivity.this)
                .setTitle("JsAlert")
                .setMessage(message)
                .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        result.confirm();
                    }
                })
                .setCancelable(false)
                .show();
        return true;
    }
});
複製代碼

html代碼

<div>我是webview</div>
<div id="cs">測試JavascriptInterface</div>
</body>
<script>
    let i = 0;
    $("#cs").on("click", function(){
        alert("我是彈窗");
    })
</script>
複製代碼

點擊以後彈窗已經換成了原生的彈窗了

第三種 URL參數

android載入h5文件的時候在地址上加一些參數

webView.loadUrl("file:///android_asset/shop.html?a=12&b=12");
複製代碼

h5頁面經過href連接能夠拿到a,b

第四種loadUrl

android能夠經過loadUrl直接執行js的方法 H5代碼

window.Bridge = {
    callJS(){
      alert("我是callJS")
    }
}
複製代碼

android代碼

webView.loadUrl("javascript:Bridge.callJS()");
複製代碼

第五種evaluateJavascript

跟上面差很少,只不過android 4.4以上才能用

webView.evaluateJavascript("javascript:Bridge.callJS()", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String value) {
        //此處爲 Bridge.callJS返回的結果
    }
});
複製代碼

第六種 JsBridge

什麼是Jsbridge? JsBridge並非Android或者H5直接就有的API.它是一種經過上面五種通訊方式(遵循某種協議)來實現的一個雙向通訊橋. 下面來實現一個簡單的 JsBridge

  1. 每次調用原生方法都會生成一個對應callBack惟一id.客戶端回調會告訴返回對應的id來執行對應的callback
  2. callNativeH5調用Android原生的方法,是經過JavascriptInterface注入一個nativeBridge來實現的.
  3. receiveNativeAndroid原生調用H5的方法,是經過webView.loadUrl("javascript:window.Bridge.receiveNative("")來實現.

你能調用我,我能調用你,而後經過某個協議(id).一個雙工通訊就實現了

H5代碼以下

<body>
    <div>我是webview</div>
    <div id="cs">測試JavascriptInterface</div>
</body>
<script>
    let cid = 0;
    let callbacks = {};
    window.Bridge = {
        // 獲取用戶的登陸信息
        getUserInfo(data = {}){
            window.Bridge.callNative("getUserInfo", data)
        },
        // 獲取網絡狀況
        getNetInfo(data = {}){
            window.Bridge.callNative("getNetInfo", data)
        },
        callNative: function(bridgeName, data) {
            cid++;
            if (data.onSuccess) {
                callbacks[cid] = data.onSuccess;
            }
            nativeBridge.postMessage(JSON.stringify({
                cid,
                bridgeName: bridgeName,
                data: data.params || {}
            }));
         },
        receiveNative: function(msg) {
            callbacks[msg.cid] && callbacks[msg.cid](msg);
            if (msg.bridgeName != "getNetInfo") {
                Reflect.deleteProperty(callbacks, msg.cid);
            }
        }
    }
    document.getElementById("cs").onclick = function(){
        window.Bridge.getUserInfo({
            params:{},
            onSuccess(res){
                alert(res.name)
            }
        })
    }
</script>
複製代碼

Android代碼以下

final WebView webView = (WebView)findViewById(R.id.h5_shop);
final Handler handler = new Handler(){
    public void handleMessage(Message msg) {
        if (msg.what == 1) {
            webView.loadUrl("javascript:window.Bridge.receiveNative("+resObj.toString()+")");
        }
    }
};
webView.getSettings().setJavaScriptEnabled(true);
class JsInterface {
    @JavascriptInterface
    public void postMessage(String a) throws JSONException{
        JSONObject jsonObj = new JSONObject(a);
        String bridgeName = jsonObj.getString("bridgeName");
        if ( bridgeName.equals("getUserInfo") ){
            resObj.put("cid", jsonObj.get("cid"));
            resObj.put("name", "leiwuyi");
            Message msg = new Message();
            msg.what = 1;
            handler.sendMessage(msg);
        } 

    }
}
webView.addJavascriptInterface(new JsInterface(), "nativeBridge");
webView.loadUrl("file:///android_asset/shop.html");
複製代碼

點擊以後效果以下

demo地址以下github

相關文章
相關標籤/搜索