和編程在一起的第三年 : Android WebView、js交互方式原理總結

5699111-782b65f81ae79343.jpg
6826752-871b78d79223ff02.jpg

前言

好的,今天是2018.4.18日,是我和Android在一起的第三年。今天分享給大家的是Android WebView 、Js交互方式的原理總結。也是筆者參加第一次面試的時候被問到的。很尷尬,當時清楚的記得 沒答出來..只是籠統的說了說WebView.

雞湯

精通android的人有,精通javascript的人亦有,但同時深入掌握兩門語言的人少有!

正文

android與js交互有兩種方式,第一種是通過系統提供的@JavascriptInterface註解實現,第二種就是js注入。下面來詳細講解一下二者的使用方式,原理,區別。

一、@JavascriptInterface實現

實現步驟:

  • a.設置WebView支持js腳本

  • b.爲提供給js調用的方法加上@JavascriptInterface註解

  • c.給WebView添加js接口

webView.getSettings().setJavaScriptEnabled(true);  
webView.addJavascriptInterface(new JSMethod(mContext), "lh");  
public class JSMethod {  
private Context mContext;  

public JSMethod(Context mContext) {  
    this.mContext = mContext;  
}  
@JavascriptInterface  
public void toast(String msg) {  
    Toast.makeText(mContext, msg == null ? "" : msg, Toast.LENGTH_SHORT).show();  
}  
}  

js端調用android方法:

lh.toast("Hello,China!");  

android端執行js方法:

 android端執行js方法:

二、js注入實現

先來說一下原理吧,當js調用prompt()方法時候,WebChromeClient.OnJsPrompt()方法會被觸發,當js觸發Android提供的接口方法時候,將該方法的名稱、參數類型、參數值轉成Json、然後通過prompt方法傳遞給Android端、android端解析json並通過反射執行對應的方法,同時也支持執行匿名回調。

5699111-e396b2906b411423.png
image.png

爲WebView綁定WebChormeClient監聽,在Html加載進度25%時進行js注入(注入的Js是根據android提供給Js的對象類名動態生成)

動態注入的Js代碼如下:

javascript: (function(b) {  
console.log("HostApp initialization begin");  
var a = {  
    queue: [],  
    callback: function() {  
          
        var d = Array.prototype.slice.call(arguments, 0);//獲取該函數參數並轉換爲Array數組  
        var c = d.shift();//取得數組第一個元素  
        var e = d.shift();  
        this.queue[c].apply(this, d);//新建一個對象 屬性名稱爲取得的c,並將d數組作爲他的值。然後將這個對象push到queue數組  
        if(!e) {//e爲空的時候,將queue數組屬性名稱爲c的對象刪除  
            delete this.queue[c]  
        }  
    }  
};  
//各種賦值,最後都等於同一個函數  
a.alert = a.alert = a.alert = a.delayJsCallBack = a.getIMSI = a.getOsSdk = a.goBack = a.overloadMethod = a.overloadMethod = a.passJson2Java = a.passLongType = a.retBackPassJson = a.retJavaObject = a.testLossTime = a.toast = a.toast = function() {  
    var f = Array.prototype.slice.call(arguments, 0);  
    if(f.length < 1) {  
        throw "HostApp call error, message:miss method name"  
    }  
    var e = [];  
    //此段判斷,然後賦值  
    for(var h = 1; h < f.length; h++) {  
        var c = f[h];  
        var j = typeof c;  
        e[e.length] = j;  
        if(j == "function") {  
            var d = a.queue.length;  
            a.queue[d] = c;  
            f[h] = d  
        }  
    }  
    //將匿名對象{method: f.shift(),types: e,args: f}轉換成json字符串並用瀏覽器彈出確認可輸入框,然後取得輸入框的值json序列化爲js對象  
    var g = JSON.parse(prompt(JSON.stringify({  
        method: f.shift(),  
        types: e,  
        args: f  
    })));  
    if(g.code != 200) {  
        throw "HostApp call error, code:" + g.code + ", message:" + g.result  
    }  
    return g.result  
};  
//獲取a的屬性值,然後循環  
Object.getOwnPropertyNames(a).forEach(function(d) {  
    var c = a[d];  
    //判斷賦值  
    if(typeof c === "function" && d !== "callback") {  
        a[d] = function() {  
            //concat 連接兩個數組  
            return c.apply(a, [d].concat(Array.prototype.slice.call(arguments, 0)))  
        }  
    }  
});  
b.HostApp = a;  
console.log("HostApp initialization end")  
 })(window);//閉包函數默認執行,然後賦給window。這樣window.b就可以執行了 b.HostApp就是執行a的內容,但是a具體處理邏輯不對外開放,避免外部污染a內部邏輯  

代碼不難,可以自行理解,其中回調函數被封裝在了a對象裏面,確保android 端可以通過webview.loadUrl()執行回調。

android端回調js代碼如下:

javascript:HostApp.callback(0, 0 ,"call back haha");  

android 提供的每一個Js方法都對應一個JsCallBack對象。android就可以通過JsCallBack對象來生成並執行回調js的代碼。

三、優缺點。

  • a第一種方式不安全,不添加addJavaScriptInterface,甚至默認爲false,在低於API的webView上默認添加"SearchBoxJavaBridge_"到mJavaScriptObjects中。這樣就有可能通過用戶信任的客戶端獲取SD卡的數據。

  • b 第一種方式必須要API大於17纔可以用。

  • c. 第一種方式當有js回調函數需要android端執行時,都需要將匿名回調函數賦值給全局函數才能供android端回調,增加了js和Android端通信的封裝層的低效代碼量;而第二種方式則是通過動態注入Js的方式則非常方便。

  • d 第二種方式也有一定的限制,比如android提供的方法必須是static修飾的。且方法第一個參數必須爲webView,不過這不影響使用。

最後,附上代碼地址:源碼地址

面試的幾個建議:

1.簡歷要如實寫,相關的知識點一定要爛熟於心。
2.基礎紮實,android和java相關的知識樹網上有很多資料,看過但讓你講出來未必能說的好。
3.提前總結,你還擅長什麼其他技術?這種開放問題要看知識面了。
4.學會提問,你有什麼問題要問我嗎?這種禮貌性問題也是一個瞭解對方的好機會。
5.良好的心裏素質,無論遇到什麼情況,面試官遲到、面試官態度冰冷說話不客氣、質疑你的回答等等各種問題都不要慌也不要排斥,一定要沉住氣,耐心積極的思考並回答對方的提問。
6.推薦幾本書,也是好幾次面試後發現裏面涵蓋了大部分答案。《Android開發藝術探索》《Android源碼設計模式-解析與實戰》《Android進階之光》《深入理解Java虛擬機》,多看幾遍。

大廠的面試流程比較長,面試是一場全面大考驗,如果想換個工作,最好提前充分準備,最後,看到這裏的人給你點個贊並有福利嘍,下面的鏈接是對以上一些問題的答案的整理,以及一些其他的經典問題,鏈接:面試那些事。其中因爲時間問題其他主題還沒有開始動筆,並且引用了很多博客鏈接,希望相關博主不要介意。僅作爲參考。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章