Hybrid App的架構與實現(xiàn)

公司想要將自己的產(chǎn)品由網(wǎng)頁端移植到原生,提升用戶體驗,因此在網(wǎng)上查找相關資料。最后App決定使用Hybrid架構來實現(xiàn)快速上線。
第一次寫文章,比較粗糙,諸位看官如果想更細致的了解HybridApp,請移步最下參考資料。
文章部分引用了相關資料的語句,在此感謝相關資料的作者。


伴隨著移動互聯(lián)網(wǎng)產(chǎn)業(yè)的興起,各式App層出不窮,我們迫切需求一種更快速、成本更低、技術更為成熟的項目開發(fā)方案,而H5的成熟讓我們看到了希望,使得Web App開始崛起。
為了提高用戶體驗,目前網(wǎng)站一般分為3個版本,簡版、移動版、電腦版,簡板Web普遍是基于WAP2.0開發(fā)的,界面視覺效果差、功能簡單;移動版則普遍使用H5開發(fā),適用于現(xiàn)在大家普遍使用的移動上網(wǎng)設備,擁有更好的視覺效果、交互方式,迥然不同于簡板Web的設計風格;而電腦版在此則不做討論。
個人認為現(xiàn)在的Web App就是由移動版網(wǎng)頁發(fā)展而來。


目前App大致分為三個大類

  • Web App

    定義:將所有功能都放在Web上展現(xiàn),運行基于本地瀏覽器。在此將給Web簡單的套一層App外殼的應用也歸入Web App。完全采用HTML/CSS/JS編寫,專為觸摸操作進行了優(yōu)化。目前iOS已禁止簡單的套殼App上架。
    優(yōu)點:開發(fā)速度快,跨平臺,成本低,實時迭代用戶無需更新
    缺點:網(wǎng)絡速度要求高、服務器壓力大,系統(tǒng)級別API調(diào)用難度大,用戶體驗差、用戶留存度低

  • Native App

    定義::NativeApp是基于手機本地操作系統(tǒng)并使用原生語言編寫的 。因為位于平臺層上方,向下訪問和兼容的能力會比較好一些,可以 支持在線或離線訪問,消息推送或本地資源訪問,攝像撥號功能的調(diào) 取。但是由于設備碎片化,App的開發(fā)成本要高很多,維持多個版本 的更新升級比較麻煩,用戶的安裝門檻也比較高。

    優(yōu)點:用戶體驗佳、交互風格與系統(tǒng)吻合,節(jié)省流量,可訪問本地資源,速度快,用戶留存度高
    缺點:成本高,版本迭代慢,需要過審

  • Hybrid App

    定義:介于Web App與Native App的一種折中方案,底層(框架)部分由iOS/Android開發(fā)人員處理,上層(內(nèi)容展現(xiàn))部分由Web前端人員處理,用戶界面操作邏輯及部分靜態(tài)資源駐留本地,使得Web App可以對操作迅速反應并在很大程度上實現(xiàn)離線訪問。Hybrid App追求趨近于原生App的體驗,但目前還較困難。

三者之間的比較
三者之間的比較

需要考慮的方面

  • 分清Native與前端的界限,Native提供宿主環(huán)境,前端需要合理的利用Native提供的資源,提升用戶體驗及自身性能。在設計上需要考慮以下問題:
  • 交互設計:如何設計與前端的交互?Native需要考慮提供NativeUI/Header/消息/Alert等組件接口、通訊錄/系統(tǒng)/設備信息讀取接口、Native/H5相互跳轉(zhuǎn)(H5跳Native、H5新開WebView跳轉(zhuǎn)、Native跳轉(zhuǎn)H5)等問題。
  • 數(shù)據(jù)訪問:Native如何訪問H5資源(File方式訪問H5本地靜態(tài)資源/URL方式訪問服務器資源)。資源增量替換是Android的,iOS不用考慮。
  • 登錄(及支付/分享等)模塊:這些模塊具體由誰實現(xiàn)?Native/Web一方操作怎樣使另一方收到對應信息并處理?(支付/分享建議Native端來做,都有相應的SDK)
  • 開發(fā)調(diào)試:Native與前端需要商量出一套可開發(fā)調(diào)試的模型,不然很多業(yè)務開發(fā)的工作將難以繼續(xù)。

Hybrid交互設計

UIWebView由于其API難用、還有內(nèi)存泄漏,現(xiàn)在已經(jīng)棄用,iOS8以上都應該盡量用新的WKWebview。WK提供了一系列API來使得Native與Web的信息交換簡單高效。還有一個不可忽視的一點是WK使用與Safari相同的JS引擎+內(nèi)置手勢+無內(nèi)存泄漏,是UIWebView的替代者。所以在這里UIWebView只做簡要介紹。

  • UIWebView
    Native調(diào)JS方法
    webView.stringByEvaluatingJavaScriptFromString()

    JS調(diào)Native方法
    UIWebView沒有辦法直接使用js調(diào)用app,但是可以通過攔截request的方式間接實現(xiàn)JS調(diào)用Native方法,另一種是使用JavaScriptCore的jsContext注冊objc對象或使用JSExport協(xié)議導出Native對象的方式。本文主要介紹第一種實現(xiàn),第二種實現(xiàn)方式不再贅述。

    func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool{
             //如果請求協(xié)議是hello 這里的hello來自js的調(diào)用,在js中設為 document.location = "hello://你好";
             //scheme:hello ,msg:你好
             //通過url攔截的方式,作為對ios原生方法的呼叫
             if request.URL?.scheme == "hello"{
                 let method:String = request.URL?.scheme as String!
                 let sel =  Selector(method+":")
                 self.performSelector(sel, withObject:request.URL?.host)
                 request.URL?.path
                 //如果return true ,頁面加載request,我們只是當做協(xié)議使用所以不能頁面跳轉(zhuǎn)
                 return false
             }
             return true
         }

函數(shù)回調(diào)/返回值
Native調(diào)JS可以有返回值,但是JS調(diào)Native是通過間接的攔截request方式實現(xiàn),它根本就不算方法調(diào)用,所以應該是不存在可以直接產(chǎn)生返回值的。當然如果需要Native對JS的調(diào)用有所響應,可以通過回調(diào)函數(shù)的方式回應JS??梢栽谡{(diào)用Native的時候增加一個JS回叫函數(shù)名 app在處理完之后調(diào)用回調(diào)函數(shù)并把需要的參數(shù)通過回調(diào)函數(shù)的方式進行傳遞。

  • WKWebView
    Web腳本注入
    WKUserScript 允許在正文加載之前或之后注入到頁面中。這個強大的功能允許在頁面中以安全且唯一的方式操作網(wǎng)頁內(nèi)容。
    WKUserScript 對象可以以 JavaScript 源碼形式初始化,初始化時還可以傳入是在加載之前還是結(jié)束時注入,以及腳本影響的是這個布局還是僅主要布局。于是用戶腳本被加入到 WKUserContentController 中,并且以 WKWebViewConfiguration 屬性傳入到 WKWebView 的初始化過程中。這個樣例可以簡單擴展為更為高級的頁面修改方法,例如去除廣告、隱藏評論等。
    let source = "document.body.style.background = \"#777\";"
    let userScript = WKUserScript(source: source, injectionTime: .AtDocumentEnd, forMainFrameOnly: true)
 
     let userContentController = WKUserContentController()
     userContentController.addUserScript(userScript)
     let configuration = WKWebViewConfiguration()
     configuration.userContentController = userContentController
     self.webView = WKWebView(frame: self.view.bounds, configuration: configuration)

Native調(diào)JS方法

     //直接調(diào)用JS
      webView.evaluateJavaScript("hi()", completionHandler: nil)
         //調(diào)用JS帶參數(shù)
         webView.evaluateJavaScript("hello('liuyanwei')", completionHandler: nil)
         //調(diào)用JS獲取返回值
         webView.evaluateJavaScript("getName()") { (any,error) -> Void in
             NSLog("%@", any as! String)
         }
WK通過與UIWebView類似的方法調(diào)用JS語句,但獲取返回值的方式不同,WKWebView用的是回調(diào)函數(shù)獲取返回值。

**JS調(diào)Native方法**
Web中的信息也可以通過調(diào)用這個函數(shù)被傳給Native里:
```
var message = {
                         'method' : 'hello',
                         'param1' : 'haibao',
                         };
window.webkit.messageHandlers.webViewApp.postMessage(message);
//這個 API 真正神奇的地方在于 JavaScript 對象可以自動轉(zhuǎn)換為 Objective-C 或 Swift 對象。
//Native中Handler的注冊handler需要在WKWebView初始化之前
config = WKWebViewConfiguration()
          //注冊js方法
         config.userContentController.addScriptMessageHandler(self, name: "webViewApp")
         webView = WKWebView(frame: self.webWrap.frame, configuration: config)
//處理handler委托。ViewController實現(xiàn)WKScriptMessageHandler委托的func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage)方法
//實現(xiàn)WKScriptMessageHandler委托
      class ViewController:WKScriptMessageHandler
      //實現(xiàn)js調(diào)用ios的handle委托
      func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {
          //接受傳過來的消息從而決定app調(diào)用的方法
          let dict = message.body as! Dictionary<String,String>
          let method:String = dict["method"]!
          let param1:String = dict["param1"]!
          if method=="hello"{
              hello(param1)
          }
      }
```
**Alert攔截**
在WKWebview中,JS的Alert是不會出現(xiàn)任何內(nèi)容的,你必須重寫WKUIDelegate委托的runJavaScriptAlertPanelWithMessage message方法,自己處理Alert。類似的還有Confirm和Prompt也和Alert類似。
```
Alert攔截方法
func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void) {
         completionHandler()
         let alert = UIAlertController(title: "ios-alert", message: "\(message)", preferredStyle: .Alert)
         alert.addAction(UIAlertAction(title: "ok", style: .Default, handler:nil))
         alert.addAction(UIAlertAction(title: "cancel", style: .Cancel, handler: nil))
         self.presentViewController(alert, animated: true, completion: nil)
     }
```

Native/Web端做好交互格式約定,Native端提供規(guī)范性的API供Web端訪問。
常用API:
* 界面跳轉(zhuǎn)(N->W/W->N/W->W/W->W新開WebView)+過場動畫
* Header組件
* NativeUI相關組件(Loading遮罩等)
* 分享
* 推送
* 登錄


框架架構

架構選擇MVC,因為上層邏輯都是Web端實現(xiàn)的,對于Controller的負擔不是太重。
框架結(jié)構為TabBar+Navi。
Web部分將入口界面的樣式資源存放本地,后續(xù)跳轉(zhuǎn)及動態(tài)數(shù)據(jù)通過網(wǎng)絡獲取。
下圖是參考的Web目錄結(jié)構圖。


Hybrid目錄結(jié)構圖
Hybrid目錄結(jié)構圖

數(shù)據(jù)請求

約定調(diào)用請求格式

let data = {url:'requestURL',
             param: {參數(shù)},
             type: 'post'
}

約定返回數(shù)據(jù)格式

let data = ["data": data,     //網(wǎng)絡請求結(jié)果、本地數(shù)據(jù)等回傳信息
          "errno": errno,   //錯誤碼
            "msg": msg,       //描述
            "callback": callback]    //回調(diào)ID

Web端通過傳遞一個字典將需要的請求信息交給Native處理,Native處理完畢后數(shù)據(jù)通過Web端回調(diào)。

let dataString = self.toJSONString(data)
webView.stringByEvaluatingJavaScriptFromString(self.getRequest + "(\(dataString));")

本地數(shù)據(jù)訪問

約定數(shù)據(jù)訪問格式

let data = {name:'name',
            type:'dataType'
}

約定返回數(shù)據(jù)格式

let data = ["data": data,     //本地數(shù)據(jù)請求結(jié)果
          "errno": errno,     //錯誤碼
            "msg": msg,       //描述
            "callback": callback]    //回調(diào)ID

參考資料:

聊聊Web App、Hybrid App與Native App的設計差異
Hybrid App開發(fā)實戰(zhàn)
iOS 8 WebKit框架概覽
淺談Hybrid技術的設計與實現(xiàn)1
淺談Hybrid技術的設計與實現(xiàn)2
去啊App實戰(zhàn):極致的Hybrid混合式開發(fā)
三層架構
UIWebView和WKWebView的使用及js交互
WKWeb View

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容