第一、WKWebView增加的属性和方法
类比UIWebView,跟UIWebView的API对比,
增加的属性:
1、estimatedProgress 加载进度条,在IOS8之前我们是通过一个假的进度条来实现
2、backForwardList 表示historyList
3、WKWebViewConfiguration *configuration; 初始化webview的配置
增加的方法:
1、- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration
初始化
3、(WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item;
跳到历史的某个页面
第二、相同的属性和方法
goBack、goForward、canGoBack、canGoForward、stopLoading、loadRequest、scrollView
第三、被删去的属性和方法:
1、- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
在跟js交互时,我们使用这个API,目前WKWebView
2、无法设置缓存
在UIWebView,使用NSURLCache缓存,通过setSharedURLCache可以设置成我们自己的缓存,但WKWebView不支持NSURLCache
第四、delegate方法的不同
UIWebView支持的代理是UIWebViewDelegate,WKWebView支持的代理是WKNavigationDelegate和WKUIDelegate
WKNavigationDelegate主要实现了涉及到导航跳转方面的回调方法
WKUIDelegate主要实现了涉及到界面显示的回调方法:如WKWebView的改变和js相关内容
具体来说WKNavigationDelegate除了有开始加载、加载成功、加载失败的API外,还具有额外的三个代理方法:
1、- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation
这个代理是服务器redirect时调用
2、- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
这个代理方法表示当客户端收到服务器的响应头,根据response相关信息,可以决定这次跳转是否可以继续进行。
3.- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
根据webView、navigationAction相关信息决定这次跳转是否可以继续进行,这些信息包含HTTP发送请求,如头部包含User-Agent,Accept
---------------------------------------------------------------------------------------------------------------------------
WKWebView
是现代 WebKit API 在 iOS 8 和 OS X Yosemite 应用中的核心部分。它代替了 UIKit 中的UIWebView
和 AppKit 中的 WebView
,提供了统一的跨双平台 API。
自诩拥有 60fps 滚动刷新率、内置手势、高效的 app 和 web 信息交换通道、和 Safari 相同的 JavaScript 引擎,WKWebView
毫无疑问地成为了 WWDC 2014 上的最亮点。
UIWebView
& UIWebViewDelegate
这个两个东西是如何在 WKWebKit 中被重构成 14 个类 3 个协议的呢。虽然这次的变化确实带来了不少的新功能,但请一定不要因此感到恐慌!
WKWebKit Framework
Classes
WKBackForwardList
: 之前访问过的 web 页面的列表,可以通过后退和前进动作来访问到。
WKBackForwardListItem
: webview 中后退列表里的某一个网页。WKFrameInfo
: 包含一个网页的布局信息。WKNavigation
: 包含一个网页的加载进度信息。
WKNavigationAction
: 包含可能让网页导航变化的信息,用于判断是否做出导航变化。WKNavigationResponse
: 包含可能让网页导航变化的返回内容信息,用于判断是否做出导航变化。WKPreferences
: 概括一个 webview 的偏好设置。WKProcessPool
: 表示一个 web 内容加载池。WKUserContentController
: 提供使用 JavaScript post 信息和注射 script 的方法。
WKScriptMessage
: 包含网页发出的信息。WKUserScript
: 表示可以被网页接受的用户脚本。 > -WKWebViewConfiguration
: 初始化 webview 的设置。WKWindowFeatures
: 指定加载新网页时的窗口属性。
Protocols
WKNavigationDelegate
: 提供了追踪主窗口网页加载过程和判断主窗口和子窗口是否进行页面加载新页面的相关方法。WKScriptMessageHandler
: 提供从网页中收消息的回调方法。WKUIDelegate
: 提供用原生控件显示网页的方法回调。
UIWebView
和 WKWebView
的 API 区别
WKWebView
继承了 UIWebView
大部分的接口,这让 app 来继承 WKWebKit 也简单了许多(同时随着更新 iOS 8 的越来越多这也成为了某种必需)。
有兴趣的同学可以看一下这两个类的 API 区别:
UIWebView | WKWebView |
---|---|
var scrollView: UIScrollView! { get } | var scrollView: UIScrollView! { get } |
var configuration: WKWebViewConfiguration! { get } | |
var delegate: UIWebViewDelegate! | var UIDelegate: WKUIDelegate! |
var navigationDelegate: WKNavigationDelegate! | |
var backForwardList: WKBackForwardList! { get } |
页面加载
UIWebView | WKWebView |
---|---|
func loadRequest(request: NSURLRequest!) | func loadRequest(request: NSURLRequest!) -> WKNavigation! |
func loadHTMLString(string: String!, baseURL: NSURL!) | func loadHTMLString(string: String!, baseURL: NSURL!) -> WKNavigation! |
func loadData(data: NSData!, MIMEType: String!, textEncodingName: String!, baseURL: NSURL!) | |
var estimatedProgress: Double { get } | |
var hasOnlySecureContent: Bool { get } | |
func reload() | func reload() -> WKNavigation! |
func reloadFromOrigin() -> WKNavigation! | |
func stopLoading() | func stopLoading() |
var request: NSURLRequest! { get } | |
var URL: NSURL! { get } | |
var title: String! { get } |
访问历史
UIWebView | WKWebView |
---|---|
func goToBackForwardListItem(item: WKBackForwardListItem!) -> WKNavigation! | |
func goBack() | func goBack() -> WKNavigation! |
func goForward() | func goForward() -> WKNavigation! |
var canGoBack: Bool { get } | var canGoBack: Bool { get } |
var canGoForward: Bool { get } | var canGoForward: Bool { get } |
var loading: Bool { get } | var loading: Bool { get } |
调用 Javascript
UIWebView | WKWebView |
---|---|
func stringByEvaluatingJavaScriptFromString(script: String!) -> String! | |
func evaluateJavaScript(javaScriptString: String!, completionHandler: ((AnyObject!, NSError!) -> Void)!) |
原生混用
UIWebView | WKWebView |
---|---|
var keyboardDisplayRequiresUserAction: Bool | |
var scalesPageToFit: Bool | |
var allowsBackForwardNavigationGestures: Bool |
页码
WKWebView
目前缺少关于页码相关的 API。
var paginationMode: UIWebPaginationMode
var paginationBreakingMode: UIWebPaginationBreakingMode
var pageLength: CGFloat
var gapBetweenPages: CGFloat
var pageCount: Int { get }
重构分离开的 WKWebViewConfiguration
下面这些 UIWebView
的属性被重构进了在初始化 WKWebView
传入的设置对象:
var allowsInlineMediaPlayback: Bool
var mediaPlaybackRequiresUserAction: Bool
var mediaPlaybackAllowsAirPlay: Bool
var suppressesIncrementalRendering: Bool
JavaScript ↔︎ Swift 对话机制
相对于 UIWebView
最大的提升就是数据在可以 app 和 web 内容之间传递。
使用用户脚本来注入 JavaScript
WKUserScript
允许在正文加载之前或之后注入到页面中。这个强大的功能允许在页面中以安全且唯一的方式操作网页内容。
一个简单的例子如下,用户改变背景的用户脚本被插入到网页中:
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)
WKUserScript
对象可以以 JavaScript 源码形式初始化,初始化时还可以传入是在加载之前还是结束时注入,以及脚本影响的是这个布局还是仅主要布局。于是用户脚本被加入到 WKUserContentController
中,并且以 WKWebViewConfiguration
属性传入到 WKWebView
的初始化过程中。
这个样例可以简单扩展为更为高级的页面修改方法,例如去除广告、隐藏评论等,更复杂的样例见此:让所有出现的"the cloud"变为"my butt"。
马杀鸡 魂斗罗(Message Handlers 抱歉我憋了一天,真的不会翻译)
web 和 app 通讯机制也通过 message handler 有很大提升。
就想在Safari 审查元素功能中的 console.log
能在调试终端打印信息一样,网页中的信息也可以通过调用这个函数被传到 app 里:
window.webkit.messageHandlers.{NAME}.postMessage()
这个 API 真正神奇的地方在于 JavaScript 对象可以自动转换为 Objective-C 或 Swift 对象。
Handler 的名字可以通过 WKScriptMessageHandler
协议中的 addScriptMessageHandler()
接口函数设置:
class NotificationScriptMessageHandler: NSObject, WKScriptMessageHandler {
func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage!) {
println(message.body)
}
}
let userContentController = WKUserContentController()
let handler = NotificationScriptMessageHandler()
userContentController.addScriptMessageHandler(handler, name: "notification")
于是当通知进入 app 的时候,比如说在页面中创建一个新对象,相关信息就可以这样传递:
window.webkit.messageHandlers.notification.postMessage({body: "..."});
添加用户脚本来对 web 事件监听并用 Message Handler 将信息传回 app。
同样的方法也可以用来收集页面信息用于 app 的页面展示或数据分析。
例如,如果某人要针对 NSHipster.com 做一个特别的浏览器,就可以加一个能够呼出相似文章列表的按钮:
// document.location.href == "http://nshipster.com/webkit"
function getRelatedArticles() {
var related = [];
var elements = document.getElementById("related").getElementsByTagName("a");
for (i = 0; i < elements.length; i++) {
var a = elements[i];
related.push({href: a.href, title: a.title});
}
window.webkit.messageHandlers.related.postMessage({articles: related});
}
let js = "getRelatedArticles();"
self.webView?.evaluateJavaScript(js) { (_, error) in
println(error)
}
// Get results in previously-registered message handler
如果你的 app 只是对网页内容做了很简单的一层包装,那么 WKWebView
可以彻底改变这种状况。你对于性能和兼容性的所有愿望都将变为现实。所有你想要的东西都在这了。
如果你是一个原生纯粹主义者,你可能会被 iOS 8 新带来强大和扩展性功能吓到。有一个秘密就是,例如 Messages 这种原生应用都应用了 WebKit 来渲染复杂的页面元素。你可能尚且没有意识到,但事实是,webview 在移动开发最佳实践中应该得到一席之地。