閱讀246 返回首頁    go 阿裏雲 go 技術社區[雲棲]


IOS WebView控件詳解

概述

WebView就是一個內嵌瀏覽器控件,在iOS中主要有兩種WebView:UIWebView和WKWebView,UIWebView是iOS2之後開始使用,WKWebView是在iOS8開始使用,WKWebView將逐步取代笨重的UIWebView。

相比UIWebView,WKWebView做了如下優化:

  1. WKWebView更多的支持HTML5的特性
  2. WKWebView更快,占用內存可能隻有UIWebView的1/3 ~ 1/4
  3. WKWebView高達60fps的滾動刷新率和豐富的內置手勢
  4. WKWebView具有Safari相同的JavaScript引擎
  5. 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:@"https://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:@"https://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:@"https://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控件來做兼容。

最後更新:2017-05-07 07:57:21

  上一篇:go Delphi ShareMem在dll中使用
  下一篇:go Greenplum 跨庫數據JOIN需求 - dblink的使用和弊端以及解決方案