关于WKWebView和JS交互同步返回数据的坑

18 篇文章 0 订阅
4 篇文章 0 订阅

后台的小伙伴要那种同步返回,可以用var直接接收返回值的形式进行处理逻辑,但是WkWebvie貌似不能用context进行JS注入。

1.先看一下UIWebView如何实现的

借助于iOS里的框架:JavaScriptCore.FrameWork来实现,

导入JavaScriptCore.FrameWork   #import <JavaScriptCore/JavaScriptCore.h>

@protocolJSObjcDelegate<JSExport>

// AndroidWebView对象调用的JavaScript方法,必须声明!!!

-(int)indexOfMap;

@end

@interfaceViewController: UIViewController<UIWebViewDelegate,JSObjcDelegate>

@property(nonatomic, strong) JSContext *context;

@property(weak, nonatomic) IBOutletUIWebView*webView;

@end
加载webview就不写了,下面实现交互
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    // 获取context对象
    self.context = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    
    //将AndroidWebView对象指向自身 js里面写window.AndroidWebView.indexOfMap() 就会调用原生里的indexOfMap方法
    self.context[@"AndroidWebView"] = self;
    self.context.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
        context.exception = exceptionValue;
        NSLog(@"异常信息:%@", exceptionValue);
    };
    
    // 获取到点击js按钮的事件
        self.context[@"clickAction0"] = ^(){
            NSLog(@"获取到点击js按钮的事件");
        };
    // oc调用js函数 并传参 js无返回值
        NSString *jsAction = @"clickAction1(555)";
        [self.context evaluateScript:jsAction];
    
    // oc调用js函数 并传参 接收js返回值
        NSString *str1 = [webView stringByEvaluatingJavaScriptFromString:@"clickAction2(666);"];
        NSLog(@"js函数给我的返回值:%@", str1);
}

/**
 待js调用
 */
- (int)indexOfMap {
    NSLog(@"我被js调用了");
    return 110;
}

JS调用:


<!DOCTYPE html>
<html>
    <head lang="en">
        <meta charset="UTF-8">
    </head>
    <body>
        <div style="margin-top: 100px">
            <h1>Objective-C和JavaScript交互</h1>
        </div>
        
        <div>
            <input type="button" value="oc掉用js弹出提示->" onclick="clickAction0(11)">
            <input type="button" value="js调用oc->" onclick="clickbtn()">
        </div>
        
        <script type="text/javascript">
            // js函数
            function clickAction0(typyId) {
                alert(typyId)
            }
            function clickAction1(typyId) {
                alert(typyId)
            }
            function clickAction2(typyId) {
                alert(typyId);
                return 'hello';
            }


            function clickbtn() {
                var tempValue = window.AndroidWebView.indexOfMap();
                alert(tempValue);
            }
            </script>
    </body>
</html>

上面的那三种调用类似WKWebview中的


-(void)sendAPPInfo{
    NSString *info = [NSString stringWithFormat:@"%@_%@",appId,appkey];
    NSString * jsStr = [NSString stringWithFormat:@"clickAction0('%@')",info];
    [self.webview evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {

    }];
 
}

JS调用

function  clickAction0(info){

这里可以使用info进行逻辑处理

}

var tempValue = window.AndroidWebView.indexOfMap();  这句就类似同步,方便js那边处理逻辑

---------------------------------------------------------------------------------------------------------------------------

2.WKWebView怎么做呢?

WKWebView默认对JavaScript下alert类的方法(包括alert(),confirm(),prompt())做了拦截,实现WKWebView的三个代理方法可拦截此方法。因为prompt方法H5应用的相对少,所以采用该方法进行拦截处理。

JS那边调用alert(),confirm(),prompt() 等函数,OC这边会走系统方法,如下的prompt方法

-(void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable))completionHandler

{

    NSLog(@"prompt-JS传值:%@---%@",prompt,defaultText); //prompt,defaultText 就是JS传给我们的

    NSString *info = [NSString stringWithFormat:@"%@_%@",appId,appkey];

    completionHandler(info);//这里就是要返回给JS的返回值

}

JS实现,一句话OK了

var info = window.prompt(text,defaultText);

我们是SDK开发,基于后台更新,和小伙伴商量,让他用之前的方式,只是在获取参数的方法中写后续逻辑(不知道为毛H5那边不能用全局参数接收数据 ,能打印和使用貌似)

2021年补充:

去到新公司一看代码,这边使用的是js注入方式,需要双方规定handler,客户端去注册handler

//添加注入js方法, oc与js端对应实现
    [config.userContentController addScriptMessageHandler:self name:@"jsAskInfo"];
    [config.userContentController addScriptMessageHandler:self name:@"jsAskImage"];
    [config.userContentController addScriptMessageHandler:self name:@"jsAskBack"];
    [config.userContentController addScriptMessageHandler:self name:@"jsAskConsume"];
    
    self.userContentController = config.userContentController;

在WKScriptMessageHandler的代理中去获取

#pragma mark - WKScriptMessageHandler

//实现js注入方法的协议方法
//依然是这个协议方法,获取注入方法名对象,获取js返回的状态值.
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
    
    //找到对应js端的方法名,获取messge.body
    
    __weak typeof(self)weakself = self;
    
   if([message.name isEqualToString:@"jsAskInfo"]) {

-----------------------------------------------------------------------------------------------我之前采用的是单向规定message的方式,h5那边去执行某个message,我这边刚开始不需要知道message是什么无需注入,只需要在拦截的时候收到这个messgae的内容,去执行对应的代码,在WKNavigationDelegate的代理中实现

// 根据WebView对于即将跳转的HTTP请求头信息和相关信息来决定是否跳转
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    NSString * urlStr = navigationAction.request.URL.absoluteString;
    NSLog(@"发送跳转请求:%@",urlStr);
    NSURL *url = [NSURL URLWithString:urlStr];
    //自己定义的协议头
    NSString *htmlHeadString = @"weixin://";
    NSString *htmlHeadString2 = @"alipay://";
    NSString *htmlHeadString1 = @"dkmweb://openwin";
    NSString *adStr = @"wdlink://ViewControllerWeb";
    NSString *backStr = @"dkmweb://cancelBack";
    NSString *SuccessStr = @"dkmweb://successBack";
    NSString *telHeaderStr = @"tel:";
    if([urlStr hasPrefix:telHeaderStr]){//致电
        if ([[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlStr]]) {
            [WSJieKouApi gameMaiDianWithEvent:@"open_phone_success" ext1:@""];//埋点
        }
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }

因此:现在的wkwebview交互有三种,简单描述一下:

1、js注入的方式,就类似双方规定一个函数如"gotoPay"。客户端需要注册这个"gotoPay"handler,然后在相关的代理中去接收"gotoPay"发过来的信息,并去执行下一步

,但这种方法类似注册通知一样,需要最后注销掉,容易遗忘

js 相关代码

window.webkit.messageHandlers.gotoPay.postMessage(action, token);

//action 和 token都可以用来传参

2、采用单向拦截方式,WKNavigationDelegate中代理decidePolicyForNavigationAction中去获取到对应的url的执行段,类似单向的。

3、采用执行弹框之类的三种代理方式,需h5端调用alert(),参数写在括号内,客户端就能在对应的代理中获取,并通过compHandler给h5返回信息。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在iOS中,可以通过WKWebView与JavaScript进行交互传值。以下是一些常见的方法: 1. 使用JavaScriptCore框架:在iOS 7及以上版本中,可以使用JavaScriptCore框架来实现WKWebViewJS交互传值。具体实现步骤如下: (1)在iOS中创建一个JSContext实例,通过该实例可以操作JS环境。 (2)将JSContext实例设置到WKWebView的配置对象中。 (3)在JS中调用iOS方法时,可以通过window.webkit.messageHandlers对象进行调用,例如window.webkit.messageHandlers.methodName.postMessage(params)。 (4)在iOS中,可以通过WKScriptMessageHandler代理方法来接收JS传递的消息,并进行处理。 2. 使用WKScriptMessageHandler协议:在iOS 8及以上版本中,可以通过WKScriptMessageHandler协议来实现WKWebViewJS交互传值。具体实现步骤如下: (1)在WKWebView的配置对象中设置WKUserContentController的代理对象,并添加需要监听的JS方法名。 (2)在JS中调用iOS方法时,可以通过window.webkit.messageHandlers对象进行调用,例如window.webkit.messageHandlers.methodName.postMessage(params)。 (3)在iOS中,可以通过WKScriptMessageHandler代理方法来接收JS传递的消息,并进行处理。 无论使用哪种方法,都需要注意JS和iOS之间传递的数据类型和格式。通常,JS传递的是字符串类型的数据,在iOS中需要进行解析和转换。同时,为了避免安全问题,需要对JS传递的数据进行校验和过滤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值