iOS UIWebView 與 WKWebView
一、 概述
UIWebView自iOS2就有,WKWebView從iOS8才有,毫無疑問WKWebView將逐步取代笨重的UIWebView。WKWebView只能用代碼創建,而且自身就支持了右滑返回手勢allowsBackForwardNavigationGestures和加載進度estimatedProgress等一些UIWebView不具備卻非常好用的屬性。通過簡單的測試即可發現UIWebView占用過多內存,且內存峰值更是夸張。WKWebView網頁加載速度也有提升,但是并不像內存那樣提升那么多。下面列舉一些其它的優勢:
- 更多的支持HTML5的特性
- 官方宣稱的高達60fps的滾動刷新率以及內置手勢
- Safari相同的JavaScript引擎
- 將UIWebViewDelegate與UIWebView拆分成了14類與3個協議( 官方文檔說明 )
- 另外用的比較多的,增加加載進度屬性:estimatedProgress
二、UIWebView的用法
1、 加載網頁或本地文件
// 網頁url
NSURL *url = [NSURLURLWithString:@"https://www.baidu.com"];
// 網絡請求
NSURLRequest *request =[NSURLRequestrequestWithURL:url];
// 加載網頁
[self.webviewloadRequest:request];
注意,如果上述的:
// 網頁url
NSURL *url = [NSURLURLWithString:@"https://www.baidu.com"];
改為:
// 網頁url
NSURL *url = [NSURLURLWithString:@"http://www.baidu.com"];
會無法加載網頁并有如下提示:
2017-02-07 15:29:46.768 WebViewTest[12469:1020441] AppTransportSecurityhasblocked a cleartextHTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
原因為ATS禁止了HTTP的明文傳輸,因為它不安全。可以修改Info.plist文件,讓它臨時允許明文傳輸。
解決辦法:
在Info.plist文件中添加”App Transport SecuritySettings”,Type為”Dictionary”,再添加一個item為”Allow Arbitray Loads”,Type 為”Boolean”,“Value”為“YES”即可。
2、 網頁導航刷新有關函數
// 刷新
- (void)reload;
// 停止加載
- (void)stopLoading;
// 后退函數
- (void)goBack;
// 前進函數
- (void)goForward;
// 是否可以后退
@property (nonatomic, readonly, getter=canGoBack) BOOL canGoBack;
// 是否可以向前
@property (nonatomic, readonly, getter=canGoForward) BOOL canGoForward;
// 是否正在加載
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
</code></pre>
3、 相關代理協議
#pragma mark - UIWebViewDelegate
// 是否允許加載網頁
- (BOOL)webView:(UIWebView )webViewshouldStartLoadWithRequest:(NSURLRequest )requestnavigationType:(UIWebViewNavigationType)navigationType {
NSLog(@"允許加載網頁");
return YES;
}
// 開始加載網頁時調用
- (void)webViewDidStartLoad:(UIWebView *)webView {
NSLog(@"開始加載網頁");
}
// 網頁加載完成時調用
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSLog(@"網頁加載完成");
}
// 網頁加載錯誤時調用
- (void)webView:(UIWebView )webViewdidFailLoadWithError:(NSError )error {
NSLog(@"網頁加載錯誤時調用");
}
</code></pre>
4、 與JS交互
(1) OC調用JS
OC調用JS主要通過下面方法:
- (nullableNSString )stringByEvaluatingJavaScriptFromString:(NSString )script;
我們只需要傳入要執行的JS代碼塊即可,如果有返回值,可以接收NSString類型返回值。
例如,我們獲取網頁Title并賦值給導航控制器Title:
/**
"調用JS"按鈕點擊事件
*/
-(void)rightAction{
self.navigationItem.title = [self.webViewstringByEvaluatingJavaScriptFromString:@"document.title"];
}
運行結果:

點擊“調用JS”按鈕后:

(2) JS調用OC
JS是不能執行OC代碼的,但是可以變相的執行,JS可以將要執行的操作封裝到網絡請求里面,然后OC攔截這個請求,獲取URL里面的字符串解析即可,這里用到代理協議的如下方法:
- (BOOL)webView:(UIWebView *)webViewshouldStartLoadWithRequest:(NSURLRequest *)requestnavigationType:(UIWebViewNavigationType)navigationType
例如:
- (BOOL)webView:(UIWebView *)webViewshouldStartLoadWithRequest:(NSURLRequest *)requestnavigationType:(UIWebViewNavigationType)navigationType
{
// 獲取請求路徑
NSString *url = request.URL.absoluteString;
// 定義的協議
NSString *scheme = @"ios://";
if ([urlhasPrefix:scheme]) {
// 獲得協議后面的路徑
NSString *path = [urlsubstringFromIndex:scheme.length];
// 利用?切割路徑 分割方法與參數
NSArray *subpaths = [pathcomponentsSeparatedByString:@"?"];
// 方法名 methodName == sendMessage:number2:
NSString *methodName = [subpathsfirstObject];
// 參數 如:200&300
NSArray *params = nil;
if (subpaths.count == 2) {
params = [[subpathslastObject] componentsSeparatedByString:@"&"];
}
// 調用本地函數
[self performSelector:NSSelectorFromString(methodName) withObjects:params];
return NO;
}
NSLog(@"想加載其他請求,不是想調用OC的方法");
return YES;
}
三、 WKWebView的用法
WKWebView 和 UIWebView 的基本使用方法相類似,但是需要導入頭文件 #import <WebKit/WebKit.h>。
1、 加載網頁
加載網頁方法與UIWebView相同:
// 網頁url
NSURL *url = [NSURLURLWithString:@"https://www.baidu.com"];
// 網絡請求
NSURLRequest *request =[NSURLRequestrequestWithURL:url];
// 加載網頁
[self.webviewloadRequest:request];
2、 加載文件
// 創建url(可以隨便從桌面拉張圖片)
NSURL *url = [NSURLfileURLWithPath:@"/Users/ios/Desktop/圖片/xxx.jpg"];
// 加載文件
[webViewloadFileURL:urlallowingReadAccessToURL:url];
其他幾個加載方法:
// 其它三個加載函數
- (WKNavigation )loadRequest:(NSURLRequest )request;
- (WKNavigation )loadHTMLString:(NSString )string baseURL:(nullableNSURL *)baseURL;
- (WKNavigation )loadData:(NSData )dataMIMEType:(NSString )MIMETypecharacterEncodingName:(NSString )characterEncodingNamebaseURL:(NSURL *)baseURL;
</code></pre>
3、 網頁導航刷新有關函數
@property (nonatomic, readonly) BOOL canGoBack;
@property (nonatomic, readonly) BOOL canGoForward;
- (WKNavigation *)goBack;
- (WKNavigation *)goForward;
- (WKNavigation *)reload;
- (WKNavigation *)reloadFromOrigin; // 增加的函數
- (WKNavigation )goToBackForwardListItem:(WKBackForwardListItem )item; // 增加的函數
- (void)stopLoading;
</code></pre>
- reloadFromOrigin會比較網絡數據是否有變化,沒有變化則使用緩存,否則從新請求。
- goToBackForwardListItem:比向前向后更強大,可以跳轉到某個指定歷史頁面
4、 常用屬性
- allowsBackForwardNavigationGestures:BOOL類型,是否允許左右劃手勢導航,默認不允許
- estimatedProgress:加載進度,取值范圍0~1
- title:頁面title
- scrollView.scrollEnabled:是否允許上下滾動,默認允許
- backForwardList:WKBackForwardList類型,訪問歷史列表,可以通過前進后退按鈕訪問,或者通過goToBackForwardListItem函數跳到指定頁面
5、 相關代理協議
幾個常用代理協議:
(1) WKNavigationDelegate
最常用,和UIWebViewDelegate功能類似,追蹤加載過程,有是否允許加載、開始加載、加載完成、加載失敗。下面會對方法做簡單的說明,并用數字標出調用的先后次序:1-2-3-4-5
三個是否允許加載方法:
// 接收到服務器跳轉請求之后調用 (服務器端redirect),不一定調用
- (void)webView:(WKWebView )webViewdidReceiveServerRedirectForProvisionalNavigation:(WKNavigation )navigation;
// 3 在收到服務器的響應頭,根據response相關信息,決定是否跳轉。decisionHandler必須調用,來決定是否跳轉,參數WKNavigationActionPolicyCancel取消跳轉,WKNavigationActionPolicyAllow允許跳轉
- (void)webView:(WKWebView )webViewdecidePolicyForNavigationResponse:(WKNavigationResponse )navigationResponsedecisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
// 1 在發送請求之前,決定是否跳轉
- (void)webView:(WKWebView )webViewdecidePolicyForNavigationAction:(WKNavigationAction )navigationActiondecisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
</code></pre>
追蹤加載過程方法:
// 2 頁面開始加載
- (void)webView:(WKWebView )webViewdidStartProvisionalNavigation:(WKNavigation )navigation;
// 4 開始獲取到網頁內容時返回
- (void)webView:(WKWebView )webViewdidCommitNavigation:(WKNavigation )navigation;
// 5 頁面加載完成之后調用
- (void)webView:(WKWebView )webViewdidFinishNavigation:(WKNavigation )navigation;
// 頁面加載失敗時調用
- (void)webView:(WKWebView )webViewdidFailProvisionalNavigation:(WKNavigation )navigation;
</code></pre>
(2) WKUIDelegate
UI界面相關,原生控件支持,三種提示框:輸入、確認、警告。首先將web提示框攔截然后再做處理。
// 創建一個新的WebView
- (WKWebView )webView:(WKWebView )webViewcreateWebViewWithConfiguration:(WKWebViewConfiguration )configurationforNavigationAction:(WKNavigationAction )navigationActionwindowFeatures:(WKWindowFeatures *)windowFeatures;
// 輸入框
- (void)webView:(WKWebView )webViewrunJavaScriptTextInputPanelWithPrompt:(NSString )promptdefaultText:(nullableNSString )defaultTextinitiatedByFrame:(WKFrameInfo )framecompletionHandler:(void (^)(NSString * __nullableresult))completionHandler;
// 確認框
- (void)webView:(WKWebView )webViewrunJavaScriptConfirmPanelWithMessage:(NSString )messageinitiatedByFrame:(WKFrameInfo *)framecompletionHandler:(void (^)(BOOL result))completionHandler;
// 警告框
- (void)webView:(WKWebView )webViewrunJavaScriptAlertPanelWithMessage:(NSString )messageinitiatedByFrame:(WKFrameInfo *)framecompletionHandler:(void (^)(void))completionHandler;
</code></pre>
6、 與JS交互
(1) WKWebView加載JS
//JS文件路徑
NSString *jsPath = [[NSBundlemainBundle] pathForResource:@"demo" ofType:@"js"];
//讀取JS文件內容
NSString *jsContent = [NSStringstringWithContentsOfFile:jsPathencoding:NSUTF8StringEncodingerror:nil];
//創建用戶腳本對象,
//WKUserScriptInjectionTimeAtDocumentStart :HTML文檔創建后,完成加載前注入,類似于<head>中
//WKUserScriptInjectionTimeAtDocumentEnd :HTML文件完成加載后注入,類似于<body>中
WKUserScript *script = [[WKUserScriptalloc] initWithSource:jsContentinjectionTime:WKUserScriptInjectionTimeAtDocumentStartforMainFrameOnly:YES];
//添加用戶腳本
[webView.configuration.userContentControlleraddUserScript:script];
(2) WKWebView執行JS方法
//執行JS方法
[webViewevaluateJavaScript:@"test()" completionHandler:^(id_Nullableresult, NSError * _Nullableerror) {
//result為執行js方法的返回值
if(error){
NSLog(@"Success");
}else{
NSLog(@"Fail");
}
}];
來自:http://www.imlifengfeng.com/blog/?p=528