WKWebView与H5交互

iOS 与js交互方法

下面主要来说说WKScriptMessageHandlerWKWebView已经内置了JS与OC的互调、传值等方法,在H5页面中,可以通window.webkit.messageHandlers接口与Native进行交互。您可以通过这个接口向原生代码发送消息,并且获取到原生代码处理的结果。

JS调OC

H5实现下面方法
// JS调OC,方法名就是交互的名称,数据就是JS给OC传的值  
  window.webkit.messageHandlers.<方法名>.postMessage(<data>)

坑点

  • 如果传的数据为空,需要这样写postMessage(null)
OC响应
  1. viewWillAppear添加配置
-(void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"getVerifyResult"]; 
}
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"getVerifyResult"]; 
}

注意

  • 这里的name就是JS的方法名字,方法名必须一致"
  1. 实现 WKScriptMessageHandler 协议
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    if([message.name isEqualToString:@"getVerifyResult"]){
        // 获取到验证结果后,可以进行不同的业务操作
        NSLog(@"data: %@", message.body);
    }
}

注意

  • 这里的name也是js的方法名字,方法名必须一致,通过方法名字判断响应H5对应的js方法

OC调JS

webView加载完成,传值给H5
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
       NSDictionary *dict = @{@"status":@(1)};
       NSData *data = [NSJSONSerialization dataWithJSONObject:dict options:(NSJSONWritingPrettyPrinted) error:nil];
       NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
       NSString *js = [NSString stringWithFormat:@"updateStatus(%@)", jsonStr];
      [self.webView evaluateJavaScript: js completionHandler:^(id _Nullable res, NSError * _Nullable error) {
          if (error) {
               NSLog(@"js执行失败:%@", error);             
           } else {
               NSLog(@"js执行成功");
          }
      }];
}

注意

  • H5 中的js方法也要和updateStatus(params)定义的方法名字一致

实践例子

需求
Native引入H5的一个验证服务,当H5中触发验证时,需要将验证相关参数传递给Native, 然后Native再去异步验证,并且要把验证结果回传给H5,但其中要求H5发出与Native传值交互后,需要同步拿到Native验证结果,并在在触发验证方法里面返回验证结果。

上述列子要实现的大概流程

 // 触发验证服务的回调函数(带验证信息)
 
  async function captchaVerifyCallback(verifyParam) {
    // 1. 向Native发送验证参数
    window.webkit.messageHandlers.getVerifyResult.postMessage(verifyParam)
    //2. 获取验证结果
    const isSucceed = await xxxx('http://您的业务请求地址', {
        verifyParam: verifyParam, // 验证码参数
     });
     // 3. 构造标准返回参数
    const verifyResult = {
        status: isSucceed
    };
    return verifyResult;
  }

由于我们第二步的验证结果是在Native中进行的,通常,这种交互是异步的,因为它依赖于原生代码的处理和回调。然而,window.webkit.messageHandlers本身并不直接支持Promise或者async/await机制。消息的发送通常是单向的,从JavaScript发送到原生代码,而原生代码的回复则需要通过其他机制来实现。如果要让这种交互能够使用await,需要构建一个Promise并在原生代码处理完毕后通过某种方式(通常是一个回调函数)来解决(resolve)这个Promise

以下是H5Native的具体实现

H5页面js实现
<script>
  async function verifyCallback(verifyParam) {
    // 1.向向Native发送相关验证信息
    let isSucceed = false;
    try {
        result = await sendMessageToNative('getVerifyResult', verifyParam);
        console.log('Received response from native:', result);
        isSucceed = result. isSucceed === 1;
    } catch (error) {
        console.error('error:', error);
    }
     // 2.构造标准返回参数
    const verifyResult = {
        result: isSucceed
    };
    return verifyResult;
  }
    // 在H5页面中定义一个函数,用于发送消息给原生,并返回一个Promise
    // actionName: 函数名称,这里为getVerifyResult
    function sendMessageToNative(actionName, params) {
        return new Promise((resolve, reject) => {
            // 创建一个唯一的回调函数名称
            const callbackName = 'method_' + Math.random().toString(36).substring(3);
            // 将回调函数挂载到window对象上,以便原生代码可以调用
            window[callbackName] = (response) => {
                resolve(response); // 注意可能要格式转换,根据实际情况
                // 移除挂载的回调函数,避免内存泄露
                delete window[callbackName];
            };
            // 发送消息给原生代码
            window.webkit.messageHandlers[actionName].postMessage({
                data: params,
                callback: callbackName
            });
        });
    }
</script>
Native 实现

WKWebView初始化

  // 配置页面自适应缩放
  NSString *javascript = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta)";
  WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc]init];
  // 设置UserAgent
  configuration.applicationNameForUserAgent = @"iOS_ua";
  WKUserScript *userScript = [[WKUserScript alloc]initWithSource:javascript injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
   WKUserContentController *usercontroller = [[WKUserContentController   [usercontroller addUserScript:userScript];
  configuration.userContentController = usercontroller;
  _webView = [[WKWebView alloc]initWithFrame:CGRectZero configuration:configuration];
  _webView.navigationDelegate = self;

实现WKScriptMessageHandler协议

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    YLTLog(@"didReceiveScriptMessage: %@", message.name);
    if([message.name isEqualToString:@"getVerifyResult"]){
        // 获取到验证结果后,可以进行不同的业务操作
        NSDictionary *msgDict = message.body;
        NSString *callbackName = msgDict[@"callback"];
        NSString *verifyParam = msgDict[@"data"];
        if (!callbackName || !verifyParam) {
            return;
        }
        // 此处以延时操作模拟验证过程
       dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
             NSDictionary *dict = @{@"isSucceed":@(1)};
             NSData *data = [NSJSONSerialization dataWithJSONObject:params options:(NSJSONWritingPrettyPrinted) error:nil];
             NSString *response = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
             NSString *js = [NSString stringWithFormat:@"%@(%@)", callbackName, response];
            // 执行回调,结果传递回H5页面
            [self.webView evaluateJavaScript:js completionHandler:^(id _Nullable res, NSError * _Nullable error) {
                if (error) {
                    NSLog(@" js 执行失败 error: %@", error);
               }else {// 验证码发送成功
                   NSLog(@" js 执行成功");
              }
            }];
       });
    }
}
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容