一、WebView
WebView就是一個內嵌瀏覽器控件,在iOS中主要有兩種WebView:UIWebView和WKWebView,UIWebView是iOS2之後開始使用,WKWebView是在iOS8開始使用,毫無疑問WKWebView將逐步取代笨重的UIWebView。
WKWebView的優點:
- WKWebView更多的支持HTML5的特性
- WKWebView更快,佔用內存可能只有UIWebView的1/3 ~ 1/4
- WKWebView高達60fps的滾動刷新率和豐富的內置手勢
- WKWebView具有Safari相同的JavaScript引擎
- WKWebView增加了加載進度屬性
儘管講了這麼多WKWebView的優點,但還有很多項目還沒有升級到iOS8,UIWebView也還有學習的必要,也可以通過對比WKWebView和UIWebView的使用,加深理解。
注意:Xcode7禁用了明碼的HTTP請求(但不限HTTPS請求),應該在info.plist裏添加下面的字段,否則無法響應HTTP請求
添加App Transport Security Settings
,並在其中設置Allow Arbitrary Loads
爲YES
二、UIWebView
1. UIWebView加載請求
- (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;
}
2. UIWebView的實用加載函數
//加載網絡請求
- (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;
下面是加載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]];
}
UIWebView
不僅可以加載HTML頁面,還支持pdf、word、txt、各種圖片等等的顯示。使用loadRequest
方法加載的URL是pdf、word、txt、各種圖片的URL路徑,就可以加載對應的文件,這裏就不演示了。
3. 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;
4. UIWebViewDelegate代理方法
一共有四個方法:
//是否允許加載網頁,也可獲取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;
5. 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代碼:
用到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"];
6. UIWebView整合功能代碼
- (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這個以後時代的主角出場了。要使用WKWebView需要導入
1. WKWebView加載請求
和UIWebView用法完全一致:
#pragma mark - 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];
}
2. WKWebView的實用加載方法
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;
loadHTMLString方法的顯示效果會有一些區別,看下圖:
我的HTML文件myPage.html如下:
<html>
<head><title>Kenshin Cui's Blog</title></head>
<body style="color:#0092FF;">
<h1 id="header">I am Kenshin Cui</h1>
<p>iOS Learn</p>
</body>
</html>
估計兩種WebView加載HTML的默認字體樣式是不一樣的,這裏只是說一下
下面是加載本地文件的實例:
/* 模擬器調試加載mac本地文件 */
- (void)loadLocalFile {
// 1.創建webview,並設置大小,"20"爲狀態欄高度
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 userName:電腦用戶名
NSURL *url = [NSURL fileURLWithPath:@"/Users/userName/Desktop/bigIcon.png"];
// 3.加載文件
[webView loadFileURL:url allowingReadAccessToURL:url];
// 最後將webView添加到界面
[self.view addSubview:webView];
}
3. WKWebView的網頁導航方法
和UIWebView相差不大,多了返回值,多了一些屬性,也多了2個方法:
* reloadFromOrigin
,緩存加載
* goToBackForwardListItem
,跳轉到指定歷史頁面
下面是網頁導航方法列表:
@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;
4. WKWebView的代理
UIWebView只有一個代理,但WKWebView有好幾個,但常用的有2個,
id<WKNavigationDelegate> 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的alert
、confirm
、prompt
方法,我們應該實現下面這幾個代理方法,然後在這裏調用iOS的彈出窗,因爲使用WKWebView
後,HTML中的alert
、confirm
、prompt
方法調用是不會再彈出窗口了
下面列出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;
WKWebView還有更多功能,比如和JavaScript互動等,但本人還不太理解,就不寫出來忽悠人了。