JS交互的方法(下)WKWebView

本文详细介绍如何使用WKWebView实现iOS与JavaScript的交互,包括配置WKWebView、设置偏好、注入JS对象、加载网页及处理各种代理方法等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前一篇文章已经介绍了JS与iOS交互,用UIWebView实现的方法。需要了解相关知识,请查看前一篇博客。

地址:JS交互的方法(上)UIWebView

这里我们来介绍另外一种基于iOS8新推出的WKWebView组件实现的方法。WKWebView实际上就是一个新的、高性能的WebView 解决方案。下面我们就来看看如何利用WKWebView实现混合开发框架。先看看实现效果:

这里写图片描述

说明:本文我们只讨论如何实现iOS与JS的交互,由于不精通HTML,所以小Demo可能会有小瑕疵,大神莫怪。

1. 配置偏好设置
  WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
  // 设置偏好设置
  config.preferences = [[WKPreferences alloc] init];
  // 默认为0
  config.preferences.minimumFontSize = 10;
  // 默认认为YES
  config.preferences.javaScriptEnabled = YES;
  // 在iOS上默认为NO,表示不能自动通过窗口打开
  config.preferences.javaScriptCanOpenWindowsAutomatically = NO;
2. 配置JS与iOS的交互内容

WKUserContentController是用于给JS注入对象的,注入对象后,JS端就可以使用。直白点说就是给JS与iOS的交互提供一个通道,以后JS与iOS交互就是通过这个AppModel值识别和传值的,传数据统一通过body传,可以是多种类型,只支持NSNumber, NSString, NSDate, NSArray,NSDictionary, and NSNull类型。

  // 通过JS与webview内容交互
  config.userContentController = [[WKUserContentController alloc] init];
  // 注入JS对象名称AppModel,当JS通过AppModel来调用时,
  // 我们可以在WKScriptMessageHandler代理中接收到
  [config.userContentController addScriptMessageHandler:self name:@"AppModel"];

下图是HTML中想iOS发送消息的代码,从这句代码我们就能看出AppModel值得作用

这里写图片描述

3. 加载网页
  //通过默认的构造器来创建对象
  self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds
                                    configuration:config];
  NSURL *path = [[NSBundle mainBundle] URLForResource:@"test" withExtension:@"html"];
  [self.webView loadRequest:[NSURLRequest requestWithURL:path]];
  [self.view addSubview:self.webView];
4. 加载网页时调用的代理方法

完成以上配置以后我们就按照程序的执行顺序解析代码,这里我们以点击提示弹窗为例进行分析,其他几个功能里也有一些需要注意的点就需要大家自己思考了。

在HTML中添加点击事件
这里写图片描述
点击事件为HTML代码,不做详述。实现点击事件,这个方法会调用iOS中的方法把body值传过去

      function callJsAlert() {
        //在JS端调用alert函数时,会触发代理方法一,括号中的内容会传到此代理方法中
        alert('这个是OC调用JS的方法,并且通过Alert()进行显示出来!');
    //在JS端调用postMessage函数时,会触发代理方法二,body的内容会传过去    
    window.webkit.messageHandlers.AppModel.postMessage({body: '在JS中调用JS中方法'});
      }

运行程序后,触发点击事件前会依次执行以下几个代理方法,我们逐一分析下

/**
 代理方法三:
 请求开始前,会先调用此代理方法,与UIWebView的
 - (BOOL)webView:(UIWebView *)webView
 shouldStartLoadWithRequest:(NSURLRequest *)request
 navigationType:(UIWebViewNavigationType)navigationType;
 方法类似,此方法在上篇博客中分析过
 */
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:
(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
  NSString *hostname = navigationAction.request.URL.host.lowercaseString;
  if (navigationAction.navigationType == WKNavigationTypeLinkActivated
      && ![hostname containsString:@".lanou.com"]) {
// 对于跨域,需要手动跳转
    [[UIApplication sharedApplication] openURL:navigationAction.request.URL];

    // 不允许web内跳转
    decisionHandler(WKNavigationActionPolicyCancel);
  } else {
    self.progressView.alpha = 1.0;
    decisionHandler(WKNavigationActionPolicyAllow);
  }

    NSLog(@"00===%s", __FUNCTION__);
}

decisionHandler(WKNavigationActionPolicyAllow)的作用是设置能否跳转,WKNavigationActionPolicyAllow是一个枚举值表示允许调转,WKNavigationActionPolicyCancel表示不允许跳转。

/**
 代理方法四
 开始导航跳转时会回调
 */
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation {
    NSLog(@"22===%s", __FUNCTION__);
}
/**
 代理方法五:
 在响应完成时,会回调此方法如果设置为不允许响应,web内容就不会传过来
 */
- (void)webView:(WKWebView *)webView
decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse
decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
  decisionHandler(WKNavigationResponsePolicyAllow);
  NSLog(@"11===%s", __FUNCTION__);
}
/**
 代理方法六:
 页面内容到达main frame时回调
 */
- (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation {
    NSLog(@"55===%s", __FUNCTION__);
}
/**
 代理方法七:
 导航完成时,会回调(也就是页面载入完成了)
 */
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
    NSLog(@"66===%s", __FUNCTION__);
}

这个代理方法执行完成,网页才完整的加载出来,还有一些代理方法是在页面加载异常时调用的,我们这里统一来看一下。

// 接收到重定向时会回调
- (void)webView:(WKWebView *)webView
didReceiveServerRedirectForProvisionalNavigation:(null_unspecified WKNavigation *)navigation {
    NSLog(@"33===%s", __FUNCTION__);
}

// 导航失败时会回调
- (void)webView:(WKWebView *)webView
didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
    NSLog(@"44===%s", __FUNCTION__);
}

    // 导航失败时会回调
- (void)webView:(WKWebView *)webView didFailNavigation:
(null_unspecified WKNavigation *)navigation withError:(NSError *)error {
  NSLog(@"77===%s", __FUNCTION__);
}

// 9.0才能使用,web内容处理中断时会触发
- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView {
    NSLog(@"99===%s", __FUNCTION__);
}

//关闭网页时调用
- (void)webViewDidClose:(WKWebView *)webView {
     NSLog(@"99===%s", __FUNCTION__);
}
5. 触发点击事件时调用的代理方法

触发点击事件,即执行如下HTML代码

//提示弹窗
alert('这个是OC调用JS的方法,并且通过Alert()进行显示出来!');
//确认弹窗
if (confirm('confirm', 'Objective-C call js to show confirm')) {
    document.getElementById('jsParamFuncSpan').innerHTML
    = 'true';
  } else {
    document.getElementById('jsParamFuncSpan').innerHTML
    = 'false';
  }
  //输入弹窗
 var response = prompt('Hello', '请输入你的名字:');
 document.getElementById('jsParamFuncSpan').innerHTML = response;

执行上述代码后,iOS会执行下面的代理方法调用这几个代理方法后,iOS会执行相应的弹窗操作。

/** 代理方法一 */
// 在JS端调用alert函数时,会触发此代理方法。
// JS端调用alert时所传的数据可以通过message拿到
// 在原生得到结果后,需要回调JS,是通过completionHandler回调
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message
initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
  NSLog(@"100===%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);
}

// JS端调用confirm函数时,会触发此方法
// 通过message可以拿到JS端所传的数据
// 在iOS端显示原生alert得到YES/NO后
// 通过completionHandler回调给JS端
- (void)webView:(WKWebView *)webView
runJavaScriptConfirmPanelWithMessage:(NSString *)message
initiatedByFrame:(WKFrameInfo *)frame
completionHandler:(void (^)(BOOL result))completionHandler {
  NSLog(@"101===%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);
}

// JS端调用prompt函数时,会触发此方法
// 要求输入一段文本
// 在原生输入得到文本内容后,通过completionHandler回调给JS
- (void)webView:(WKWebView *)webView
runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt
    defaultText:(nullable NSString *)defaultText
initiatedByFrame:(WKFrameInfo *)frame
completionHandler:(void (^)(NSString * __nullable result))completionHandler {
  NSLog(@"102===%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];
}
6. 执行跳转控制器的代理方法

HTML代码中执行如下代码会调用iOS中的代理方法

// AppModel是我们所注入的对象
window.webkit.messageHandlers.AppModel.postMessage({body: response});

执行上述代码会调用如下代理方法

/** 代理方法二 */
- (void)userContentController:(WKUserContentController *)userContentController
      didReceiveScriptMessage:(WKScriptMessage *)message {
  if ([message.name isEqualToString:@"AppModel"]) {
    // 打印所传过来的参数,只支持NSNumber, NSString, NSDate, NSArray,
    // NSDictionary, and NSNull类型
    NSLog(@"9999===%@", message.body);
          //跳转到指定控制器中
      JumpViewController *root = [[JumpViewController alloc]init];
      root.str = message.body;
      [self.navigationController pushViewController:root animated:YES];
  }
}

到这里终于实现了控制器的跳转

7. 其他

在加载网页时往往还会用KVO监听是否正在加载、当前进度等状态,这里不再赘述。

8. 详细代码请下载源码自行研究

地址:http://download.youkuaiyun.com/detail/qq_34101611/9553494

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值