自從iOS8開始,Apple引入了WKWebView欲代替UIWebView。相比而言,WKWebView消耗內從更少,功能也更加強大。讓我們來看看WKWebView怎麼使用吧!
0.初始化
(1)首先需要引入WebKit庫
複製代碼 代碼如下:
#import <WebKit/WebKit.h>
(2)初始化方法分為以下兩種
複製代碼 代碼如下:
// 預設初始化
- (instancetype)initWithFrame:(CGRect)frame;
// 根據對webview的相關配置,進行初始化
- (instancetype)initWithFrame:(CGRect)frame configuration:(WKWebViewConfiguration *)configuration NS_DESIGNATED_INITIALIZER;
(3)載入網頁與HTML代碼的方式與UIWebView相同,代碼如下:
複製代碼 代碼如下:
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];
[self.view addSubview:webView];
1. WKWebView的代理方法
(1) WKNavigationDelegate
該代理提供的方法,可以用來追蹤載入過程(頁面開始載入、載入完成、載入失敗)、決定是否執行跳轉。
複製代碼 代碼如下:
// 頁面開始載入時調用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
// 當內容開始返回時調用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;
// 頁面載入完成之後調用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
// 頁面載入失敗時調用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;
頁面跳轉的代理方法有三種,分為(收到跳轉與決定是否跳轉兩種)
複製代碼 代碼如下:
// 接收到伺服器跳轉請求之後調用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;
// 在收到響應後,決定是否跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
// 在發送請求之前,決定是否跳轉
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
(2)WKUIDelegate
複製代碼 代碼如下:
// 建立一個新的WebView
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;
剩下三個代理方法全都是與介面彈出提示框相關的,針對於web介面的三種提示框(警告框、確認框、輸入框)分別對應三種代理方法。下面只舉了警告框的例子。
複製代碼 代碼如下:
/**
* web介面中有彈出警告框時調用
*
* @param webView 實現該代理的webview
* @param message 警告框中的內容
* @param frame 主視窗
* @param completionHandler 警告框消失調用
*/
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(void (^)())completionHandler;
(3)WKScriptMessageHandler
這個協議中包含一個必須實現的方法,這個方法是提高App與web端互動的關鍵,它可以直接將接收到的JS指令碼轉為OC或Swift對象。(當然,在UIWebView也可以通過“曲線救國”的方式與web進行互動,著名的Cordova架構就是這種機制)
複製代碼 代碼如下:
// 從web介面中接收到一個指令碼時調用
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;
2.修改Info.plist
注意從iOS9開始,凡是涉及到網路操作的,都要在Info.plist中加入:
3.載入網頁
先要在ViewController 匯入WebKit:
複製代碼 代碼如下:
import WebKit
然後:
複製代碼 代碼如下:
var webview = WKWebView()
override func viewDidLoad() {
super.viewDidLoad()
//建立wkwebview
let webview = WKWebView(frame: CGRectMake(0, 0, self.view.frame.width, self.view.frame.height))
//建立網址
let url = NSURL(string: "http://www.jianshu.com/users/040395b7230c/latest_articles")
//建立請求
let request = NSURLRequest(URL: url!)
//載入請求
webview.loadRequest(request)
//添加wkwebview
self.view.addSubview(webview)
}
運行效果如圖:
4.擷取網頁標題
為了顯示標題,首先給ViewController嵌入一個NavigationController。有了導覽列後,我們要調整一下webview的y軸位置,防止導覽列遮住網頁上面部分,在viewDidLoad()裡寫上:
複製代碼 代碼如下:
//擷取導覽列高度
let navHeight = self.navigationController?.navigationBar.frame.height
//擷取狀態列高度
let statusHeight = UIApplication.sharedApplication().statusBarFrame.height
webview = WKWebView(frame: CGRectMake(0, statusHeight+navHeight!,self.view.frame.width, self.view.frame.height))
其次,這裡要用到WKNavigationDelegate,所以在viewDidLoad()裡加上
複製代碼 代碼如下:
self.webview.navigationDelegate = self
注意網頁標題要在網頁載入完成後才能擷取,否則為空白,於是我們用到'處理網頁載入完成'這個方法:
複製代碼 代碼如下:
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
self.navigationItem.title = self.webview.title
}
運行效果如圖:
5.前進和後退
首先我們要在navgationBar上添加前進和後退按鈕:
複製代碼 代碼如下:
var btnBack = UIBarButtonItem()
var btnForward = UIBarButtonItem()
func setNavBar() {
btnBack = UIBarButtonItem(title: "後退", style: UIBarButtonItemStyle.Plain, target: self, action: "toBack")
btnForward = UIBarButtonItem(title: "前進", style: UIBarButtonItemStyle.Plain, target: self, action: "toForward")
self.navigationItem.leftBarButtonItem = btnBack
self.navigationItem.rightBarButtonItem = btnForward
}
然後我們用到了goBack()和goForward()方法,在前進或後退之前我們要判斷一下網頁是否能夠前進或後退:
複製代碼 代碼如下:
func toBack() {
if self.webview.canGoBack {
self.webview.goBack()
}
}
func toForward() {
if self.webview.canGoForward {
self.webview.goForward()
}
}
最後在viewDidLoad()裡加上調用setNavBar()方法:
複製代碼 代碼如下:
setNavBar()
運行效果如圖:
6.修改網頁配置
現在,一個看似很簡單的瀏覽器完成了,但如果我們把網址換成:
http://csol2.tiancity.com/homepage/article/Class_1166_Time_1.html
即在viewDidLoad()裡修改:
複製代碼 代碼如下:
let url = NSURL(string: "http://csol2.tiancity.com/homepage/article/Class_1166_Time_1.html")
我們會發現網頁上列表裡的文字,包括頂欄上的文字點擊了沒反應,問題出在哪裡呢?這是因為系統阻止了不安全的串連。怎麼解決呢?我們就要用到WKUIDelegate中的createWebViewWithConfiguration()這個方法讓其允許導航,首先我們要設定自身代理,在viewDidLoad()裡加上:
複製代碼 代碼如下:
self.webview.UIDelegate = self
其次:
複製代碼 代碼如下:
func webView(webView: WKWebView, createWebViewWithConfiguration configuration: WKWebViewConfiguration, forNavigationAction navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
//如果目標主視圖不為空白,則允許導航
if !(navigationAction.targetFrame?.mainFrame != nil) {
self.webview.loadRequest(navigationAction.request)
}
return nil
}
運行一下,發現點擊跳轉了!
7.處理js的提示框
現在把網址修改為
http://evt.tiancity.com/csol2/1565/home/index.php
即在viewDidLoad()裡修改:
複製代碼 代碼如下:
let url = NSURL(string: "http://evt.tiancity.com/csol2/1565/home/index.php")
往下拉,點擊'立即領取',本應該出現提示框,卻發現什麼也沒發生。為此,我們要處理一下js的提示框事件。還記得一開始提到的那個方法吧,如下:
複製代碼 代碼如下:
func webView(webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: () -> Void) {
let alert = UIAlertController(title: nil, message: message, preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "Ok", style: .Default, handler: { (_) -> Void in
completionHandler()
}))
self.presentViewController(alert, animated: true, completion: nil)
}
這裡要建立一個警告框來顯示,現在再運行一下看看?!
8.添加進度條
我們知道UIWebView是無法擷取網頁載入的進度的,於是也就無法建立進度條了,當然我們可以以某種演算法類比網頁載入,自己設定進度條的值。而WKWebView卻提供了擷取網頁載入進度的方法,支援KVO,也就是estimatedProgress。另外還有loading是否正在載入和title頁面標題。
我們得建立一個進度條:
複製代碼 代碼如下:
var progBar = UIProgressView()
//以下代碼添加到viewDidLoad()
progBar = UIProgressView(frame: CGRectMake(0, 0, self.view.frame.width, 30))
progBar.progress = 0.0
progBar.tintColor = UIColor.redColor()
self.webview.addSubview(progBar)
然後給網頁添加監聽進度,同樣在viewDidLoad()裡:
複製代碼 代碼如下:
self.webview.addObserver(self, forKeyPath: "estimatedProgress", options: NSKeyValueObservingOptions.New, context: nil)
再處理KVO:
複製代碼 代碼如下:
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if keyPath == "estimatedProgress" {
self.progBar.alpha = 1.0
progBar.setProgress(Float(webview.estimatedProgress), animated: true)
//進度條的值最大為1.0
if(self.webview.estimatedProgress >= 1.0) {
UIView.animateWithDuration(0.3, delay: 0.1, options: UIViewAnimationOptions.CurveEaseInOut, animations: { () -> Void in
self.progBar.alpha = 0.0
}, completion: { (finished:Bool) -> Void in
self.progBar.progress = 0
})
}
}
}
這裡設定進度條的值很重要,因為我們發現,其實進度條的值總比網頁載入的實際值慢一些,兩者並不同步。如果你不添加動畫使進度條載入完成後消失,你會發現進度條還沒到最右邊中途就不見了。所以我們要用個動畫來實現。此外,如果把self.progBar.progress = 0這句語句,即清零的功能放到別的方法中去,比如說放到開始導航的時候來清零,你會發現進度條的動畫有問題,會來迴轉。總之,怎麼處理進度條的動畫很講究,我試了好多次發現這個方法相對來說穩定一些。所以我建議大家可以換個進度條的樣式,即不依賴於值的顯示,如可以轉圈圈等等。現在有好多第三方庫可以使用,大家可以上cocoapods去尋找。
還有一點別忘了,對於KVO模式,有add一定要remove,否則會崩潰。我們可以在視圖消失的時候添加remove:
複製代碼 代碼如下:
override func viewWillDisappear(animated: Bool) {
webview.removeObserver(self, forKeyPath: "estimatedProgress")
}
大家可以換些網址試試!
9.最終效果圖
10.總結
WKWebView的簡單使用就介紹到這裡了!大家有興趣可以為其添加更多功能!如果喜歡本文的話別忘了點擊喜歡哦!
後記
既然說WKWebView相比UIWebView消耗的記憶體更少,那麼我們就來實際對比一下,我們讓它們載入同一個網站,結果如圖
(左為UIWebView,右為WKWebView):