iOS UIWebView 與 WKWebView

RPJKimberly 7年前發布 | 9K 次閱讀 UIWebView iOS開發 移動開發

一、 概述

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

     

     

 本文由用戶 RPJKimberly 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!