iPhone 應(yīng)該如何運(yùn)行軟件呢?像 OS X 上的應(yīng)用程序,或者 web 頁面,以及 Safari 都應(yīng)該如何運(yùn)行起來呢?仿照 OS X 去構(gòu)建 iPhone OS 的方法已經(jīng)廣泛地被大家熟知了,這種方法到今天也留下了不少爭議。
Web 一直是 iOS 系統(tǒng)上的二級(jí)公民(諷刺的是,其實(shí)現(xiàn)今移動(dòng)網(wǎng)頁響應(yīng)式設(shè)計(jì)的出現(xiàn)大多是 iPhone 推動(dòng)的)。UIWebView笨重難用,還有內(nèi)存泄漏,和 Nirtro JavaScript 引擎談笑風(fēng)生的 Safari 不知道要比它高到哪里去了。
然而,這所有的一切都會(huì)因?yàn)閃KWebView和WebKit框架其他部分的出現(xiàn)而發(fā)生改變。
WKWebView是現(xiàn)代 WebKit API 在 iOS 8 和 OS X Yosemite 應(yīng)用中的核心部分。它代替了 UIKit 中的UIWebView和 AppKit 中的WebView,提供了統(tǒng)一的跨雙平臺(tái) API。
自詡擁有 60fps 滾動(dòng)刷新率、內(nèi)置手勢(shì)、高效的 app 和 web 信息交換通道、和 Safari 相同的 JavaScript 引擎,WKWebView毫無疑問地成為了 WWDC 2014 上的最亮點(diǎn)。
UIWebView&UIWebViewDelegate這個(gè)兩個(gè)東西是如何在 WKWebKit 中被重構(gòu)成 14 個(gè)類 3 個(gè)協(xié)議的呢。雖然這次的變化確實(shí)帶來了不少的新功能,但請(qǐng)一定不要因此感到恐慌!
WKWebKit Framework
Classes
WKBackForwardList: 之前訪問過的 web 頁面的列表,可以通過后退和前進(jìn)動(dòng)作來訪問到。
WKBackForwardListItem: webview 中后退列表里的某一個(gè)網(wǎng)頁。
WKFrameInfo: 包含一個(gè)網(wǎng)頁的布局信息。
WKNavigation: 包含一個(gè)網(wǎng)頁的加載進(jìn)度信息。
WKNavigationAction: 包含可能讓網(wǎng)頁導(dǎo)航變化的信息,用于判斷是否做出導(dǎo)航變化。
WKNavigationResponse: 包含可能讓網(wǎng)頁導(dǎo)航變化的返回內(nèi)容信息,用于判斷是否做出導(dǎo)航變化。
WKPreferences: 概括一個(gè) webview 的偏好設(shè)置。
WKProcessPool: 表示一個(gè) web 內(nèi)容加載池。
WKUserContentController: 提供使用 JavaScript post 信息和注射 script 的方法。
WKScriptMessage: 包含網(wǎng)頁發(fā)出的信息。
WKUserScript: 表示可以被網(wǎng)頁接受的用戶腳本。 > -WKWebViewConfiguration: 初始化 webview 的設(shè)置。
WKWindowFeatures: 指定加載新網(wǎng)頁時(shí)的窗口屬性。
Protocols
WKNavigationDelegate: 提供了追蹤主窗口網(wǎng)頁加載過程和判斷主窗口和子窗口是否進(jìn)行頁面加載新頁面的相關(guān)方法。
WKScriptMessageHandler: 提供從網(wǎng)頁中收消息的回調(diào)方法。
WKUIDelegate: 提供用原生控件顯示網(wǎng)頁的方法回調(diào)。
UIWebView和WKWebView的 API 區(qū)別
WKWebView繼承了UIWebView大部分的接口,這讓 app 來繼承 WKWebKit 也簡單了許多(同時(shí)隨著更新 iOS 8 的越來越多這也成為了某種必需)。
看一下這兩個(gè)類的 API 區(qū)別:

頁面加載


訪問歷史

頁碼
WKWebView目前缺少關(guān)于頁碼相關(guān)的 API。
var paginationMode: UIWebPaginationMode
var paginationBreakingMode: UIWebPaginationBreakingMode
var pageLength: CGFloat
var gapBetweenPages: CGFloat
var pageCount: Int { get }
重構(gòu)分離開的WKWebViewConfiguration
下面這些UIWebView的屬性被重構(gòu)進(jìn)了在初始化WKWebView傳入的設(shè)置對(duì)象:
var allowsInlineMediaPlayback: Bool
var mediaPlaybackRequiresUserAction: Bool
var mediaPlaybackAllowsAirPlay: Bool
var suppressesIncrementalRendering: Bool
JavaScript ?? Swift 對(duì)話機(jī)制
相對(duì)于UIWebView最大的提升就是數(shù)據(jù)在可以 app 和 web 內(nèi)容之間傳遞。
使用用戶腳本來注入 JavaScript
WKUserScript允許在正文加載之前或之后注入到頁面中。這個(gè)強(qiáng)大的功能允許在頁面中以安全且唯一的方式操作網(wǎng)頁內(nèi)容。
一個(gè)簡單的例子如下,用戶改變背景的用戶腳本被插入到網(wǎng)頁中:
letsource="document.body.style.background =\"#777\";"
letuserScript=WKUserScript(source:source,injectionTime:.AtDocumentEnd,forMainFrameOnly:true)
letuserContentController=WKUserContentController()
userContentController.addUserScript(userScript)
letconfiguration=WKWebViewConfiguration()
configuration.userContentController=userContentController
self.webView=WKWebView(frame:self.view.bounds,configuration:configuration)
WKUserScript對(duì)象可以以 JavaScript 源碼形式初始化,初始化時(shí)還可以傳入是在加載之前還是結(jié)束時(shí)注入,以及腳本影響的是這個(gè)布局還是僅主要布局。于是用戶腳本被加入到WKUserContentController中,并且以WKWebViewConfiguration屬性傳入到WKWebView的初始化過程中。
這個(gè)樣例可以簡單擴(kuò)展為更為高級(jí)的頁面修改方法,例如去除廣告、隱藏評(píng)論等,
web 和 app 通訊機(jī)制也通過 message handler 有很大提升。
就想在Safari 審查元素功能中的console.log能在調(diào)試終端打印信息一樣,網(wǎng)頁中的信息也可以通過調(diào)用這個(gè)函數(shù)被傳到 app 里:
window.webkit.messageHandlers.{NAME}.postMessage()
這個(gè) API 真正神奇的地方在于 JavaScript 對(duì)象可以自動(dòng)轉(zhuǎn)換為 Objective-C 或 Swift 對(duì)象。
Handler 的名字可以通過WKScriptMessageHandler協(xié)議中的addScriptMessageHandler()接口函數(shù)設(shè)置:
classNotificationScriptMessageHandler:NSObject,WKScriptMessageHandler{funcuserContentController(userContentController:WKUserContentController,didReceiveScriptMessagemessage:WKScriptMessage!){println(message.body)}}letuserContentController=WKUserContentController()lethandler=NotificationScriptMessageHandler()userContentController.addScriptMessageHandler(handler,name:"notification")
于是當(dāng)通知進(jìn)入 app 的時(shí)候,比如說在頁面中創(chuàng)建一個(gè)新對(duì)象,相關(guān)信息就可以這樣傳遞:
window.webkit.messageHandlers.notification.postMessage({body:"..."});
添加用戶腳本來對(duì) web 事件監(jiān)聽并用 Message Handler 將信息傳回 app。
同樣的方法也可以用來收集頁面信息用于 app 的頁面展示或數(shù)據(jù)分析。
例如,如果某人要針對(duì) NSHipster.com 做一個(gè)特別的瀏覽器,就可以加一個(gè)能夠呼出相似文章列表的按鈕:
// document.location.href == "http://nshipster.com/webkit"functiongetRelatedArticles(){varrelated=[];varelements=document.getElementById("related").getElementsByTagName("a");for(i=0;i
如果你的 app 只是對(duì)網(wǎng)頁內(nèi)容做了很簡單的一層包裝,那么WKWebView可以徹底改變這種狀況。你對(duì)于性能和兼容性的所有愿望都將變?yōu)楝F(xiàn)實(shí)。所有你想要的東西都在這了。
如果你是一個(gè)原生純粹主義者,你可能會(huì)被 iOS 8 新帶來強(qiáng)大和擴(kuò)展性功能嚇到。有一個(gè)秘密就是,例如 Messages 這種原生應(yīng)用都應(yīng)用了 WebKit 來渲染復(fù)雜的頁面元素。你可能尚且沒有意識(shí)到,但事實(shí)是,webview 在移動(dòng)開發(fā)最佳實(shí)踐中應(yīng)該得到一席之地。