WKWebView的使用与JS交互详细解读
前言:
WKWebView 这是在iOS8.0之后增加的一个比UIWebView更加完善和强大的控件!看网上关于它的博客也是有许多的了,从各个方面总结一下这个WKWebView看网上说它主要是为了和JS做好交互产生的,我们也会相应的尝试一下。就先从它基本的说起!
一:和UIWebView相比它的不同处
1:和JS更好的做交互,也支持H5的一些新特性
2:加载进度条(下面会演示)
3:性能高,加载变得更快更可靠
二:从加载一张网页开始
1:使用这个WKWebView是要#import <WebKit/WebKit.h>
2:遵守协议,WKNavigationDelegate,WKUIDelegate,WKScriptMessageHandler(最后这个协议留神一下就知道视为JS准备的)
3:加载百度试一下
1 2 3 | WKWebView * webviwe = [[WKWebView alloc]initWithFrame: self .view.bounds]; [webviwe loadRequest:[ NSURLRequest requestWithURL:[ NSURL URLWithString:@ "https://www.baidu.com" ]]]; [ self .view addSubview:webviwe]; |
三:说说加载进度条
这个是利用KVO模式写的,WKWebView有一个 estimatedProgress 属性,利用它来监听加载的进度,下面的进度打印出来了,但具体的进度条就没有写出来,你们可以自己写一个 UIProgressView 放在导航栏的下面。
1 2 | // estimatedProgress WKWebView 这个属性添加观察者 [webviwe addObserver: self forKeyPath:@ "estimatedProgress" options: NSKeyValueObservingOptionNew context: nil ]; |
1 2 3 4 5 6 7 8 | -( void )observeValueForKeyPath:( NSString *)keyPath ofObject:( id )object change:( NSDictionary < NSString *, id > *)change context:( void *)context { if (object == webviwe && [keyPath isEqualToString:@ "estimatedProgress" ] ) { // 这里就不写进度条了,把加载的进度打印出来,进度条可以自己加上去! CGFloat newProgress = [[change objectForKey: NSKeyValueChangeNewKey ] floatValue]; NSLog (@ "%f" ,newProgress); } } |
看看打印的进度信息:
2016-08-11 14:44:17.237 RaectiveCocoaTest[21054:252565] 页面开始加载
2016-08-11 14:44:17.724 RaectiveCocoaTest[21054:252565] 0.300000
2016-08-11 14:44:17.726 RaectiveCocoaTest[21054:252565] 内容正在加载当中
2016-08-11 14:44:18.000 RaectiveCocoaTest[21054:252565] 0.719984
2016-08-11 14:44:18.196 RaectiveCocoaTest[21054:252565] 1.000000
2016-08-11 14:44:18.196 RaectiveCocoaTest[21054:252565] 页面加载完成
四:详细的方法使用说明以及注释
详解 WKNavigationDelegate 代理方法,我们把它的代理方法使用代码以及注意点全都写出来,注意看下面的注释!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | #pragma mark - WKNavigationDelegate // 页面加载开始 Provisional临时的 -( void )webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { NSLog (@ "页面开始加载" ); } // 加载内容 -( void )webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation { NSLog (@ "内容正在加载当中" ); } // 页面加载完成 -( void )webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { NSLog (@ "页面加载完成" ); } // 页面加载失败 -( void )webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:( NSError *)error { NSLog (@ "页面加载失败" ); } // 接收到服务器重新配置请求之后再执行 -( void )webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation { } // API是根据WebView对于即将跳转的HTTP请求头信息和相关信息来决定是否跳转 -( void )webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:( void (^)(WKNavigationActionPolicy))decisionHandler { NSURLRequest * request = navigationAction.request; NSLog (@ "%@" ,request.URL.absoluteString); // 判断请求头是否是 https://www.baidu.com 如果是就不在请求加载跳转 WKNavigationActionPolicy actionPolicy = WKNavigationActionPolicyAllow; if ([request.URL.absoluteString hasPrefix:@ "https://www.baidu.com" ]) { actionPolicy = WKNavigationActionPolicyCancel; } // 必须这样执行,不然会崩 decisionHandler(actionPolicy); } /** * 要是允许跳转,看下面的打印内容,注意加载的顺序!和下面的方法进行比较,区分它们的不同之处 2016-08-11 13:55:12.628 RaectiveCocoaTest[18155:211964] https://www.baidu.com/ 2016-08-11 13:55:12.629 RaectiveCocoaTest[18155:211964] 页面开始加载 2016-08-11 13:55:13.725 RaectiveCocoaTest[18155:211964] 内容正在加载当中 2016-08-11 13:55:14.681 RaectiveCocoaTest[18155:211964] 页面加载完成 * */ // API是根据客户端受到的服务器响应头以及response相关信息来决定是否可以跳转 -( void )webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:( void (^)(WKNavigationResponsePolicy))decisionHandler { NSLog (@ "%@" ,navigationResponse.response); /** * 判断响应的数据里面的URL是https://www.baidu.com/开头的,要是就不让它加载跳转 */ WKNavigationResponsePolicy responsePolicy = WKNavigationResponsePolicyAllow; if ([navigationResponse.response.URL.absoluteString hasPrefix:@ "https://www.baidu.com/" ]) { responsePolicy = WKNavigationResponsePolicyCancel; } decisionHandler(responsePolicy); } /** * 响应返回的的URL包含了https://www.baidu.com/,所以页面是不能被加载的,要是能加载就有下面的打印信息,注意和上面方法的区分对比! 2016-08-11 13:53:38.392 RaectiveCocoaTest[17961:209778] 页面开始加载 2016-08-11 13:53:38.675 RaectiveCocoaTest[17961:209778] https://www.baidu.com/ 2016-08-11 13:53:38.678 RaectiveCocoaTest[17961:209778] 内容正在加载当中 2016-08-11 13:53:38.936 RaectiveCocoaTest[17961:209778] 页面加载完成 */ |
五:说说WKUIDelegate和JS的简单交互
先看看 WKUIDelegate里面的代理方法都是用来做什么的,我们一个一个的解释这几个代理方法;
1 2 3 4 5 6 7 8 9 10 11 | // 创建方法,这个就不在多说了,重点放在下面几个 -(nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures { return nil ; } // ios 9 之后才有的方法 -( void )webViewDidClose:(WKWebView *)webView { } |
下面这三个方法根据方法前面的字面意思就能区分记住!
runJavaScriptAlert 方法注意点
1.在JS端调用alert函数时,会触发此代理方法。
2.JS端调用alert时所传的数据可以通过message,打印message信息读取出JS端给你的信息。
3.在原生得到结果后,需要回调给JS,通过completionHandler 回调给JS
4.completionHandler 回调的参数和返回值都是空
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /** 下面这三个方法根据前面的字面意思就能区分记住! */ // runJavaScriptAlert // 在JS端调用alert函数时,会触发此代理方法。 // JS端调用alert时所传的数据可以通过message,打印message信息读取出JS端给你的信息。 // 在原生得到结果后,需要回调给JS,通过completionHandler 回调给JS // completionHandler 回调的参数和返回值都是空 -( void )webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:( NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:( void (^)( void ))completionHandler { UIAlertController *alert = [UIAlertController alertControllerWithTitle:@ "alert" message:@ "JS调用alert" preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@ "确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { }]]; [ self presentViewController:alert animated: YES completion: NULL ]; NSLog (@ "%@" , message); } |
runJavaScriptTextInput 注意点
1.要求用户输入一段文字
3.在原生输入得到文本内容后,通过completionHandler回调给JS
4.大家注意这个回调的completionHandler参数是字符串
1 2 3 4 5 6 7 | // runJavaScriptTextInput // 要求用户输入一段文本 // 在原生输入得到文本内容后,通过completionHandler回调给JS 大家注意这个回调的completionHandler参数是字符串 -( void )webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:( NSString *)prompt defaultText:( NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:( void (^)( NSString * _Nullable))completionHandler { } |
runJavaScriptConfirmPane(ConfirmPane字面意思是确认框)
1.JS端调用confirm函数时,会触发此方法
2.通过message可以拿到JS端所传给我们数据
3.在iOS端显示原生alert得到YES/NO后,通过completionHandler回调给JS端
4.注意这个completionHandler回调的参数是BOOL类型的
1 2 3 4 | -( void )webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:( NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:( void (^)( BOOL ))completionHandler { } |
要有什么问题或者发现错误的地方,及时留言联系我,立马改正!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话