IOS WebView控制元件詳解
概述
WebView就是一個內嵌瀏覽器控制元件,在iOS中主要有兩種WebView:UIWebView和WKWebView,UIWebView是iOS2之後開始使用,WKWebView是在iOS8開始使用,WKWebView將逐步取代笨重的UIWebView。
相比UIWebView,WKWebView做了如下優化:
- WKWebView更多的支援HTML5的特性
- WKWebView更快,佔用記憶體可能只有UIWebView的1/3 ~ 1/4
- WKWebView高達60fps的滾動重新整理率和豐富的內建手勢
- WKWebView具有Safari相同的JavaScript引擎
- WKWebView增加了載入進度屬性
UIWebView
UIWebView繼承與UIView,因此,其初始化方法和一般的view一樣,通過alloc和init進行初始化。其載入資料的方式有三種:
第一種:
- (void)loadRequest:(NSURLRequest *)request;
這是載入網頁最常用的一種方式,通過一個網頁URL來進行載入,這個URL可以是遠端的也可以是本地的。例如:
- (void)simpleUIWebViewTest {
// 1.建立webview,並設定大小,"20"為狀態列高度
CGFloat width = self.view.frame.size .width;
CGFloat height = self.view.frame.size.height - 20;
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 20, width, height)];
// 2.建立URL
NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
// 3.建立Request
NSURLRequest *request =[NSURLRequest requestWithURL:url];
// 4.載入網頁
[webView loadRequest:request];
// 5.最後將webView新增到介面
[self.view addSubview:webView];
self.webView = webView;
}
第二種:
- (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL;
這個方法需要將httml檔案讀取為字串,其中baseURL是我們自己設定的一個路徑,用於尋找html檔案中引用的圖片等素材。例如:
- (void)loadLocalHTMLFileToUIWebView{
// 獲取本地html檔案檔案路徑
NSString *localHTMLPageName = @"myPage";
NSString *path = [[NSBundle mainBundle] pathForResource:localHTMLPageName ofType:@"html"];
// 從html檔案中讀取html字串
NSString *htmlString = [NSString stringWithContentsOfFile:path
encoding:NSUTF8StringEncoding
error:NULL];
// 載入本地HTML字串
[self.webView loadHTMLString:htmlString baseURL:[[NSBundle mainBundle] bundleURL]];
}
第三種:
- (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName baseURL:(NSURL *)baseURL;
這個方式使用的比較少,但也更加自由,其中data是檔案資料,MIMEType是檔案型別,textEncodingName是編碼型別,baseURL是素材資源路徑。例如:
//載入網路請求
- (void)loadRequest:(NSURLRequest *)request;
/*
功能:載入本地HTML字串
string為要載入的本地HTML字串
baseURL用來確定htmlString的基準地址,相當於HTML的<base>標籤的作用,定義頁面中所有連結的預設地址
*/
- (void)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;
/* 載入二進位制資料 */
- (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType
characterEncodingName:(NSString *)characterEncodingName
baseURL:(NSURL *)baseURL;
UIWebView導航
在我們瀏覽網頁,時常會使用到的重新整理網頁、前進、後退等導航操作,UIWebView裡面也有對應的操作方法。直接程式碼講解:
#pragma mark - 判斷屬性
// 是否可以後退
@property (nonatomic, readonly, getter=canGoBack) BOOL canGoBack;
// 是否可以向前
@property (nonatomic, readonly, getter=canGoForward) BOOL canGoForward;
// 是否正在載入
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
#pragma mark - 操作方法
// 重新整理網頁
- (void)reload;
// 停止載入網頁
- (void)stopLoading;
// 後退
- (void)goBack;
// 前進
- (void)goForward;
UIWebView代理
在UIWebViewDelegate方法中,一共有4個方法需要注意:
//是否允許載入網頁,也可獲取js要開啟的url,通過擷取此url可與js互動
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType;
//開始載入網頁
- (void)webViewDidStartLoad:(UIWebView *)webView;
//網頁載入完成
- (void)webViewDidFinishLoad:(UIWebView *)webView;
//網頁載入錯誤
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;
UIWebView和JavaScript互動
UIWebView和JavaScript的互動主要涉及兩個方面:JS執行OC程式碼、OC調取JS程式碼。
JS執行OC程式碼
JS是不能執行OC程式碼的,但是可以變相的執行,JS可以將要執行的操作封裝到網路請求裡面,然後OC攔截這個請求,獲取URL裡面的字串解析即可。例如:
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType
OC調取JS程式碼
OC調取JS用到了WebView的一個方法stringByEvaluatingJavaScriptFromString。
// 實現自動定位JS程式碼, htmlLocationID為定位的位置(由JS開發人員給出),實現自動定位程式碼,應該在網頁載入完成之後再呼叫
NSString *javascriptStr = [NSString stringWithFormat:@"window.location.href = '#%@'",htmlLocationID];
// webview執行程式碼
[self.webView stringByEvaluatingJavaScriptFromString:javascriptStr];
// 獲取網頁的title
NSString *title = [self.webView stringByEvaluatingJavaScriptFromString:@"document.title"];
上述完整程式碼:
- (void)viewDidLoad
{
[super viewDidLoad];
[self initWebView];
}
- (void)initWebView{
// 1.建立webview,並設定大小,"20"為狀態列高度
CGFloat width = self.view.frame.size.width;
CGFloat height = self.view.frame.size.height - 20;
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0,20,width,height)];
// 2.建立URL
NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
// 3.建立Request
NSURLRequest *request =[NSURLRequest requestWithURL:url];
// 4.載入網頁
[webView loadRequest:request];
// 5.最後將webView新增到介面
[self.view addSubview:webView];
self.webView = webView;
webView.delegate = self;
}
#pragma mark 設定前進後退按鈕狀態
-(void)setBarButtonStatus{
if (_webView.canGoBack) {
_barButtonBack.enabled = YES;
}else{
_barButtonBack.enabled = NO;
}
if(_webView.canGoForward){
_barButtonForward.enabled = YES;
}else{
_barButtonForward.enabled = NO;
}
}
/*瀏覽器後退*/
- (void)clickGoBackBtn{
if(self.webView.canGoBack){
[self.webView goBack];
}
}
/*瀏覽器前進*/
- (void)clickGoForwardBtn{
if(self.webView.canGoForward){
[self.webView goForward];
}
}
#pragma mark - UIWebViewDelegate代理方法
#pragma mark 開始載入
//是否允許載入網頁,也可獲取js要開啟的url,通過擷取此url可與js互動
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType
{
//擷取URL,這裡可以和JS進行互動,但這裡沒有寫,因為會涉及到JS的一些知識,增加複雜性
NSString *urlString = [request.URL absoluteString];
urlString = [urlString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSArray *urlComps = [urlString componentsSeparatedByString:@"://"];
NSLog(@"urlString=%@---urlComps=%@",urlString,urlComps);
return YES;
}
//開始載入網頁
- (void)webViewDidStartLoad:(UIWebView *)webView{
//顯示網路請求載入
[UIApplication sharedApplication].networkActivityIndicatorVisible = true;
}
//網頁載入完成
- (void)webViewDidFinishLoad:(UIWebView *)webView{
//隱藏網路請求載入圖示
[UIApplication sharedApplication].networkActivityIndicatorVisible = false;
[self setBarButtonStatus];
//取得html內容
NSLog(@"%@",[self.webView stringByEvaluatingJavaScriptFromString:@"document.title"]);
}
//網頁載入錯誤
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"系統提示"
message:@"網路連線發生錯誤!"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:@"確定", nil];
[alert show];
}
WKWebView
WKWebView是iOS8中出的一個新控制元件,算是對UIWebVeiw的升級版。使用上和UIWebView用法大體一致,主要是新增和優化了一些方法。
例如,使用WKWebView載入百度首頁。
- (void)wkWebViewEasyUse
{
//1.建立WKWebView
CGFloat width = self.view.frame.size.width;
CGFloat height = self.view.frame.size.height - 20;
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0,20,width,height)];
//2.建立URL
NSURL *URL = [NSURL URLWithString:@"http://www.baidu.com"];
//3.建立Request
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
//4.載入Request
[webView loadRequest:request];
//5.新增到檢視
self.webView = webView;
[self.view addSubview:webView];
}
UIWebView有的,WKWebView都有,WKWebView多了一個載入檔案方法,而且WKWebView的這些載入方法都有返回值。
載入方法
/*載入請求*/
- (WKNavigation *)loadRequest:(NSURLRequest *)request;
/*載入本地HTML字串*/
- (WKNavigation *)loadHTMLString:(NSString *)string
baseURL:(nullable NSURL *)baseURL;
/*載入本地檔案*/
- (WKNavigation *)loadFileURL:(NSURL*)url
allowingReadAccessToURL:(NSURL*)url;
/* 載入二進位制資料 */
- (WKNavigation *)loadData:(NSData *)data
MIMEType:(NSString *)MIMEType
characterEncodingName:(NSString *)characterEncodingName
baseURL:(NSURL *)baseURL;
WKWebView網頁導航
和UIWebView相差不大,多了返回值,多了一些屬性和方法。
@property (nonatomic, readonly) BOOL canGoBack;
@property (nonatomic, readonly) BOOL canGoForward;
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
- (WKNavigation *)goBack;
- (WKNavigation *)goForward;
- (WKNavigation *)reload;
- (void)stopLoading;
/* 載入進度,取值範圍0~1 */
@property (nonatomic, readonly) double estimatedProgress;
/* 是否允許左右劃手勢導航,預設不允許 */
@property (nonatomic) BOOL allowsBackForwardNavigationGestures;
/* 訪問歷史列表 */
@property (nonatomic, readonly, strong) WKBackForwardList *backForwardList;
/* 會比較網路資料是否有變化,沒有變化則使用快取,否則從新請求 */
- (WKNavigation *)reloadFromOrigin;
/* 比向前向後更強大,可以跳轉到某個指定歷史頁面 */
- (WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item;
WKWebView代理
UIWebView只有一個代理,但WKWebView有好幾個,但常用的有2個,
id navigationDelegate和id< WKUIDelegate > UIDelegate。WKNavigationDelegate: 最常用,和UIWebViewDelegate功能類似,追蹤載入過程,有是否允許載入、開始載入、載入完成、載入失敗。WKUIDelegate:UI介面相關,原生控制元件支援,三種提示框:輸入、確認、警告。
WKNavigationDelegate常用代理:
/* 1.在傳送請求之前,決定是否跳轉 */
- (void)webView:(WKWebView *)webView
decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
/* 2.頁面開始載入 */
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;
/* 3.在收到伺服器的響應頭,根據response相關資訊,決定是否跳轉。 */
- (void)webView:(WKWebView *)webView
decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse
decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;
/* 4.開始獲取到網頁內容時返回,需要注入JS,在這裡新增 */
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;
/* 5.頁面載入完成之後呼叫 */
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;
/* error - 頁面載入失敗時呼叫 */
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;
/* 其他 - 處理伺服器重定向Redirect */
- (void)webView:(WKWebView *)webView
didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;
WKUIDelegate常用代理
/* 輸入框,頁面中有呼叫JS的 prompt 方法就會呼叫該方法 */
- (void)webView:(WKWebView *)webView
runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt
defaultText:(nullable NSString *)defaultText
initiatedByFrame:(WKFrameInfo *)frame
completionHandler:(void (^)(NSString *result))completionHandler;
/* 確認框,頁面中有呼叫JS的 confirm 方法就會呼叫該方法 */
- (void)webView:(WKWebView *)webView
runJavaScriptConfirmPanelWithMessage:(NSString *)message
initiatedByFrame:(WKFrameInfo *)frame
completionHandler:(void (^)(BOOL result))completionHandler;
/* 警告框,頁面中有呼叫JS的 alert 方法就會呼叫該方法 */
- (void)webView:(WKWebView *)webView
runJavaScriptAlertPanelWithMessage:(NSString *)message
initiatedByFrame:(WKFrameInfo *)frame
completionHandler:(void (^)(void))completionHandler;
雖然很多裝置以及升級到8.0系統,但是對於一些老的裝置,我們還是需要使用UIWebView控制元件來做相容。