現(xiàn)在锅睛,混合開發(fā)是APP的主流開發(fā)模式——NATIVE+H5。金科支持的各site也是采取同樣的做法义辕∠罕辏混合開發(fā)的優(yōu)點(diǎn)很多,百度一下就知道灌砖,不是本文的重點(diǎn)璧函。這里簡(jiǎn)單介紹下hyperion的工作原理,重點(diǎn)分析億賬通運(yùn)營(yíng)服務(wù)小組現(xiàn)在使用的方案——H5框架里面耳熟能詳?shù)膬蓚€(gè)hyperion JS文件走讀下代碼基显。
大綱:
一 背景介紹
二 hyperion.adapert.js
? ?2.1 如何交互
? ?2.2 代碼走讀
? ?2.3 目前遇到情況蘸吓,Android/iOS ?對(duì)接目前的問題
三 hyperion.js 新增配置
一 背景介紹
? ? 由于APP和H5各自的優(yōu)勢(shì)劣勢(shì),混合開發(fā)能彌補(bǔ)APP打包撩幽、審核库继、發(fā)布耗時(shí)長(zhǎng),也解決了H5不能調(diào)用系統(tǒng)接口的局限窜醉。兩者的結(jié)合既保留APP的性能優(yōu)勢(shì)宪萄,也充分發(fā)揮H5的跨平臺(tái)性,這種方式也被很多業(yè)內(nèi)知名的互聯(lián)網(wǎng)公司采用榨惰,如淘寶拜英、京東、微信公眾號(hào)琅催,包括平安集團(tuán)的大多數(shù)APP也采用混合開發(fā)的模式居凶。
? ? 有了混合App(Hybrid App)的誕生,那么NATIVE和H5是如何進(jìn)行交互的藤抡,需要我們做哪些事情侠碧,是想要在這篇文章說明的重點(diǎn)。
二 hyperion.adapert.js
? ? ?2.1 交互原理
混合APP需要開啟webview的功能缠黍,并且在webview加載H5頁面的時(shí)候需要注入js腳本弄兜。通過類似iframe、prompt、alert挨队、confirm等方法和webview交互,webview能監(jiān)聽到j(luò)s的事件拿到所傳輸?shù)臄?shù)據(jù)蒿往,在進(jìn)行處理后返回接觸的結(jié)果數(shù)據(jù)告訴H5執(zhí)行的回調(diào)盛垦。總結(jié)起來就是下圖示意:
2.2 hyperion.adapert.js
? ? 這個(gè)文件是定義H5和NATIVE交互的方法瓤漏。文件可以分成兩個(gè)部分腾夯,下面的一段(function(global){})(this)自執(zhí)行函數(shù),和上面的定義全局變量HFEasyJS蔬充。(本人不太明白IOS和JAVA開發(fā)蝶俱,僅從H5的角度來分析代碼的邏輯,說的不全的地方請(qǐng)大家留言指正饥漫。)
? ? (function(global){})(this)里面干了兩件事情榨呆。一是定義了Hyperion的方法,其中一個(gè)屬性Hyperion.call傳參給native庸队,另一個(gè)Hyperion._callback處理JS回調(diào)积蜻。JS自身并不清楚回調(diào)要什么時(shí)候來觸發(fā),所以其實(shí)這里的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的框架我們默認(rèn)一定要引入hyprion.adapte.js和hyperion.js兩個(gè)腳本文件丙笋,但是在調(diào)試Android端的時(shí)候發(fā)現(xiàn),hyprion.adapte.js其實(shí)是有注入進(jìn)webview的煌贴,就是我們實(shí)際上調(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(){}; ...略
}
確實(shí)看起來和我們hyprion.adapte.js很像御板,但是還少了一部分代碼,因?yàn)锳ndroid端到這里已經(jīng)結(jié)束了崔步。在Hyprion.call里面有別與Android和IOS的部分:
if (isAndroid) {
prompt(callData);
} else if (isiOS) {
try {
global.Hyperion_NATIVE.call(callData);
} catch (e) {}
}
對(duì)照?qǐng)D2.1來理解稳吮,Android端用了prompt的方法和webview進(jìn)行傳參,但是IOS用了另一種方式iframe井濒,就是Hyperion.adapte.js的上面部分定義的HFEasyJS灶似。(為什么不能用一個(gè)方法來傳值了,還區(qū)分平臺(tái)瑞你,這個(gè)已經(jīng)無從考證酪惭,是歷史代碼原因還是平臺(tái)版本的兼容性問題有了解更多的大神歡迎指導(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進(jìn)行傳值,在document內(nèi)append(iframe)的時(shí)候會(huì)把參數(shù)拼接成字符串通過src進(jìn)行傳值例: ?src:'easy-js:Hyperion_NATIVE:call:'者甲,NATIVE在接收到定義的協(xié)議后并不去請(qǐng)網(wǎng)絡(luò)資源春感,而是解析傳入的方法。
2.3 目前遇到情況,Android/iOS? 對(duì)接目前的問題
? ? 定義接口的文件綜上所述鲫懒。發(fā)現(xiàn)Android和IOS都有注入hyperion.adapter.js嫩实,而且H5在框架層也引入了此文件。注入的原因可能是為了解決加載H5資源過多窥岩,但是也會(huì)存在注入時(shí)機(jī)的問題甲献,如果頁面初始化的需要調(diào)用例如Hyperion.actions.onEvent()的方法,注入腳本是在靜態(tài)資源加載完成時(shí)颂翼,那么就會(huì)導(dǎo)致找不到方法報(bào)錯(cuò)晃洒。可能NATIVE有多次注入朦乏,其實(shí)為了防止報(bào)錯(cuò)的問題球及,H5的框架保險(xiǎn)起見再次引入了hyperion.adapter.js。那初衷為了減少請(qǐng)求開支的目的也沒用達(dá)到呻疹,而且如果協(xié)議文件改了Android和IOS都要改腳本并且打包吃引,(用了這么久應(yīng)該也不會(huì)改了吧,實(shí)際上卻是碰到了問題刽锤,需要改動(dòng)native端的腳本)所以的site也要更新代碼际歼,搞得挺麻煩,H5來維護(hù)更方便姑蓝。
三 hyperion.js 新增配置
相對(duì)來說hyperion.js更容易理解鹅心,其實(shí)就是封裝的各個(gè)方法,其中Hyperion 文檔有介紹如何寫的比較詳細(xì)纺荧,這里就不贅述旭愧。