現(xiàn)在,混合開發(fā)是APP的主流開發(fā)模式——NATIVE+H5。金科支持的各site也是采取同樣的做法。混合開發(fā)的優(yōu)點很多,百度一下就知道,不是本文的重點。這里簡單介紹下hyperion的工作原理,重點分析億賬通運營服務(wù)小組現(xiàn)在使用的方案——H5框架里面耳熟能詳?shù)膬蓚€hyperion JS文件走讀下代碼。
大綱:
一 背景介紹
二 hyperion.adapert.js
? ?2.1 如何交互
? ?2.2 代碼走讀
? ?2.3 目前遇到情況,Android/iOS ?對接目前的問題
三 hyperion.js 新增配置
一 背景介紹
? ? 由于APP和H5各自的優(yōu)勢劣勢,混合開發(fā)能彌補APP打包、審核、發(fā)布耗時長,也解決了H5不能調(diào)用系統(tǒng)接口的局限。兩者的結(jié)合既保留APP的性能優(yōu)勢,也充分發(fā)揮H5的跨平臺性,這種方式也被很多業(yè)內(nèi)知名的互聯(lián)網(wǎng)公司采用,如淘寶、京東、微信公眾號,包括平安集團的大多數(shù)APP也采用混合開發(fā)的模式。
? ? 有了混合App(Hybrid App)的誕生,那么NATIVE和H5是如何進行交互的,需要我們做哪些事情,是想要在這篇文章說明的重點。
二 hyperion.adapert.js
? ? ?2.1 交互原理
混合APP需要開啟webview的功能,并且在webview加載H5頁面的時候需要注入js腳本。通過類似iframe、prompt、alert、confirm等方法和webview交互,webview能監(jiān)聽到j(luò)s的事件拿到所傳輸?shù)臄?shù)據(jù),在進行處理后返回接觸的結(jié)果數(shù)據(jù)告訴H5執(zhí)行的回調(diào)。總結(jié)起來就是下圖示意:

2.2 hyperion.adapert.js
? ? 這個文件是定義H5和NATIVE交互的方法。文件可以分成兩個部分,下面的一段(function(global){})(this)自執(zhí)行函數(shù),和上面的定義全局變量HFEasyJS。(本人不太明白IOS和JAVA開發(fā),僅從H5的角度來分析代碼的邏輯,說的不全的地方請大家留言指正。)
? ? (function(global){})(this)里面干了兩件事情。一是定義了Hyperion的方法,其中一個屬性Hyperion.call傳參給native,另一個Hyperion._callback處理JS回調(diào)。JS自身并不清楚回調(diào)要什么時候來觸發(fā),所以其實這里的Hyperion._callback的觸發(fā)是native端來調(diào)起的。查閱Android端的回調(diào)代碼:
jsContent = "javascript:Hyperion._callback('" + callBackFunName + "'," + callBackCode + ","+ callBackParam + ")";
... ?
?loadUrl(jsContent);
...
找到傳過去的callBackFunName,調(diào)起已注入JS的代碼,并在webview里面執(zhí)行。
? ? H5的框架我們默認一定要引入hyprion.adapte.js和hyperion.js兩個腳本文件,但是在調(diào)試Android端的時候發(fā)現(xiàn),hyprion.adapte.js其實是有注入進webview的,就是我們實際上調(diào)起的Hyperion方法是覆蓋了腳本文件用的Android端的腳本:
public static String getCommonInjectedJS(){
return "javascript:(function(Global){var Hyperion=Global.Hyperion||{};var slice=Array.prototype.slice,ua=Global.navigator?Global.navigator.userAgent:\"\",isiOS=/iPhone|iPad|iPod|iOS/i.test(ua),isAndroid=/Android/i.test(ua),callbackId=0;var noop=function(){}; ...略
}
確實看起來和我們hyprion.adapte.js很像,但是還少了一部分代碼,因為Android端到這里已經(jīng)結(jié)束了。在Hyprion.call里面有別與Android和IOS的部分:
if (isAndroid) {
prompt(callData);
} else if (isiOS) {
try {
global.Hyperion_NATIVE.call(callData);
} catch (e) {}
}
對照圖2.1來理解,Android端用了prompt的方法和webview進行傳參,但是IOS用了另一種方式iframe,就是Hyperion.adapte.js的上面部分定義的HFEasyJS。(為什么不能用一個方法來傳值了,還區(qū)分平臺,這個已經(jīng)無從考證,是歷史代碼原因還是平臺版本的兼容性問題有了解更多的大神歡迎指導(dǎo)留言)
window.HFEasyJS = {
__callbacks: {},
invokeCallback: function(cbID, removeAfterExecute) {
...
},
call: function(obj, functionName, args) {
...
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", "easy-js:" + obj + ":" + encodeURIComponent(functionName) + argStr);
},
inject: function(obj, methods) {
for (var i = 0, l = methods.length; i < l; i++) {
jsObj[jsMethod] = function() {
return HFEasyJS.call(obj, method, Array.prototype.slice.call(arguments));
?}}};
IOS用iframe進行傳值,在document內(nèi)append(iframe)的時候會把參數(shù)拼接成字符串通過src進行傳值例: ?src:'easy-js:Hyperion_NATIVE:call:',NATIVE在接收到定義的協(xié)議后并不去請網(wǎng)絡(luò)資源,而是解析傳入的方法。
2.3 目前遇到情況,Android/iOS? 對接目前的問題
? ? 定義接口的文件綜上所述。發(fā)現(xiàn)Android和IOS都有注入hyperion.adapter.js,而且H5在框架層也引入了此文件。注入的原因可能是為了解決加載H5資源過多,但是也會存在注入時機的問題,如果頁面初始化的需要調(diào)用例如Hyperion.actions.onEvent()的方法,注入腳本是在靜態(tài)資源加載完成時,那么就會導(dǎo)致找不到方法報錯。可能NATIVE有多次注入,其實為了防止報錯的問題,H5的框架保險起見再次引入了hyperion.adapter.js。那初衷為了減少請求開支的目的也沒用達到,而且如果協(xié)議文件改了Android和IOS都要改腳本并且打包,(用了這么久應(yīng)該也不會改了吧,實際上卻是碰到了問題,需要改動native端的腳本)所以的site也要更新代碼,搞得挺麻煩,H5來維護更方便。
三 hyperion.js 新增配置
相對來說hyperion.js更容易理解,其實就是封裝的各個方法,其中Hyperion 文檔有介紹如何寫的比較詳細,這里就不贅述。