UIWebView和WKWebView比較
原先有些程式是使用UIWebView去開發,但是自iOS 8.0之後蘋果推薦使用WKWebView去取代舊有的元件,因此為了理解WKWebView與舊有的UIWebView相比有何進步之處,以及如何將UIWebView替換成WKWebView而去做了些整理。
WKWebView的優勢
- WKWebView適用於iOS和OS X。之前iOS是使用UIWebView而OS X是使用WebView,現在就可以都用WKWebView。
- WKWebView使用了Multi-process Architecture。WKWebView執行程序獨立於App之外,系統會統一管理以增進效能也更省電。建立WKWebView物件會分配個Web content processs,建立越多就會用越多Web content process,不過這會有個限制,過多的WKWebView會共享同個Web content process,因此當Web內容包含了許多JavaScript物件或複雜的動畫效果,APP依然可以持續地保持回應,也就是說如果WKWebView使用了過多的記憶體,他並不會Crash本身的App,只不過畫面會變成一片空白。
- WKWebView支援60fps的畫面滾動更新。藉由hardware acceleration和Core Animation達成。
- 使用Nitro JavaScript引擎。WKWebView採用了跟Safari一樣的JavaScript引擎大大地提升了效能。
- 內建手勢支援。返回上一頁和放大縮小手勢。
- App和Web page的溝通更方便。WKWebView新增了WKScriptMessageHandler協定,可以讓Objective-C或Swift透過監聽的方式,直接得到執行JavaScript的回應。
從UIWebView到WKWebView
WKWebView的方法與UIWebView相比而言是分的更多更細了,基本上UIWebView可以做到的功能WKWebView也可以做到,另外還增加了些新的功能。
Protocols
UIWebView | WKWebView |
---|---|
var delegate: UIWebViewDelegate? | var navigationDelegate: WKNavigationDelegate? |
var uiDelegate: WKUIDelegate? |
以Web頁面導覽功能來說,從UIWebView換到WKWebView只要把delegate換成navigationDelegate就可以滿足大部份的需求,不過如果有彈出視窗的介面需求就會需要用到uiDelegate。
Loading Content
UIWebView | WKWebView |
---|---|
func loadRequest(URLRequest) | func load(URLRequest) -> WKNavigation? |
func loadHTMLString(String, baseURL: URL?) | func loadHTMLString(String, baseURL: URL?) -> WKNavigation? |
func load(Data, mimeType: String, textEncodingName: String, baseURL: URL) | func load(Data, mimeType: String, characterEncodingName: String, baseURL: URL) -> WKNavigation? |
func loadFileURL(URL, allowingReadAccessTo: URL) -> WKNavigation? |
功能基本上也差不多,有一個比較要注意的地方是在iOS 8的版本WKWebView無法從main bundle直接讀取web的資源,直到iOS 9以上才解決了這個問題。
JavaScript Communication
UIWebView | WKWebView |
---|---|
func stringByEvaluatingJavaScript(from script: String) -> String? | func evaluateJavaScript(_ javaScriptString: String, completionHandler: ((Any?, Error?) -> Void)? = nil) |
UIWebView執行JavaScript的方法為同步任務,而WKWebView則是非同步任務,因此使用UIWebView的方法可能會造成App有停頓的感覺,這裡WKWebView是比較適當的。
WKWebView還新增了兩種和JavaScript溝通的模式:
透過
WKUserScript
寫入JavaScript。透過WKWebView的設定,可以決定何時寫入JavaScript的Source以及寫入的位置,相比原來的方法有更多的彈性。let jsSource = "document.getElementsByTagName(\"h3\").style.fontSize = \"17px\"" // 決定寫入JavaScript的方式 let userScript = WKUserScript(source: source, injectionTime: .AtDocumentEnd, forMainFrameOnly: true) webView.configuration.userContentController.addUserScript(userScript)
使用
WKScriptMessageHandler
接收JavaScript執行結果。註冊一個message handler方法,就可以在Web呼叫這個方法時,通知App端這個方法被執行了,也可以藉此傳遞參數讓App得到Web內容的狀態。一開始要先註冊一個message handler:
webView.configuration.userContentController.add(self, name: "callBack")
在JavaScript的方法中去呼叫這個message handler加上傳遞參數:
window.webkit.messageHandlers.callBack.postMessage("Hello");
最後在App端去接收JavaScript回傳的結果:
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { guard let body: String = message.body as? String else { return } // 可以顯示出"Hello"的字串 print(body) }
來源: