【Hybird】274-Hybird App 應用開發中 5 個必備知識點複習

前言

咱們大前端團隊內部 📖每週一練 的知識複習計劃還在繼續,本週主題是 《Hybird APP 混合應用專題》 ,這期內容比較多,篇幅也相對較長,每一個知識點內容也比較多。javascript

以前分享的每週內容,我都整理到掘金收藏集 [📔《EFT每週一練》] (https://juejin.im/collection/5cd11b0af265da0346227e24) 上啦,歡迎點贊收藏咯💕💕。html

注:本文整理資料來源網絡,有些圖片/段落找不到原文出處,若有侵權,聯繫刪除。前端

1、什麼是 Hybird App,與 Native App 及 Web App 有什麼區別

參考文章:java


  1. [《Web App Hybrid App和 Native App的區別》] (http://www.ionic.wang/article-index-id-58.html)android



  2. [《Hybrid APP基礎篇(二) -> Native、Hybrid、React Native、Web App方案的分析比較》] (https://www.cnblogs.com/dailc/p/5930238.html)web


1.1 主流應用類型

隨着如今移動互聯網的快速發展,市面上目前主流移動應用程序主要分三類:Web AppNative AppHybrid Appjson

三者大體關係以下:api

1.2 Web App

Web App,即移動端網站,通常指的是基於 Web 的應用,基於瀏覽器運行無需下載安裝,基本上能夠說是觸屏版的網頁應用。這類應用基本上是一個網頁或一系列網頁,旨在在移動屏幕上工做。瀏覽器

Web 網站通常分爲兩種:緩存


  1. MPA(Multi-page Application)



  2. SPA(Single-page Application)


通常的 Web App 是指 SPA 形式開發的網站。

優勢:

  • 開發和維護成本低,能夠跨平臺,調試方便;

前端人員開發的代碼,可應用於各大主流瀏覽器(特殊狀況能夠代碼進行下兼容),沒有新的學習成本,並且能夠直接在瀏覽器中調試。

  • 更新最爲快速;

因爲web app資源是直接部署在服務器端的,因此只需替換服務器端文件,用戶訪問是就已經更新了(固然須要解決一些緩存問題)。

  • 無需安裝App,不會佔用手機內存;

經過瀏覽器便可訪問,無需安裝,用戶使用成本更低。

缺點:

  • 性能低,用戶體驗差;

因爲是直接經過的瀏覽器訪問,因此沒法使用原生的API,操做體驗很差。

  • 依賴於網絡,頁面訪問速度慢,耗費流量;

Web App每次訪問都必須依賴網絡,從服務端加載資源,當網速慢時訪問速度很不理想,特別是在移動端,對網站性能優化要求比較高。

  • 功能受限,大量功能沒法實現;

只能使用 HTML5 的一些特殊 API ,沒法調用原生 API ,因此不少功能存在沒法實現狀況。

  • 臨時性入口,用戶留存率低;

這既是它的優勢,也是缺點,優勢是無需安裝,肯定是用完後有時候很難再找到,或者說很難專門爲某個web app留存一個入口,致使用戶很難再次使用。

1.3 Native App

Native APP 指的是原生程序,須要用戶下載安裝使用,通常依託於操做系統,有很強的交互,是一個完整的App,可拓展性強,能發佈應用商店。

目前市面上主流的平臺有:AndroidiOS

優勢:


  • 直接依託於操做系統,用戶體驗好操做流暢性能穩定



  • 用戶留存率高;



  • 功能最爲強大,特別是在與系統交互中,幾乎全部功能都能實現;


因爲 Native APP 是直接依託於系統,因此能夠直接調用官方提供的API,功能最爲全面(好比本地資源操做,通知,動畫等)。

缺點:

  • 開發和維護成本高,沒法跨平臺,須要各平臺各自獨立開發;

Android 上基於 Java 開發,iOS 上基 OCSwift 開發,相互之間獨立,必需要有各自的開發人員。

  • 門檻較高,原生人員有必定的入門門檻,人才較少;

原生的一個很大特色就是獨立,因此不太容易入門,並且 AndroidiOS都須要獨立學習。

  • 分發成本高,更新緩慢,特別是發佈應用商店後,須要等到審覈週期;

原生應用更新是一個很大的問題, Android中還能直接下載整包APK進行更新,可是 iOS中,若是是發佈 AppStore ,必須經過 AppStore地址更新,而每次更新都須要審覈,因此沒法達到及時更新。

1.4 Hybrid App

Hybrid App 指的是混合開發,也就是半原生半 Web 的開發模式,有跨平臺效果,固然了,實質最終發佈的仍然是獨立的原生APP(各類的平臺有各類的SDK)。

優勢:

  • 學習和開發成本較低,能夠跨平臺,調試方便

Hybrid 開發模式下,由原生提供統一的 API 給 JS 調用,實際的主要邏輯由 HTML 和 JS 完成,最終放在 webview 中顯示,這樣只須要寫一套代碼便可,達到跨平臺效果,另外也能夠直接在瀏覽器中調試,很方便。

通常 Hybrid 中的跨平臺最少能夠跨三個平臺: Android App ,iOS App ,普通 webkit 瀏覽器。

須要前端人員關注一些原生提供的API,具體的實現無需關心,沒有新的學習內容。

  • 維護成本低,功能可複用,而且更容易更新;

雖然沒有 web app 更新那麼快速,可是 Hybrid 中也能夠經過原生提供 api ,進行資源主動下載,達到只更新資源文件,不更新 apk(ipa) 的效果。

  • 功能更加完善,性能和體驗要比起 web app 好太多;

由於能夠調用原生api,因此不少功能只要原生提供出就能夠實現,另外性能也比較接近原生。

  • 部分性能要求的頁面可用原生實現;

這種模式是原生混合 web ,因此咱們徹底能夠將交互強,性能要求高的頁面用原生寫,而後一些其它頁面用 JS 寫,嵌入 webview 中,達到最佳體驗。

缺點:

  • 相比原生,性能仍然有較大損耗;

這種模式受限於 webview 的性能,相比原生而言有很多損耗,體驗沒法和原生相比。

  • 不適用於交互性較強的app;

這種模式的主要適用:一些新聞閱讀類,信息展現類的 app ,不適用於一些交互較強或者性能要求較高的 app (好比動畫較多就不適合)。

1.5 三者區別

三者使用場景對比:

三者技術特徵對比:

另外增長 ReactNative 一塊兒放入做對比。


1.6 三者如何選擇

這裏簡單介紹幾種狀況,具體仍是要以實際項目技術評估結果爲主。

  • 選擇純 Native App 模式的狀況:

性能要求極高,體驗要求極好,不追求開發效率

  • 選擇 Web App 模式的狀況:

不追求用戶體驗和性能,對離線訪問沒要求,正常來講,若是追求性能和體驗,都不會選用web app。

  • 選擇 Hybrid App 模式的狀況

大部分狀況下的App都推薦採用這種模式,這種模式能夠用原生來實現要求高的界面,對於一些比較通用型,展現型的頁面徹底能夠用web來實現,達到跨平臺效果,提高效率。通常好一點的Hybrid方案,都會把資源放在本地的,能夠減小網絡流量消耗

  • 選擇React Native App模式的狀況

追求性能,體驗,同時追求開發效率,並且有必定的技術資本,捨得前期投入。

React Native這種模式學習成本較高,因此須要前期投入很多時間才能達到較好水平,可是有了必定水準後,開發起來它的優點就體現出來了,性能不遜色原生,並且開發速度也很快

2、什麼是 Cordova,它的優缺點是什麼

參考文章:[《淺談Cordova框架》] (https://blog.csdn.net/weixin_37730482/article/details/73920722)

2.1 Cordova 簡介

Cordova 是一個用基於 HTML、CSS 和 JavaScript 的,用於建立跨平臺移動應用程序的快速開發平臺。它使開發者可以利用iPhone、Android、Palm、Symbian、WP七、Bada和Blackberry等智能手機的核心功能——包括地理定位、加速器、聯繫人、聲音和振動等,此外 Cordova 擁有豐富的插件,能夠調用。

也能夠用來開發原生和WebView組件之間的插件接口

來源:
Cordova 是 PhoneGap 貢獻給 Apache 後的開源項目,是從 PhoneGap 中抽出的核心代碼,是驅動 PhoneGap 的核心引擎。能夠把它們的關係想象成相似於 Webkit 和 Google Chrome 的關係。

2.2 Cordova 架構圖

架構圖介紹:

  • Web App

用於存放咱們程序的代碼,包括業務邏輯,還有一些運行須要的資源(如:CSS,JavaScript,圖片,媒體文件等)。應用的實現是經過 web 頁面,默認的本地文件名稱是 index.html ,應用執行在原生應用包裝的 WebView 中,這個原生應用是你分發到應用商店中的。

  • WebView

Cordova 用的 WebView 能夠給應用提供完整用戶訪問界面,使得應用混合了 Webview 和原生的應用組件。

  • Cordova Plugins

插件是 Cordova 生態系統的重要組成部分。它提供了 Cordova 和原生組件相互通訊的接口,並綁定到了標準的設備API上,這使你可以經過 JavaScript 調用原生代碼

2.3 優缺點

優勢:

  • 跨平臺,開發簡單,學習成本低;

  • 框架多,插件多,可自定義插件;

  • 發展最先,社區資源豐富;

缺點:

  • WebView性能低下時,用戶體驗差,反應慢;

  • 中文文檔資源少;

  • 調試不方便,既不像原生那麼好調試,也不像純web那種調試;

3、Cordova 插件的原理是什麼

Cordova 插件就是一些附加代碼用來提供原生組件的 JavaScript 接口,它容許你的 App 可使用原生設備的能力,超越了純粹的 Web App。

Cordova 在 iOS 上的實現原理:

3.1 工做流程

  1. Cordova 發起對原生的請求:

  
  
   
   
            
   
   
cordova.exec(successCallback, failCallback, service, action, actionArgs); // successCallback: 成功回調方法// failCallback: 失敗回調方法// server: 所要請求的服務名字// action: 所要請求的服務具體操做// actionArgs: 請求操做所帶的參數

  1. 這五個參數並非直接傳給原生,Cordova JS 端會作如下處理:


    • 爲每一個請求生成一個惟一標識( callbackId ),並傳給原生端,原生端處理完後,會把 callbackId 連同處理結果一塊兒返回給 JS 端;

    • 以 callbackId 爲 key, {success:successCallback,fail:failCallback} 爲 value,把這個鍵值對保存在 JS 端的字典裏, successCallback 與 failCallback 這兩個參數不須要傳給原生,原生返回結果時帶上 callbackId,JS 端就能夠根據 callbackId 找到回調方法;

    • 每次 JS 請求,最後發到原生的數據包括: callbackIdserviceactionactionArgs


  1. 原生代碼拿到 callbackIdserviceactionactionArgs 後,會作如下處理:


    • 根據 service 參數找到對應插件類;

    • 根據 action 參數找到插件類中對應的處理方法,並把 actionArgs 做爲處理方法請求參數的一部分傳給處理方法;

    • 處理完成後,把處理結果及 callbackId 返回給 JS 端,JS 端收到後會根據 callbackId 找到回調方法,並把處理結果傳給回調方法;

  1. JS 端根據 callbackId 回調 cordova.js

  
  
   
   
            
   
   

// 根據 callbackId 及是否成功標識,找到回調方法,並把處理結果傳給回調方法callbackFromNative: function(callbackId, success, status, args, keepCallback) { var callback = cordova.callbacks[callbackId]; if (callback) { if (success && status == cordova.callbackStatus.OK) { callback.success && callback.success.apply(null, args); } else if (!success) { callback.fail && callback.fail.apply(null, args); } // Clear callback if not expecting any more results if (!keepCallback) { delete cordova.callbacks[callbackId]; } }}

4、什麼是 JS Bridge,它的做用是什麼

參考文章:[《JSBridge的原理》] (https://juejin.im/post/5abca877f265da238155b6bc)

4.1 JS Bridge 介紹

JSBridge 簡單來說,主要是 給 JavaScript 提供調用 Native 功能的接口,讓混合開發中的前端部分能夠方便地使用地址位置、攝像頭甚至支付等 Native 功能。

JSBridge 就像其名稱中的 「Bridge」 的意義同樣,是 Native 和非 Native 之間的橋樑,它的核心是 構建 Native 和非 Native 間消息通訊的通道,並且是 雙向通訊的通道

JSBridge 另外一個叫法及你們熟知的 Hybrid app 技術。

所謂 雙向通訊的通道:

  • JS 向 Native 發送消息 :

調用相關功能、通知 Native 當前 JS 的相關狀態等。

  • Native 向 JS 發送消息 :

回溯調用結果、消息推送、通知 JS 當前 Native 的狀態等。

4.2. JS Bridge 實現原理

參考文章:[《Hybrid APP基礎篇(四)->JSBridge的原理》] (https://www.cnblogs.com/dailc/p/5931324.html)

Android 和 iOS 的 JSBridge 實現方式:

4.2.1 基本流程

  • H5 頁面經過某種方式觸發一個 url scheme

  • Native 捕獲到 url scheme,並進行分析和處理;

  • Native 調用 H5 的 JSBridge 對象傳遞迴調;

原生的 WebView/UIWebView 控件已經可以和 JS 實現數據通訊了,那爲何還要 JSBridge呢?

其實使用JSBridge有不少方面的考慮:

  • Android4.2如下, addJavascriptInterface 方式有安全漏掉。

  • iOS7如下,JS 沒法調用 Native。

  • url scheme 交互方式是一套現有的成熟方案,能夠完美兼容各類版本,對之前老版本技術的兼容。

4.2.1 實現流程(Android 爲例)

  1. 擬定協議,參考 http 制定的協議爲: jsbridge://className:port/methodName?jsonObj

  
  
   
   
            
   
   
className // Android端實現暴露給前端的類名port // Android返回結果給前端的端口methodName // 前端須要調用的函數jsonObj // 前端給Android傳遞的參數
  1. 新建 HTML 文件命名爲 index.html, 編寫一個 button 綁定 click 事件;

  
  
   
   
            
   
   
<button onclick="JSBridge.call( 'bridge', 'showToast', {'msg':'Hello JSBridge'}, function(res){ alert(JSON.stringify(res)) })"> 測試showToast</button>
  1. 新建 JS 文件命名爲 JSBridge.js, 第2步中的 JSBridge.call 即爲調用 JSBridge.js中的 call 方法,後面帶了四個參數;

  
  
   
   
            
   
   
call: function (obj, method, params, callback) { console.log(obj+" "+method+" "+params+" "+callback); var port = Util.getPort(); console.log(port); this.callbacks[port] = callback; var uri=Util.getUri(obj,method,params,port); console.log(uri); window.prompt(uri, "");},

JSBridge.js 中的 call 方法,最後調用了 window.prompt 方法,這個方法就是觸發 Android 端 webChromeClient的回調函數用的。

  1. window.prompt 觸發了 WebChromeClient(這個須要使用函數 WebView.setWebChromeClient(newWebChromeClietn() )進行設定);

類中的以下回調 onJsPrompt。這時就完成了前端與 Android端 的通訊了,由於前端的信息都順利經過這個函數傳遞給Android了。

  
  
   
   
            
   
   
@Overridepublic boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { result.confirm(JSBridge.callJava(view,message)); return true;}
  1. Android 中會定義一個類 JSBridge.java 來管理暴露給前端使用的函數;

這個類有兩個功能:

  • 暴露給前端的函數的動態註冊功能。

  • 解析前端信息,調用了 Android 端對應的函數,這個示例中是: showToast 函數。

解析前端的信息,獲取前端調用的函數名:

  
  
   
   
            
   
   
Uri uri = Uri.parse(uriString);className = uri.getHost();param = uri.getQuery();port = uri.getPort() + "";String path = uri.getPath();HashMap< String, Method> methodHashMap = exposedMethod.get(className);Method method = methodHashMap.get(methodName);

經過獲取的函數名,這裏是 showToast,調用 Android 端的 showToast函數。

  
  
   
   
            
   
   
method.invoke(null,webView,new JSONObject(param),new Callback(webView,port));
  1. 定義類 BridgeImpl.java 來具體的實現暴露給前端的全部函數。這裏的 showToast函數以下:

  
  
   
   
            
   
   
public static void showToast(WebView webView, JSONObject param, final JSBridge.Callback callback){ String message = param.optString("msg"); Toast.makeText(webView.getContext(),message,Toast.LENGTH_LONG).show(); if(null != callback){ try { JSONObject object = new JSONObject(); object.put("key","value"); object.put("key1","vaule1"); callback.apply(getJSONObject(0,"ok",object)); }catch (Exception e){ e.printStackTrace(); } }}

5、請列舉 Android 與 iOS 平臺下 JS Bridge 的實現方式

這邊代碼比較多,我使用圖片來展現,你們能夠放大來查看。

5.1 Android 實現方式

5.1.1 Android 調用 JS 的 2 種方式
  1. 經過 WebView  loadUrl():

JS 代碼調用必定要在 onPageFinished() 回調以後才能調用,不然不會調用。

Web 端代碼:

  
  
   
   
            
   
   
<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>前端代碼</title> <script> // Android須要調用的方法 function callJS(){ alert("Android調用了JS的callJS方法"); } </script> </head></html>

Android 端代碼:

  1. 經過 WebView  evaluateJavascript()

  
  
   
   
            
   
   
// 只須要將第一種方法的loadUrl()換成下面該方法便可mWebView.evaluateJavascript( "javascript:callJS()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { //此處爲 js 返回的結果 } });}
5.1.2 JS 調用 Android 的 3 種方式
  1. 經過 WebView 的 addJavascriptInterface() 進行對象映射:

Android 映射:

  
  
   
   
            
   
   
// 繼承自Object類public class AndroidtoJs extends Object { // 定義JS須要調用的方法 // 被JS調用的方法必須加入@JavascriptInterface註解 @JavascriptInterface public void hello(String msg) { System.out.println("JS調用了Android的hello方法"); }}

Web:

  
  
   
   
            
   
   
<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>前端代碼</title> <script> function callAndroid(){ // 因爲對象映射,因此調用test對象等於調用Android映射的對象 test.hello("js調用了android中的hello方法"); } </script> </head> <body> //點擊按鈕則調用callAndroid函數 <button type="button" id="button1" "callAndroid()"></button> </body></html>

Android 端:

  1. 經過 WebViewClient 的 shouldOverrideUrlLoading() 方法回調攔截 url

Web 端:

  
  
   
   
            
   
   
<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>前端代碼</title> <script> function callAndroid(){ /*約定的url協議爲:js://webview?arg1=111&arg2=222*/ document.location = "js://webview?arg1=111&arg2=222"; } </script> </head> <!-- 點擊按鈕則調用callAndroid()方法 --> <body> <button type="button" id="button1" onclick="callAndroid()" >點擊調用Android代碼</button> </body></html>

Android 端:

  1. 經過 WebChromeClient 的方法回調攔截JS對話框方法:

經過 WebChromeClient 的 onJsAlert()onJsConfirm()onJsPrompt()方法回調攔截JS對話框 alert()confirm()prompt() 消息。

Web 端:

  
  
   
   
            
   
   
<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>前端代碼</title> <script> function clickprompt(){ // 調用prompt() var result=prompt("js://demo?arg1=111&arg2=222"); alert("demo " + result); } </script> </head> <!-- 點擊按鈕則調用clickprompt() --> <body> <button type="button" id="button1" onclick="clickprompt()" >點擊調用Android代碼</button> </body></html>

Android 端:

5.2 iOS 實現方式

5.2.1 JS 調用 iOS 的 2 種方式
  1. 使用 XMLHttpRequest 發起請求的方式:

Web 端:

XMLHttpRequest bridge:

JS 端使用 XMLHttpRequest 發起了一個請求:execXhr.open('HEAD',"/!gap_exec?"+(+newDate()),true);,請求的地址是 /!gap_exec;並把請求的數據放在了請求的 header 裏面,見這句代碼:execXhr.setRequestHeader('cmds',iOSExec.nativeFetchMessages());

而在 Objective-C 端使用一個 NSURLProtocol 的子類來檢查每一個請求,若是地址是 /!gap_exec 的話,則認爲是 Cordova 通訊的請求,直接攔截,攔截後就能夠經過分析請求的數據,分發到不一樣的插件類(CDVPlugin 類的子類)的方法中:

Cordova 中優先使用這種方式, Cordova.js 中的註釋有說起爲何優先使用 XMLHttpRequest 的方式,及爲何保留第二種 iframe bridge 的通訊方式:

  
  
   
   
            
   
   
// XHR mode does not work on iOS 4.2, so default to IFRAME_NAV for such devices.// XHR mode’s main advantage is working around a bug in -webkit-scroll, which// doesn’t exist in 4.X devices anyways123

iframe bridge:

在 JS 端建立一個透明的 iframe,設置這個 ifamesrc 爲自定義的協議,而 ifamesrc更改時, UIWebView 會先回調其 delegatewebView:shouldStartLoadWithRequest:navigationType: 方法,關鍵代碼以下:

  1. 經過設置透明的 iframe 的 src 屬性:

5.2.2 iOS 調用 JS 的方式

UIWebView 有一個這樣的方法 stringByEvaluatingJavaScriptFromString:,這個方法可讓一個 UIWebView 對象執行一段 JS 代碼,這樣就能夠達到 Objective-C 跟 JS 通訊的效果,在 Cordova 的代碼中多處用到了這個方法,其中最重要的兩處以下:

  1. 獲取 JS 的請求數據:

  1. 把 JS 請求的結果返回給 JS 端:

結語

對於初入混合應用開發的小夥伴,這些會有點難度,可是好好理解下那幾張流程圖,再理一理思路,相信會有幫助😁

給你們加加油~~

關於我

本文首發在 [pingan8787我的博客] (http://www.pingan8787.com),如需轉載請保留我的介紹

微信公衆號

本文分享自微信公衆號 - 前端自習課(FE-study)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索