ios工作

内置网页-WKWebView

2019-08-02  本文已影响0人  求长生

WKWebView有 WKNavigationDelegate 和 WKUIDelegate 及WKScriptMessageHandler。WKNavigationDelegate主要处理一些跳转、加载处理操作,WKUIDelegate主要处理JS脚本,确认框,警告框等。因此WKNavigationDelegate更加常用。

pragma mark --基本使用方法

WKWebViewConfiguration:为添加WKWebView配置信息
WKUserScript:用于进行JavaScript注入

    - (WKWebView *)webView {
    if (!_webView) {
        //创建网页配置对象
        WKWebViewConfiguration * config = [[WKWebViewConfiguration alloc]init];
        //创建设置对象
        WKPreferences * preference = [[WKPreferences alloc]init];
        preference.minimumFontSize = 0;
        preference.javaScriptEnabled = YES;
        preference.javaScriptCanOpenWindowsAutomatically = YES; // 在iOS上默认为NO,表示是否允许不经过用户交互由javaScript自动打开窗口
        config.preferences = preference;
        config.allowsInlineMediaPlayback = YES; //allowsInlineMediaPlayback这个属性,默认为NO,如果不做更改,网页中内嵌的视频就无法正常播放
        config.requiresUserActionForMediaPlayback = YES;
        config.allowsPictureInPictureMediaPlayback = YES;
        config.applicationNameForUserAgent = @"Tutor";
        
        //自定义的WKScriptMessageHandler 是为了解决内存不释放的问题
        WeakWebViewScriptMessageDelegate * weakWebViewScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc]initWithDelegate:self];
        //native与JavaScript的交互管理,注册一个name的js方法为jsocModalT 设置处理接收JS方法的对象
        WKUserContentController * wkUContentController = [[WKUserContentController alloc]init];
        [wkUContentController addScriptMessageHandler:weakWebViewScriptMessageDelegate name:@"jsocModalT"];
        [wkUContentController addScriptMessageHandler:weakWebViewScriptMessageDelegate name:@"jsocAuthT"];
        [wkUContentController addScriptMessageHandler:weakWebViewScriptMessageDelegate name:@"jsocShareT"];
        [wkUContentController addScriptMessageHandler:weakWebViewScriptMessageDelegate name:@"jsocCloseWVT"];
        config.userContentController = wkUContentController;
        
        _webView = [[WKWebView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) configuration:config];
        _webView.UIDelegate = self;
        _webView.navigationDelegate = self;
        _webView.allowsBackForwardNavigationGestures = YES; // 是否允许手势左滑返回上一级, 类似导航控制的左滑返回
    }
    return _webView;
    }

pragma mark -- WKNavigationDelegate

/*
WKNavigationDelegate主要处理一些跳转、加载处理操作,WKUIDelegate主要处理JS脚本,确认框,警告框等
*/

    // 页面开始加载时调用
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation{
    
}

// 页面加载失败时调用
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error{
    [self.progressView setProgress:0.0f animated:NO];
    //无网络时;Code=-1009 "The Internet connection appears to be offline." UserInfo={NSUnderlyingError=0x280b69080 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)"
    //网页无法打开时:omain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be found." UserInfo={NSUnderlyingError=0x281105c20 {Error Domain=kCFErrorDomainCFNetwork Code=-1003 "(null)"
    
    [self.navigationController setNavigationBarHidden:NO animated:NO];
}

// 当内容开始返回时调用
- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation{
    
}

// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{

}

//提交发生错误时调用
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error{
    [self.progressView setProgress:0.0f animated:NO];
}

// 接收到服务器跳转请求即服务重定向时之后调用
- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
    
}

// 根据WebView对于即将跳转的HTTP请求头信息和相关信息来决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    NSString * urlStr = navigationAction.request.URL.absoluteString;
    NSLog(@"发送跳转请求:%@",urlStr);
    //自己定义的协议头
    NSString *htmlHeadString = @"在收到跳转请求响应后,决定是否跳转";
    if ([urlStr hasPrefix:htmlHeadString]) {
        decisionHandler(WKNavigationActionPolicyCancel); //不允许跳转
    }else{
        decisionHandler(WKNavigationActionPolicyAllow); //允许跳转
    }
}

// 根据客户端受到的服务器响应头以及response相关信息来决定是否可以跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
    NSString * urlStr = navigationResponse.response.URL.absoluteString;
    NSLog(@"当前跳转地址:%@",urlStr);
    decisionHandler(WKNavigationResponsePolicyAllow);
}

//进程被终止时调用
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView{
    
}

pragma mark -- WKUIDelegate

/**

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler{
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
    [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler();
    }])];
    [self presentViewController:alertController animated:YES completion:nil];
}

- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"" message:message?:@"" preferredStyle:UIAlertControllerStyleAlert];
    [alertController addAction:([UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(NO);
    }])];
    [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(YES);
    }])];
    [self presentViewController:alertController animated:YES completion:nil];
}

- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler{
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:@"" preferredStyle:UIAlertControllerStyleAlert];
    [alertController addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
        textField.text = defaultText;
    }];
    [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        completionHandler(alertController.textFields[0].text?:@"");
    }])];
    [self presentViewController:alertController animated:YES completion:nil];
}

// 创建一个新的WebView,内部点击链接跳转
- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
    if (!navigationAction.targetFrame.isMainFrame) {
        [webView loadRequest:navigationAction.request];
    }
    return nil;
}

pragma mark -- OC调用JS

h5只能传一个参数,如果需要多个参数就需要用字典或者json组装。

- (void)ocToJs{
    NSString * authorization = [AccountTool person].authorization;
    NSDictionary * dic = [[NSDictionary alloc]initWithObjects:@[authorization] forKeys:@[@"authorization"]];
    NSString * str = [dic mj_JSONString]; //模型转字符串
    NSString * AuthJSString = [NSString stringWithFormat:@"jsocAuthL('%@')",str];
    [_webView evaluateJavaScript:AuthJSString completionHandler:^(id _Nullable data, NSError * _Nullable error) {
    }];
}

pragma mark -- JS调用OC

WKUserContentController:这个类主要用来做native与JavaScript的交互管理
WKScriptMessageHandler:这个协议类专门用来处理监听JavaScript方法从而调用原生OC方法,和WKUserContentController搭配使用。
addScriptMessageHandler要和removeScriptMessageHandlerForName配套出现,否则会造成内存泄漏。

1.注册JS方法:是用JS回调的方法前先要注册其方法。

       //native与JavaScript的交互管理,注册一个name的js方法为jsocModalT 设置处理接收JS方法的对象
        WKUserContentController * wkUContentController = [[WKUserContentController alloc]init];
        [wkUContentController addScriptMessageHandler:weakWebViewScriptMessageDelegate name:@"jsocModalT"];
        [wkUContentController addScriptMessageHandler:weakWebViewScriptMessageDelegate name:@"jsocAuthT"];
        [wkUContentController addScriptMessageHandler:weakWebViewScriptMessageDelegate name:@"jsocShareT"];
        [wkUContentController addScriptMessageHandler:weakWebViewScriptMessageDelegate name:@"jsocCloseWVT"];
        config.userContentController = wkUContentController;
  1. WKScriptMessageHandler协议,获取回调中的方法名及参数
//通过接收JS传出消息的name进行捕捉的回调方法
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    NSLog(@"name:%@\\\\n body:%@\\\\n frameInfo:%@\\\\n",message.name,message.body,message.frameInfo);
    //用message.body获得JS传出的参数体
    NSDictionary * parameter = message.body;
    if ([message.name isEqualToString:@"jsocModalT"]) {
        UIAlertController * alertController = [UIAlertController alertControllerWithTitle:@"标题" message:parameter[@"title"] preferredStyle:UIAlertControllerStyleAlert];
        [alertController addAction:([UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            [self ocToJsAlert:true];
        }])];
        [alertController addAction:([UIAlertAction actionWithTitle:@"NO" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            [self ocToJsAlert:false];
        }])];
        [self presentViewController:alertController animated:YES completion:nil];
    }else if ([message.name isEqualToString:@"jsocAuthT"]){
        [self ocToJsAuth];
    }else if ([message.name isEqualToString:@"jsocShareT"]){
        
    }else if ([message.name isEqualToString:@"jsocCloseWVT"]){
        [self.navigationController popViewControllerAnimated:YES];
    }
}

3.注册过的方法要Remove掉。

- (void)dealloc{
    //移除注册的js方法
    [[_webView configuration].userContentController removeScriptMessageHandlerForName:@"jsocModalT"];
    [[_webView configuration].userContentController removeScriptMessageHandlerForName:@"jsocAuthT"];
    [[_webView configuration].userContentController removeScriptMessageHandlerForName:@"jsocShareT"];
    [[_webView configuration].userContentController removeScriptMessageHandlerForName:@"jsocCloseWVT"];
    //移除观察者
    [_webView removeObserver:self
                  forKeyPath:NSStringFromSelector(@selector(estimatedProgress))];
    [_webView removeObserver:self
                  forKeyPath:NSStringFromSelector(@selector(title))];
}

pragma mark --观察title和网页加载进度条

//添加监测网页加载进度的观察者
    [self.webView addObserver:self forKeyPath:NSStringFromSelector(@selector(estimatedProgress)) options:0 context:nil];
    [self.webView addObserver:self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context:nil];

//kvo 监听进度 必须实现此方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:NSStringFromSelector(@selector(estimatedProgress))] && object == _webView) {
        NSLog(@"网页加载进度 = %f",_webView.estimatedProgress);
        self.progressView.progress = _webView.estimatedProgress;
        if (_webView.estimatedProgress > 1.0f) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                self.progressView.progress = 0;
            });
        }
    }else if([keyPath isEqualToString:@"title"] && object == _webView){
        self.navigationItem.title = _webView.title;
    }else{
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

pragma mark --加载网址和加载本地Html和刷新

//创建一个NSURLRequest 的对象
NSMutableURLRequest *Request_zsj = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:string]];
    [self.webView loadRequest:Request_zsj];

//加载本地Html
NSString *path = [[NSBundle mainBundle]pathForResource:@"JStoOC.html" ofType:nil];
    NSString *htmlString = [[NSString alloc]initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
    [_webView loadHTMLString:htmlString baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];

//刷新
[_webView reload];

//页面前进
 [_webView goForward];

 //页面后退
 [_webView goBack];
        

《文章仅做工作时笔记整理。如没帮到您,还可以看看一下网站》

https://www.cnblogs.com/oc-bowen/p/5946383.html
https://www.w3school.com.cn/index.html

上一篇下一篇

猜你喜欢

热点阅读