h5調用安卓方法

原文:http://blog.csdn.net/so_huangbo/article/details/55522205?utm_source=itdadao&utm_medium=referraljavascript

隨着移動互聯網的高速發展,常規的開發速度已經漸漸不能知足市場需求。原生H5混合開發應運而生,目前,市場上許多主流應用都有用到混合開發,例如支付寶、美團等。下面,結合我本人的開發經驗,簡單談一下對混合開發的認識以及實現方式。前端

混合開發的優勢

優勢顯而易見,由前端工程師寫一個頁面,多個平臺均可以運行,省了AndroidiOS工程師很多事,無形中提升了開發效率,節約了開發成本。java

缺點

凡是使用過的人都知道,H5的界面顯示在手機上,對點擊、觸摸、滑動等事件的響應並不如原生控件那樣流暢,甚至還會出現卡頓。這樣也很正常,若是體驗跟原生控件同樣好的話,也就沒androidios)工程師什麼事了。android

H5調用原生的方式

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

第一種

1.首先對WebView進行初始化web

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

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

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) {
    ArrayMap<String, String> queryStringMap = new ArrayMap<>();
    if (url.contains(pre)) {
        int index = url.indexOf(pre);
        int end = index + pre.length();
        String queryString = url.substring(end + 1);

        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 + 5);
                queryStringMap.put("data", dataValue);
            } else {
                queryStringParam = qs.split("=");

                String value = "";
                if (queryStringParam.length > 1) {
                    //避免後臺有時候不傳值,如「key=」這種
                    value = queryStringParam[1];
                }
                queryStringMap.put(queryStringParam[0].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;
    }
}

最後,特別說明一下shouldOverrideUrlLoading()方法的返回值問題,該方法的返回值有三種:

1.返回true,即根據代碼邏輯執行相應操做,webview不加載該url;

2.返回false,除執行相應代碼外,webview加載該url;

3.返回super.shouldOverrideUrlLoading(),點進父類中,咱們能夠看到,返回的仍是false。

相關文章
相關標籤/搜索