得益于近幾年移動端的發展,前端早已今非昔比,從大型架構來說angularJS、react、VueJS都有其應用場景,從工程化來說各種配套建構工具也紛紛出世,而從前端複雜度來說,最近幾年的前端代碼難度着實提升不少,從子產品化的必須,到MVC的必要、再到元件化程式設計,一種分而治之的思想逐漸侵入前端領域,而這種種迹象均表明一個問題,前端代碼現在不好寫了!!!
抛開近幾年前端互動加重而導緻的難度,我們今天主要探讨下前端跨平台一塊的痛點,也就是Hybrid多容器解決方案。
Hybrid是一種混合開發模式,最簡單的了解就是,Native會提供一個webview容器(确實不明白可以了解為iframe),然後在裡面加載你的H5站點。
在大約三年前,當時Hybrid平台還比較少,如果一個公司前端團隊比較強的話可以做到一套代碼三端運作就很不錯了,也就是一個H5頁面同時運作在:
① 浏覽器
② 公司IOS APP Webview容器
③ APP Andriod Webview容器
再這裡有個和簡單iframe不同的是,處于Native中的話,那麼很多H5的表現便不太一樣了,比如header一部分的UI是Native的,比如擷取定位資訊直接由Native給H5,在這裡面會有些差異化處理,一般來說隻有保持應用層API一緻,底層稍作修改即可;但也有一些特殊場景需要判斷,比如,一個按鈕的回調在H5站點的處理和處于Native中不一樣,這個時候可能就需要if else判斷處理了。
總的來說,雙容器時代持續了一陣子,而因為條件仍然比較單一,無非隻是判斷H5站點或者自身APP容器,是以問題也就不大。
多容器
量變到一定階段便不再一樣了,簡單從攜程來說,Hybrid的頻道從最初的一個發展到現在APP中80%都是Hybrid頻道,攜程APP本身有一套完整的Hybrid互動規範,俨然已經不再簡單是個APP了,而是一個Hybrid平台,開發規範一旦制定,一旦進入工廠化開發就很難更改了,除了攜程各個業務團隊依賴這個APP外,還有很多攜程子公司乃至第三方公司依賴這個APP,那麼這個時候底層若是不穩定,那麼導緻的問題将是連鎖的、不可控的。
這種平台化的APP産品遠不止攜程一家,已知的就有:
① 微信APP平台
② 淘寶APP平台
③ 手機百度APP平台
④ 糯米平台
⑤ 手機QQ平台
......
國内這些“平台”都有各自問題,不論是微信一些版本不支援flex、手機百度IOS、Andriod Webview容器各種不一緻,還是糯米Native預設後退不處理導緻假死,都可以看出為了搶占市場,各個團隊走的太急,考慮的應用場景過少,推出産品後後宣傳網站寫的漂亮,API看似豐富,但是光鮮的隻是表面,真正形成平台後,各個業務方接入會形成各種小機率場景,而Native發版是無力的,Native不動就隻能業務開發代碼适配,這個時候受苦的總是各個接入方,而導緻罵聲一片。
各個平台不穩定、考慮場景太少其實也無可厚非,畢竟Hybrid才火不到幾年,各個公司真正的經驗場景又很難被其它公司吸收,是以這種現象還得持續一段時間......
當然,APP底層的問題不是我們今天思考的重點,我們還是回到前端應用層。
多容器與前端
上述平台産品雖然有各自的問題,但是其流量優勢是無可比拟的!是以很多業務方、第三方公司都會接入,對于前端來說難度便增加了不少,以百度為例:
最初是前端代碼運作在浏覽器即可,而現在一套前端代碼卻需要運作在:
② 自身APP
③ 百度地圖APP
④ 手機百度APP
⑤ 糯米APP
而各個APP平台的Hybrid互動又完全不一緻,更有甚者後期還需要微信APP、手機QQ等Hybrid平台,那麼就簡單一個按鈕的互動都會令人頭疼的!因為我們的代碼中可能會出現這種東東:
複制代碼
1 if (shoujibaidu) {
2 //手機百度邏輯
3
4 } else if (baiduditu) {
5 //百度地圖邏輯
6
7 } else if (nuomi) {
8 //糯米邏輯
9 }
10 //......其它平台邏輯
這種代碼十分令人頭疼,是以我們一般會封裝一個方法在底層,哪個平台有差異就做特殊處理:
1 hybridCallback({
2 //預設回調
3 callback: function() {
4 },
5 //手機百度回調
6 shoubaicallback: function () {
7 },
8 //......
9 });
這個方法就是用于處理Hybrid差異而生,隻有處于某一個環境,才會執行其中的回調,這其實隻是一個文法糖,将判斷的邏輯封裝了,是以這個方案依舊很爛,如果哪天你要多一個容器或者少一個容器,整個站點的代碼要如何處理呢?如果代碼量超過萬行,這個代碼可不好處理!
更好的解決方案是抽離共性,是繼承,一般來說,Hybrid還是有一個很大的特點:主要邏輯與H5一緻,一些差異往往是顯示什麼,不顯示什麼(比如糯米中不顯示H5推薦下載下傳APP的廣告),更多的是一些點選回調的響應,于是我們找到了更好的方案:
多容器解決方案
容器判斷
解決多容器的第一步是容器判斷,一般來說,不同的Webview容器會有不同的userAgent:
//微信中UA為:
Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Mobile/11D257 MicroMessenger/6.1.5 NetType/WIFI
//浏覽器中為:
Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53
//糯米
Mozilla/5.0 (iPhone; CPU iPhone OS 9_2_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Mobile/13D15 BDNuomiAppIOS
手機百度也會包含關鍵字:bdbox_x.x(x.x一般是版本号),根據ua我們可以知道目前處于什麼環境(ios還是Andriod)與什麼平台。
前端實作
如果是頁面片的開發模式,一個頁面往往會有一個js檔案,做的好的團隊這個js檔案會是一個類,通過requireJS可以輕易拿到該檔案,我們這裡不做無用功,直接在之前代碼的基礎上做,有疑問的朋友請移步該文章:
【元件化開發】前端進階篇之如何編寫可維護可更新的代碼
在上文中,我們将一個個頁面以元件化的方式打散了,我們這裡新增一個index頁面,并且新增一個按鈕,點選按鈕彈出一個提示:
View Code
1 propertys: function ($super) {
2 $super();
3 this.template = layoutHtml;
4 this.events = {
5 'click .js_clickme': 'clickAction'
6 };
7 },
8
9 clickAction: function () {
10 this.showMessage('顯示消息');
11 },
首先我們看看這個回調,假如我們需要做到在糯米容器中使用Native的彈出提示的話,代碼便有所不同了:
http://dev.nuomi.com/#/guide/doc/api_doc/.%252Fcomdoc%252Fcomp_api%252Fcomp%252Fapi_doc%252Fbnjs_ui_doc.md
我們使用的應該是:
1 // 僅顯示'ok'按鈕
2 BNJS.ui.dialog.show({
3 title: '測試Dialog',
4 message: '我是測試Dialog~~~~',
5 ok: 'ok',
6 onConfirm: function() {
7 BNJS.ui.toast.show('您剛剛點選了ok按鈕');
8 }
9 });
于是我們在index目錄中新增了一個nuomi.index.js的檔案,繼承自index.js,并且在入口檔案main_webviews(原main.js檔案)中做更改:
1 define([
2 'IndexPath/index'
3 ], function (
4 IndexView
5 ) {
6 return _.inherit(IndexView, {
7
8 clickAction: function () {
9 BNJS.ui.dialog.show({
10 title: '測試Dialog',
11 message: '我是測試Dialog~~~~',
12 ok: 'ok',
13 onConfirm: function () {
14 BNJS.ui.toast.show('您剛剛點選了ok按鈕');
15 }
16 });
17 }
18
19 });
20 });
如此,在一般浏覽器中點選按鈕便是H5的UI元件,在糯米中便是使用的糯米元件了,如果哪天不需要糯米這個平台将nuomi.js删除即可:
可以看到,按鈕的點選已經不一樣了,當然還有很多不足,比如糯米中header部分便沒有做處理。
header元件
header這種元件與上述問題又不一緻,這種不一緻主要展現在兩個方面:
① 由于底層實作問題,做不到一緻
比如手機百度就不支援傳回按鈕定制,就連最簡單的title改變都是直接監聽的document.title的變化,并且Andriod還有BUG,像這種底層實作直接就抹殺的基本沒法,一般來說就是把原來的header換個方式顯示在頁面中,可以是弧形按鈕,可以是其它方式。
② header是系統級别的操作,不應該由使用者控制
如同該文中對header元件的處理:淺談Hybrid技術的設計與實作,像header這一類元件,這類元件必須滿足在H5站點與Hybrid中API使用一緻,而底層實作各異,與之前不同的是,這裡的header元件要考慮的可不止2個平台那種問題了,他可能是這樣的:
ui.eader //H5站點使用
nuomi.ui.header //糯米使用
xx.ui.header //......
我們這裡将場景變小,暫時隻考慮糯米與H5的實作,于是會在底層多出一個header的實作:
我這裡工作做的多一些,考慮了微信時候的場景,但是這裡業務代碼暫時隻考慮糯米,對應糯米的文檔:
代碼實作很簡單,隻要保持與H5使用API一緻即可,這個時候再簡單改下入口檔案,便能适配了。
PS:注意,這裡的适配隻是簡單實作,考慮多場景的話不能這樣寫代碼!!!
于是我們在糯米中便能很好的運作了
結語
代碼位址
https://github.com/yexiaochai/mvc
demo位址
http://yexiaochai.github.io/mvc/webapp/bus/index.html
測試糯米時請掃描第二個二維碼:
這裡抛出了前端多Webview容器會遇到的一些問題,并提出了一個解決思路,後續可能會有更加完整解決方案與demo出來,希望對各位有用,若是有已經涉及到這塊業務的朋友可以私下交流下。
本文轉自葉小钗部落格園部落格,原文連結:http://www.cnblogs.com/yexiaochai/p/5204847.html,如需轉載請自行聯系原作者