搭建 Android 混編框架(1)
混合 Android 框架流行一時,個人也用過像 hbuilder 或 cordova 這樣框架開發過一兩個應用,只是停留在用的層面上,直到前一段時間才研究了一下其內部的機制,自己通過學習別人的思想而受啟發自己研究了一套解決方案。
在 Android 混合開發的框架中,有以下幾個技術難點是我們需要克服的。
-
javascript 和原生 java 互調
首先我們來看框架中,是如何實現 javascript 和 java 的互調,也就是兩種語言間的通訊。傳統方式是通過暴露全域性物件來實現 javascript 和 java 進行互調方法,這樣做耦合度高,不安全,而且不可控。
思路是 javascript 端向 dom 新增一個 iframe,然後通過 iframe 發起請求來呼叫原生的方法,傳遞函式,這樣達到解耦的目的,自然也提高了應用的安全性。我們需要定義 url 的特定 schema 來區分普通 url 請求和呼叫原生方法的請求。
<iframe srt="zidea://<原生方法名>?param=<引數物件>&callback=<回撥>" style="display:none;"> zidea://<原生方法名>?param=<引數物件>&callback=<回撥>
這裡我們解釋一下
- schema : zidea 作為 schema 表示這一次請求原生 java 方法的請求,而並非普通 http 請求。
- 原生方法名 : 我們呼叫 java 端對應的原生方法名稱,其實 java 我們可以定義 action 來對應這次請求的原生方法名
- 引數 : 這裡可以以物件形式來傳遞引數以備原生方法使用
- 回撥 : 當原生方法執行完畢會呼叫這個回撥函式以將處理的結果傳遞迴 javascript 端。
var Native = (function(){ var _SCHEME = "zidea" function _callNativeMethod(_method, _param, _callback){ var param = JSON.stringify(_param); var url = _SCHEME + "://" + _method + "?param=" + param + "&callback=" + _callback; var iframeEle = document.createElement("iframe"); iframeEle.setAttribute("src",url); iframeEle.style.display = "none"; console.log(url); // var bodyEle = document.getElementsByTagName("body"); document.body.appendChild(iframeEle); setTimeout(function(){ iframeEle.remove(); },1000); } return{ goto:function(intent){ _callNativeMethod("startActivity",intent.param,intent.callback); }, updateHeader:function(obj){ console.log(obj); _callNativeMethod("updateTitile",obj.param,obj.callback); } } })()
通過上面解釋,我們來簡單地在 javascript 這一側實現一下,定義一個 schema 為 zidea
然後定義一個全域性物件 Native 接受一個立即執行函式的返回物件,其中內部封裝一個 _callNativeMethod 方法。方法就是將一個發起呼叫原生方法請求的 iframe 新增到 dom 上,然後以一定時間內銷燬 iframe 以達到銷燬請求的目的。
也可以直接在點選事件中發起請求,這裡使用到了 jQuery。上面程式碼是對這個封裝。
(function(){ $("#updateOneWebview").on("click",function(){ // alert("hello"); var url = "zidea://packagename?param={param1:one,param2:tow}&callback=cb"; var $iframe = $('<iframe style="display: none;" src="' + url + '"/>') $('body').append($iframe); setTimeout(function(){ $iframe.remove(); },1000); }); $("#gotoThreePage").on("click",function(){ // alert("hello"); var url = "zidea://forward?param={topage:three,SpParamType:H5,SpParamAnimation:push,hasnavgation:true}&callback=forwardcallback"; var $iframe = $('<iframe style="display: none;" src="' + url + '"/>') $('body').append($iframe); setTimeout(function(){ $iframe.remove(); },1000); }) })()