WKWebView替换WebView体会总结

一.引言

最近应公司要求,把项目里用到的UIWebView全都用WKWebView替换掉。于是就去研究了WKWebview,加上在使用中遇到的一些问题加以总结,如有不足之处,还望指出,本人将会加以修改。

UIWebView自iOS2就有,WKWebView从iOS8才有,毫无疑问WKWebView将逐步取代笨重的UIWebView。通过简单的测试即可发现UIWebView占用过多内存,且内存峰值更是夸张。WKWebView网页加载速度也有提升,但是并不像内存那样提升那么多。下面列举一些其它的优势:

  • 更多的支持HTML5的特性
  • 官方宣称的高达60fps的滚动刷新率以及内置手势
  • Safari相同的JavaScript引擎
  • 将UIWebViewDelegate与UIWebView拆分成了14类与3个协议(官方文档说明)
  • 另外用的比较多的,增加加载进度属性:estimatedProgress

缺点:   WKWebView 不支持缓存 和   NSURLProtocol 拦截了

二、UIWebView使用说明

1 举例:简单的使用

UIWebView使用非常简单,可以分为三步,也是最简单的用法,显示网页

// 1.创建webview,并设置大小,"20"为状态栏高度

UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0,20, self.view.frame.size.width,self.view.frame.size.height -20)];

// 2.创建请求

NSMutableURLRequest *request =[NSMutableURLRequestrequestWithURL:[NSURLURLWithString:@"http://www.cnblogs.com/mddblog/"]];

// 3.加载网页

[webView loadRequest:request];

// 最后将webView添加到界面

[self.view addSubview:webView];


2 一些实用函数

  • 加载函数。

- (void)loadRequest:(NSURLRequest *)request;

- (void)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;

- (void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName baseURL:(NSURL *)baseURL;



UIWebView不仅可以加载HTML页面,还支持pdf、word、txt、各种图片等等的显示。下面以加载mac桌面上的png图片:/Users/coohua/Desktop/bigIcon.png为例

// 1.获取url

NSURL *url = [NSURLfileURLWithPath:@"/Users/coohua/Desktop/bigIcon.png"];

// 2.创建请求

NSURLRequest *request=[NSURLRequestrequestWithURL:url];

// 3.加载请求

[self.webView loadRequest:request];


  • 网页导航刷新有关函数

// 刷新

- (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;


3 代理协议使用:UIWebViewDelegate

一共有四个方法

///是否允许加载网页,也可获取js要打开的url,通过截取此url可与js交互

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {

    

    NSString *urlString = [[request URL] absoluteString];

    urlString = [urlString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

    

    NSArray *urlComps = [urlString componentsSeparatedByString:@"://"];

    NSLog(@"urlString=%@---urlComps=%@",urlString,urlComps);

    returnYES;

}

///开始加载网页

- (void)webViewDidStartLoad:(UIWebView *)webView {

    NSURLRequest *request = webView.request;

    NSLog(@"webViewDidStartLoad-url=%@--%@",[request URL],[request HTTPBody]);

}

///网页加载完成

- (void)webViewDidFinishLoad:(UIWebView *)webView {

    NSURLRequest *request = webView.request;

    NSURL *url = [request URL];

    if ([url.path isEqualToString:@"/normal.html"]) {

        NSLog(@"isEqualToString");

    }

    NSLog(@"webViewDidFinishLoad-url=%@--%@",[request URL],[request HTTPBody]);

    NSLog(@"%@",[self.webView stringByEvaluatingJavaScriptFromString:@"document.title"]);

}

///网页加载错误

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {

    NSURLRequest *request = webView.request;

    NSLog(@"didFailLoadWithError-url=%@--%@",[request URL],[request HTTPBody]);

    

}


4 与js交互

///加载完成时调用

- (void)webViewDidFinishLoad:(UIWebView *)webView

{

    [self.webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];

    

    [self.webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];

    

    [self.showView removeFromSuperview];

    NSString *jsToGetHTMLSource = @"document.getElementsByTagName('html')[0].innerHTML";

    NSString *HTMLSource = [self.webView stringByEvaluatingJavaScriptFromString:jsToGetHTMLSource];

    

    [self.activityView stopAnimating];

    

    NSRange range = [HTMLSource rangeOfString:@"Bad Gateway"];//判断字符串是否包含

    bool urlIsTrue = (range.location == NSNotFound);

    if (urlIsTrue ==true ) {

        range = [HTMLSource rangeOfString:@"Network is unreachable"];

        urlIsTrue = (range.location == NSNotFound);

    }

    if (urlIsTrue ==true ) {

        range = [HTMLSource rangeOfString:@"页面不存在"];

        urlIsTrue = (range.location == NSNotFound);

    }

    if (urlIsTrue ==true) {

        range = [HTMLSource rangeOfString:@"网页无法访问"];

        urlIsTrue = (range.location == NSNotFound);

    }

    if (urlIsTrue ==true) {

        range = [HTMLSource rangeOfString:@"Not Found"];

        urlIsTrue = (range.location == NSNotFound);

    }

    //网页可访问隐藏我们自己的返回按钮

    if (urlIsTrue==true)

    {

        self.topView.hidden =YES;

    }

    else

    {

        [webView stopLoading];

        [self addShowView];

    } 

}


三、WKWebView使用说明

1 简单使用

与UIWebview一样,仅需三步:记住导入(#import

- (void)simpleExampleTest {

    // 1.创建webview,并设置大小,"20"为状态栏高度

    WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0,20, self.view.frame.size.width,self.view.frame.size.height -20)];

    // 2.创建请求

    NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://www.cnblogs.com/mddblog/"]];

    // 3.加载网页

    [webView loadRequest:request];

    

    //最后将webView添加到界面

    [self.view addSubview:webView];

}


2 一些实用函数

  • 加载网页函数
    相比UIWebview,WKWebView也支持各种文件格式,并新增了loadFileURL函数,顾名思义加载本地文件。

///模拟器调试加载mac本地文件

- (void)loadLocalFile {

    // 1.创建webview,并设置大小,"20"为状态栏高度

    WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(0,20, self.view.frame.size.width,self.view.frame.size.height -20)];

    // 2.创建url  userName:电脑用户名

    NSURL *url = [NSURL fileURLWithPath:@"/Users/userName/Desktop/bigIcon.png"];

    // 3.加载文件

    [webView loadFileURL:url allowingReadAccessToURL:url];

    //最后将webView添加到界面

    [self.view addSubview:webView];

}


/// 其它三个加载函数

- (WKNavigation *)loadRequest:(NSURLRequest *)request;

- (WKNavigation *)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;

- (WKNavigation *)loadData:(NSData *)data MIMEType:(NSString *)MIMEType characterEncodingName:(NSString *)characterEncodingName baseURL:(NSURL *)baseURL;



  • 网页导航刷新相关函数
    和UIWebview几乎一样,不同的是有返回值,WKNavigation(已更新),另外增加了函数 reloadFromOrigingoToBackForwardListItem
  • reloadFromOrigin会比较网络数据是否有变化,没有变化则使用缓存,否则从新请求。
  • goToBackForwardListItem:比向前向后更强大,可以跳转到某个指定历史页面

@property (nonatomic,readonly) BOOL canGoBack;

@property (nonatomic,readonly) BOOL canGoForward;

- (WKNavigation *)goBack;

- (WKNavigation *)goForward;

- (WKNavigation *)reload;

- (WKNavigation *)reloadFromOrigin; //增加的函数

- (WKNavigation *)goToBackForwardListItem:(WKBackForwardListItem *)item;// 增加的函数

- (void)stopLoading;



  • 一些常用属性
    • allowsBackForwardNavigationGestures:BOOL类型,是否允许左右划手势导航,默认不允许
    • estimatedProgress:加载进度,取值范围0~1
    • title:页面title
    • .scrollView.scrollEnabled:是否允许上下滚动,默认允许
    • backForwardList:WKBackForwardList类型,访问历史列表,可以通过前进后退按钮访问,或者通过goToBackForwardListItem函数跳到指定页面


3 代理协议使用

一共有三个代理协议:

  • WKNavigationDelegate:最常用,和UIWebViewDelegate功能类似,追踪加载过程,有是否允许加载、开始加载、加载完成、加载失败。下面会对函数做简单的说明,并用数字标出调用的先后次序:1-2-3-4-5


三个是否允许跳转加载的函数:

/// 接收到服务器跳转请求之后调用 (服务器端redirect),不一定调用

- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation;

/// 3 在收到服务器的响应头,根据response相关信息,决定是否跳转。decisionHandler必须调用,来决定是否跳转,参数WKNavigationActionPolicyCancel取消跳转,WKNavigationActionPolicyAllow允许跳转

- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler;

/// 1 在发送请求之前,决定是否跳转

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;


追踪加载过程函数:

/// 2 页面开始加载

- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation;

/// 4 开始获取到网页内容时返回

- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation;

/// 5 页面加载完成之后调用

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;

/// 页面加载失败时调用

- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation;


  • WKScriptMessageHandler:必须实现的函数,是APP与js交互,提供从网页中收消息的回调方法

/// message: 收到的脚本信息.

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message;



  • WKUIDelegate:UI界面相关,原生控件支持,三种提示框:输入、确认、警告。首先将web提示框拦截然后再做处理。

/// 创建一个新的WebView

- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures;

/// 输入框

- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *__nullable result))completionHandler {

    NSLog(@"%s",__FUNCTION__);

    

    NSLog(@"%@", prompt);

    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"textinput" message:@"JS调用输入框" preferredStyle:UIAlertControllerStyleAlert];

    [alert addTextFieldWithConfigurationHandler:^(UITextField *_Nonnull textField) {

        textField.textColor = [UIColor redColor];

    }];

    

    [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

        completionHandler([[alert.textFields lastObject] text]);

    }]];

    

    [self presentViewController:alert animated:YES completion:NULL];

}

/// 确认框

- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {

    NSLog(@"%s"__FUNCTION__);

    

    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"confirm" message:@"JS调用confirm"preferredStyle:UIAlertControllerStyleAlert];

    [alert addAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

        completionHandler(YES);

    }]];

    [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {

        completionHandler(NO);

    }]];

    [self presentViewController:alert animated:YES completion:NULL];

    

    NSLog(@"%@", message);

}

/// 警告框

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {

    NSLog(@"%s"__FUNCTION__);

    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"alert"message:@"JS调用alert" preferredStyle:UIAlertControllerStyleAlert];

    [alert addAction:[UIAlertAction actionWithTitle:@"确定"style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {

        completionHandler();

    }]];

    

    [self presentViewController:alert animated:YES completion:NULL];

    NSLog(@"%@", message);

}


4 与js交互

/// 5 页面加载完成之后调用

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation;

{

    

    // 直接调用js

    [self.webViewevaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none';"completionHandler:nil];

    // 调用js参数

    [self.webViewevaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none';"completionHandler:nil];

    [self.showViewremoveFromSuperview];

    NSString *jsToGetHTMLSource =@"document.getElementsByTagName('html')[0].innerHTML";

    [self.activityViewstopAnimating];

    // 调用js获取返回值

    [self.webViewevaluateJavaScript:jsToGetHTMLSourcecompletionHandler:^(id_Nullable HTMLSource, NSError * _Nullable error) {

        NSRange range = [HTMLSourcerangeOfString:@"Bad Gateway"];//判断字符串是否包含

        bool urlIsTrue = (range.location ==NSNotFound);

        if (urlIsTrue ==true ) {

            range = [HTMLSource rangeOfString:@"Network is unreachable"];

            urlIsTrue = (range.location ==NSNotFound);

        }

        

        if (urlIsTrue ==true ) {

            range = [HTMLSource rangeOfString:@"页面不存在"];

            urlIsTrue = (range.location ==NSNotFound);

        }

        if (urlIsTrue ==true) {

            range = [HTMLSource rangeOfString:@"网页无法访问"];

            urlIsTrue = (range.location ==NSNotFound);

        }

        if (urlIsTrue ==true) {

            range = [HTMLSource rangeOfString:@"Not Found"];

            urlIsTrue = (range.location ==NSNotFound);

        }

        //网页可访问隐藏我们自己的返回按钮

        if (urlIsTrue==true)

        {

            self.topView.hidden =YES;

        }

        else

        {

            [webView stopLoading];

            [selfaddShowView];

        }

    }];

    [webView stopLoading];


}



如果想在加载的页面中继续操作
UIWebView打开一个页面之后,点击里面的内容就直接能跳转。而WKWebView一开始点里面的东西没反应,只要加了这个方法就好了。

//在发送请求之前,决定是否跳转

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {

    if (navigationAction.targetFrame ==nil) {

        [webView loadRequest:navigationAction.request];

    }

   // 没有这一句页面就不会显示

    decisionHandler(WKNavigationActionPolicyAllow); 

}






你可能感兴趣的:(WKWebView替换WebView体会总结)