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

相关文章
相关标签/搜索