公司想要將自己的產品由網頁端移植到原生,提升用戶體驗,因此在網上查找相關資料。最后App決定使用Hybrid架構來實現快速上線。
第一次寫文章,比較粗糙,諸位看官如果想更細致的了解HybridApp,請移步最下參考資料。
文章部分引用了相關資料的語句,在此感謝相關資料的作者。
伴隨著移動互聯網產業的興起,各式App層出不窮,我們迫切需求一種更快速、成本更低、技術更為成熟的項目開發方案,而H5的成熟讓我們看到了希望,使得Web App開始崛起。
為了提高用戶體驗,目前網站一般分為3個版本,簡版、移動版、電腦版,簡板Web普遍是基于WAP2.0開發的,界面視覺效果差、功能簡單;移動版則普遍使用H5開發,適用于現在大家普遍使用的移動上網設備,擁有更好的視覺效果、交互方式,迥然不同于簡板Web的設計風格;而電腦版在此則不做討論。
個人認為現在的Web App就是由移動版網頁發展而來。
目前App大致分為三個大類
-
Web App
定義:將所有功能都放在Web上展現,運行基于本地瀏覽器。在此將給Web簡單的套一層App外殼的應用也歸入Web App。完全采用HTML/CSS/JS編寫,專為觸摸操作進行了優化。目前iOS已禁止簡單的套殼App上架。
優點:開發速度快,跨平臺,成本低,實時迭代用戶無需更新
缺點:網絡速度要求高、服務器壓力大,系統級別API調用難度大,用戶體驗差、用戶留存度低 -
Native App
定義::NativeApp是基于手機本地操作系統并使用原生語言編寫的 。因為位于平臺層上方,向下訪問和兼容的能力會比較好一些,可以 支持在線或離線訪問,消息推送或本地資源訪問,攝像撥號功能的調 取。但是由于設備碎片化,App的開發成本要高很多,維持多個版本 的更新升級比較麻煩,用戶的安裝門檻也比較高。
優點:用戶體驗佳、交互風格與系統吻合,節省流量,可訪問本地資源,速度快,用戶留存度高
缺點:成本高,版本迭代慢,需要過審 -
Hybrid App
定義:介于Web App與Native App的一種折中方案,底層(框架)部分由iOS/Android開發人員處理,上層(內容展現)部分由Web前端人員處理,用戶界面操作邏輯及部分靜態資源駐留本地,使得Web App可以對操作迅速反應并在很大程度上實現離線訪問。Hybrid App追求趨近于原生App的體驗,但目前還較困難。

需要考慮的方面
- 分清Native與前端的界限,Native提供宿主環境,前端需要合理的利用Native提供的資源,提升用戶體驗及自身性能。在設計上需要考慮以下問題:
- 交互設計:如何設計與前端的交互?Native需要考慮提供NativeUI/Header/消息/Alert等組件接口、通訊錄/系統/設備信息讀取接口、Native/H5相互跳轉(H5跳Native、H5新開WebView跳轉、Native跳轉H5)等問題。
- 數據訪問:Native如何訪問H5資源(File方式訪問H5本地靜態資源/URL方式訪問服務器資源)。資源增量替換是Android的,iOS不用考慮。
- 登錄(及支付/分享等)模塊:這些模塊具體由誰實現?Native/Web一方操作怎樣使另一方收到對應信息并處理?(支付/分享建議Native端來做,都有相應的SDK)
- 開發調試:Native與前端需要商量出一套可開發調試的模型,不然很多業務開發的工作將難以繼續。
Hybrid交互設計
UIWebView由于其API難用、還有內存泄漏,現在已經棄用,iOS8以上都應該盡量用新的WKWebview。WK提供了一系列API來使得Native與Web的信息交換簡單高效。還有一個不可忽視的一點是WK使用與Safari相同的JS引擎+內置手勢+無內存泄漏,是UIWebView的替代者。所以在這里UIWebView只做簡要介紹。
-
UIWebView
Native調JS方法
webView.stringByEvaluatingJavaScriptFromString()
JS調Native方法
UIWebView沒有辦法直接使用js調用app,但是可以通過攔截request的方式間接實現JS調用Native方法,另一種是使用JavaScriptCore的jsContext注冊objc對象或使用JSExport協議導出Native對象的方式。本文主要介紹第一種實現,第二種實現方式不再贅述。
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool{
//如果請求協議是hello 這里的hello來自js的調用,在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,我們只是當做協議使用所以不能頁面跳轉
return false
}
return true
}
函數回調/返回值
Native調JS可以有返回值,但是JS調Native是通過間接的攔截request方式實現,它根本就不算方法調用,所以應該是不存在可以直接產生返回值的。當然如果需要Native對JS的調用有所響應,可以通過回調函數的方式回應JS。可以在調用Native的時候增加一個JS回叫函數名 app在處理完之后調用回調函數并把需要的參數通過回調函數的方式進行傳遞。
- WKWebView
Web腳本注入
WKUserScript 允許在正文加載之前或之后注入到頁面中。這個強大的功能允許在頁面中以安全且唯一的方式操作網頁內容。
WKUserScript 對象可以以 JavaScript 源碼形式初始化,初始化時還可以傳入是在加載之前還是結束時注入,以及腳本影響的是這個布局還是僅主要布局。于是用戶腳本被加入到 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調JS方法
//直接調用JS
webView.evaluateJavaScript("hi()", completionHandler: nil)
//調用JS帶參數
webView.evaluateJavaScript("hello('liuyanwei')", completionHandler: nil)
//調用JS獲取返回值
webView.evaluateJavaScript("getName()") { (any,error) -> Void in
NSLog("%@", any as! String)
}
WK通過與UIWebView類似的方法調用JS語句,但獲取返回值的方式不同,WKWebView用的是回調函數獲取返回值。
**JS調Native方法**
Web中的信息也可以通過調用這個函數被傳給Native里:
```
var message = {
'method' : 'hello',
'param1' : 'haibao',
};
window.webkit.messageHandlers.webViewApp.postMessage(message);
//這個 API 真正神奇的地方在于 JavaScript 對象可以自動轉換為 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實現WKScriptMessageHandler委托的func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage)方法
//實現WKScriptMessageHandler委托
class ViewController:WKScriptMessageHandler
//實現js調用ios的handle委托
func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) {
//接受傳過來的消息從而決定app調用的方法
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是不會出現任何內容的,你必須重寫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端提供規范性的API供Web端訪問。
常用API:
* 界面跳轉(N->W/W->N/W->W/W->W新開WebView)+過場動畫
* Header組件
* NativeUI相關組件(Loading遮罩等)
* 分享
* 推送
* 登錄
框架架構
架構選擇MVC,因為上層邏輯都是Web端實現的,對于Controller的負擔不是太重。
框架結構為TabBar+Navi。
Web部分將入口界面的樣式資源存放本地,后續跳轉及動態數據通過網絡獲取。
下圖是參考的Web目錄結構圖。

數據請求
約定調用請求格式
let data = {url:'requestURL',
param: {參數},
type: 'post'
}
約定返回數據格式
let data = ["data": data, //網絡請求結果、本地數據等回傳信息
"errno": errno, //錯誤碼
"msg": msg, //描述
"callback": callback] //回調ID
Web端通過傳遞一個字典將需要的請求信息交給Native處理,Native處理完畢后數據通過Web端回調。
let dataString = self.toJSONString(data)
webView.stringByEvaluatingJavaScriptFromString(self.getRequest + "(\(dataString));")
本地數據訪問
約定數據訪問格式
let data = {name:'name',
type:'dataType'
}
約定返回數據格式
let data = ["data": data, //本地數據請求結果
"errno": errno, //錯誤碼
"msg": msg, //描述
"callback": callback] //回調ID
參考資料:
聊聊Web App、Hybrid App與Native App的設計差異
Hybrid App開發實戰
iOS 8 WebKit框架概覽
淺談Hybrid技術的設計與實現1
淺談Hybrid技術的設計與實現2
去啊App實戰:極致的Hybrid混合式開發
三層架構
UIWebView和WKWebView的使用及js交互
WKWeb View