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
/**
- web界面中有弹出警告框时调用
- @param webView 实现该代理的webview
- @param message 警告框中的内容
- @param completionHandler 警告框消失调用
*/
- (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;
- 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
网友评论