美文网首页
WKWebView替换WebView体会总结

WKWebView替换WebView体会总结

作者: Q14 | 来源:发表于2017-11-20 17:55 被阅读138次

    一 先来看下UIWebView 基本用法 以及与JS交互过程

    1. 举例:简单的使用
    //1.创建webview,并设置大小
    _webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
     //2.创建请求
    NSURL *url = [NSURL URLWithString:self.urlString];
    NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30];
    //3.加载网页 将webView添加到界面
    [_webView loadRequest:urlRequest];
    [self.view addSubview:_webView]; 
    
    1. 一些实用函数
    - (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;
    
    1. 网页导航刷新有关函数
    // 刷新
    - (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;
    
    1. 代理协议使用:UIWebViewDelegate
    #pragma mark - UIWebViewDelegate
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
        // 拦截scheme为aaa时,是javascript要调用native代码
        if ([[request.URL scheme] isEqualToString:@"aaa"]) {
            // Host
            NSString *host = [[request.URL host] trimBothEnd];
            // 取得参数
            NSDictionary *parameters = [request.URL.absoluteString urlQueryToDictionary];
            [self handleLinkTapWithUrl:request.URL.absoluteString withHost:host withParams:parameters];
        }
        return YES;
    }
    
    - (void)handleLinkTapWithUrl:(NSString *)url withHost:(NSString *)host withParams:(NSDictionary *)param{
        if(host && [[self getHostDictionary] objectForKey:host]){
            [self pushScheme:url];
        }
    }
    
    - (void)webViewDidFinishLoad:(UIWebView*)webView {
        
        // 在最后执行一次,以保证标题正确设置,loading被正确隐藏
        self.title = [_webView stringByEvaluatingJavaScriptFromString:@"document.title"];
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        [self hideLoading];
        [self registerJSContextFunction];
    }
    
    - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
    {
        [self hideLoading];
        if ([error code] != NSURLErrorCancelled){
            [self showWarning:@"加载失败,请重试"];
        }
    }
    
    1. 与js交互
    1 在viewDidLoad 中 初始化 给JS注册方法
     // 初始化以做后来交互使用
        _jsContext = [_webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
        //在js自己刷新页面,不通过本地刷新的时候,需要重新绑定clint,写成成员变量,避免多次实例化。
        _client = [ClientH5Object new];
        _client.delegate = self;
        
        // 给JS注册方法
        [self registerJSContextFunction];
    2 注册方法
    #pragma mark - JSContext
    - (void)registerJSContextFunction {
        
        __weak __typeof(self)weakSelf = self;
        _jsContext[@"jsObjLoadDomFinished"] = ^() {
            dispatch_async(dispatch_get_main_queue(), ^{
                [weakSelf loadDomFinished];
            });
            
        };
        
        _jsContext[@"jsObjPageDataLoaded"] = ^() {
            dispatch_async(dispatch_get_main_queue(), ^{
                [weakSelf globalObjectLoaded];
            });
            
        };
        
        // 使用这种方式可以避免循环引用。
        // 注意:不能把self赋给_jsContext,即使是weakSelf也不行
        _jsContext[@"client"] = _Client;
    
    
        for (NSString *key in _jsCallers) {
            _jsContext[@"client"][key] = _jsCallers[key];
        }
    }
    
    - (void)addJSCall:(NSString *)jsFuncName implemention:(id)block {
        _jsCallers[jsFuncName] = block;
    }
    
    /**
     *  @brief  js调用该方法以hideLoading
     */
    - (void)loadDomFinished{
        
        [self hideLoading];
        
        // 因为此时_jsGlobalObject还不能从H5中获取,所以只先设置一个title,与数据相关的分享功能先不展示
        self.title = [_webView stringByEvaluatingJavaScriptFromString:@"document.title"];
    }
    
    
    - (void)globalObjectLoaded{
        
        // 从H5中取得全局变量
        @try {
            _jsGlobalObject = [[self.jsContext evaluateScript:@"window.GLOBAL.pagedata"] toDictionary];
        } @catch (NSException *exception) {                                                                                   
        }
        if (_jsGlobalObject == nil) {
            return;
        }
    
        //分享数据源
        _shareObject = [[WMShareObject alloc]initWithDictionary:_jsGlobalObject[@"share_data"] error:nil];
    
        //同时不为空的时候才显示微信快照和朋友圈快照
        _isShowScreenshot = [_shareObject.wechatScreenshot.content isNonEmpty] && [_shareObject.wechatScreenshot.content isNonEmpty];
        if (![_jsGlobalObject[@"hide_share"] boolValue] && (_shareObject != nil)) {
            [self setNavigateTitle:[_webView stringByEvaluatingJavaScriptFromString:@"document.title"] rightButtonOption:OCBarButtonImageTypeShare];
        }
    }
    

    二 WKWebView使用说明

    1 简单使用

        与UIWebview一样,仅需三步:记住导入
        // 1.创建webview,并设置大小
        WKWebView *webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
        // 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(已更新),另外增加了函数reloadFromOrigin和goToBackForwardListItem。
    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体会总结

          本文链接:https://www.haomeiwen.com/subject/yyzvvxtx.html