天天看點

Android 與h5互動 協定

H5調用原生的方式

方式可能有多種,根據我本人的開發經驗,我接觸過兩種方式。

第一種

1.首先對WebView進行初始化

WebSettings settings = webview.getSettings();
settings.setJavaScriptEnabled(true); //允許在WebView中使用js
           

2.建立一個類JavaScriptMetod,專門用來給js提供可調用的方法

3.建立該類的構造方法,提供兩個參數,WebView對象和上下文對象

private Context mContext;
    private WebView mWebView;
    public JavaScriptMethod(Context context, WebView webView) {
        mContext = context;
        mWebView = webView;
    }
           

4.建立一個字元串常量,作為android與js通信的接口,即字元串映射對象

public static final String JAVAINTERFACE = "javaInterface";
           

5.接下來就是建立給js調用的方法,方法的參數接收一個json字元串(注意:在Android4.2之後,為了提高代碼安全性,方法必須使用注解@JavascriptInterface,否則無法調用)

@JavascriptInterface
    //andorid4.2(包括android4.2)以上,如果不寫該注解,js無法調用android方法
    public void showToast(String json){
        Toast.makeText(context, json, Toast.LENGTH_SHORT).show();
    }
           

6.在WebView初始化代碼中執行如下代碼,

//建立上面建立類的對象
    JavaScriptMetod m = new JavaScriptMetod(this, webview);
    //其實就是告訴js,我提供給哪個對象給你調用,這樣js就可以調用對象裡面的方法
    //第二個參數就是該類中的字元串常量
    webview.addJavascriptInterface(m, JavaScriptMetod.javaInterface);
           

現在,在js中就可以調用JavaScriptMetod中的方法了,調用方式如下

//參數一般為json格式
    var json = {"name":"javascript"};
    //javaInterface是上面所說的字元串映射對象
    window.javaInterface.showToast(JSON.stringify(json));
           

網絡上介紹js與android原生互動的文章裡,大部分都是上面這種方式,但是這種方式并不适用于ios,也就是說,window.javaInterface.showToast(JSON.stringify(json))這樣的js代碼并不适用于ios,如果用以上的方法,就得分别為android和ios各寫一套js代碼。這樣很顯然是不太合理的,是以在實際開發中,一般都使用接下來的第二種方法。

第二種

這種方法實作的思想是js發出一個url請求,并将所需的參數添加到該url中。android端通過webView.setWebViewClient()攔截url,解析url中攜帶的參數,并根據參數資訊進行相應的操作。

1.與方法一相同,首先都需要對webview進行初始化

WebSettings settings = webview.getSettings();
    settings.setJavaScriptEnabled(true); //允許在WebView中使用js
           

2.首先看js中的代碼是怎麼寫的,

$("#showtoast").click(function () {
        var json = {"data": "I am a toast"};
       window.location.href="protocol://android?code=toast&data="+JSON.stringify(json);
    });
    $("#call").click(function () {
        var json = {"data": "10086"};
       window.location.href="protocol://android?code=call&data="+JSON.stringify(json);
    });
           

這裡定義兩個點選事件,分别控制android顯示吐司和打電話的操作。其中,protocol://android為自定義的H5與android間的通信協定,與http請求進行區分。code規定了要進行的操作,data為傳輸的資料。

2.android中的代碼

webView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                /**
                 * 通過判斷攔截到的url是否含有pre,來辨識是http請求還是調用android方法的請求
                 */
                String pre = "protocol://android";
                if (!url.contains(pre)) {
                    //該url是http請求,用webview加載url
                    return false;
                }
                //該url是調用android方法的請求,通過解析url中的參數來執行相應方法
                Map<String, String> map = getParamsMap(url, pre);
                String code = map.get("code");
                String data = map.get("data");
                parseCode(code, data);
                return true;
            }
        });
           

其中,getParamsMap()方法從攔截到的url解析出code,data參數,parseCode()方法将根據不同的code進行相應的操作,代碼如下:

private Map<String, String> getParamsMap(String url, String pre) {
        Map<String, String> queryStringMap = new HashMap<>();
        if (url.contains(pre)) {
            int index = url.indexOf(pre);
            int end = index + pre.length();
            String queryString = url.substring(end + );

            String[] queryStringSplit = queryString.split("&");

            String[] queryStringParam;
            for (String qs : queryStringSplit) {
                if (qs.toLowerCase().startsWith("data=")) {
                    //單獨處理data項,避免data内部的&被拆分
                    int dataIndex = queryString.indexOf("data=");
                    String dataValue = queryString.substring(dataIndex + );
                    queryStringMap.put("data", dataValue);
                } else {
                    queryStringParam = qs.split("=");

                    String value = "";
                    if (queryStringParam.length > ) {
                        //避免背景有時候不傳值,如“key=”這種
                        value = queryStringParam[];
                    }
                    queryStringMap.put(queryStringParam[].toLowerCase(), value);
                }
            }
        }
        return queryStringMap;
    }

    private void parseCode(String code, String data) {
        if(code.equals("call")) {
            try {
                JSONObject json = new JSONObject(data);
                String phone = json.optString("data");
                //執行打電話的操作,具體代碼省略
                PhoneUtils.call(this, phone);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return;
        }
        if(code.equals("toast")) {
            try {
                JSONObject json = new JSONObject(data);
                String toast = json.optString("data");
                Toast.makeText(this, toast, Toast.LENGTH_SHORT).show();
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return;
        }
    }
參考部落格:https://blog.csdn.net/so_huangbo/article/details/55522205?utm_source=itdadao&utm_medium=referral