1. 程式人生 > >Android WebView、js互動方式原理總結

Android WebView、js互動方式原理總結

webView.loadUrl("javascript:console(" + "'Hello,China!'" + ")"");

二、js注入實現

先來說說原理吧,當js呼叫prompt()方法時,WebChromeClient.onJsPrompt()方法會被觸發,當js觸發Android提供的介面方法時,將該方法的方法名稱、引數型別、引數值轉成json,然後通過prompt方法傳遞給android端,android端解析json並通過反射執行對應的方法,同時也支援執行匿名回撥。 整個流程比較複雜,看圖:
為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,在低於API17的WebView上預設新增"SearchBoxJavaBridge_"到mJavaScriptObjects中。這樣就有可能通過使用者信任的客戶端獲取SD卡的資料; b.第一種方式必須要API大於等於17才能使用 c.第一種方式當有js回撥函式需要android端執行時,都需要將匿名回撥函式賦值給全域性函式才能供android端回撥,增加了js和android端通訊的封裝層的低效程式碼量;而第二種方式則是通過動態注入js的方式則非常方便。 d.第二種方式也有一定限制,比如android提供的方法必須是static修飾的,且方法第一個引數必須為WebView,不過這不影響使用。

最後,附上程式碼地址:

點我