美文网首页
原生App与js(web)交互

原生App与js(web)交互

作者: 悟2023 | 来源:发表于2019-04-10 11:04 被阅读0次

    iOS与JS交互的方法:

    1、拦截URL(适用于UIWebView和WKWebView)
    2、JavaScriptCore(仅适用于UIWebView,iOS7+)
    3、WKScriptMessageHandler(仅适用于WKWebView,iOS8+)
    4、WebViewJavascriptBridge(适用于UIWebView和WKWebView),属于第三方框架

    方法一:拦截URL

    首先需要与web端同事协定好协议。
    如:webAction://scan表示启动二维码扫描;webAction://location表示获取定位;scanResult方法名等

    情况一:使用UIWebView
    web调用原生:需要用webView: shouldStartLoadWithRequest:navigationType:方法。
    原生调用web:需要用stringByEvaluatingJavaScriptFromString:方法

    //web端代码
    <a href="webAction://scan">扫一扫</a>
    
    //原生代码
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
        if ([request.URL.absoluteString hasPrefix:@"webAction://scan"]) {
            NSLog(@"调用原生扫描二维码");
            
            //把拿到的数据给Web端
            [self.webView stringByEvaluatingJavaScriptFromString:@"scanResult('%@','%@','%@')",@"数据1",@"数据2",@"数据3"];
            return NO;
        }
        return YES;
    }
    

    情况二:使用WKWebView
    实现一:

    //web端代码
    <a href="webAction://scan">扫一扫</a>
    
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
        NSString *urlStr = navigationAction.request.URL.absoluteString;
        if ([urlStr rangeOfString:@"webAction://scan"].location != NSNotFound) {
            NSLog(@"调用原生扫描二维码");
            
            //把拿到的数据给Web端
            NSString *jsStr = [NSString stringWithFormat:@"scanResult('%@','%@','%@')",@"数据1",@"数据2",@"数据3"];
            [self.wkWebView evaluateJavaScript:jsStr completionHandler:^(id _Nullable data, NSError * _Nullable error) {
                NSLog(@"%@ - 错误:%@", data, error);
            }];
            decisionHandler(WKNavigationActionPolicyCancel);
        }
        else {
            decisionHandler(WKNavigationActionPolicyAllow);
        }
    }
    

    实现二:

    function jsToOCClick() {
        window.location.href="http://www.dongzhuoqiong.com?uuid=1233546769978";
    }
    
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
        NSLog(@"是否使用导航  %s",__func__);
        NSURL *URL = navigationAction.request.URL;
        NSString * urlStr = [[URL absoluteString] stringByRemovingPercentEncoding];
        
        if([urlStr rangeOfString:@"www.dongzhuoqiong.com"].location != NSNotFound){
            NSLog(@"yes");
            NSArray *arr = [urlStr componentsSeparatedByString:@"="];
            
            decisionHandler(WKNavigationActionPolicyCancel);    // 取消加载,不让原有事件响应。
        }
        else {
            decisionHandler(WKNavigationActionPolicyAllow);     // 加载
        }
    }
    

    方法二:JavaScriptCore

    • 通过方法一web调用原生只适合简单的调用,如果要传递参数,虽然也可以拼接在url上,如webAction://scan?method=aaa,但是需要我们自行对字符串进行分割解析,并且特殊字符需要编码。
    • 在iOS7系统提供了JavaScriptCore.framework,可以更优雅地实现js与原生的交互。
    • 首先需要与web端同事协定好协议。
      如:conversion_jsPeopleResult方法名等

    Block形式:(重点代码block块)
    一、对象转化
    OC to js(传输的对象必须遵守JSExport协议)

    //原生代码
    JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    context[@"conversion_js"] = ^() {
        NSLog(@"oc_js 对象转化");
    
        // 将_people对象返回给js
        JSValue *value = [JSContext currentContext][@"PeopleResult"];
        [value callWithArguments:@[_people]];
    };
    context.exceptionHandler = ^(JSContext *context, JSValue *exception) {
        NSLog(@"Error: %@", exception);
    };
    

    js to OC (传输的对象必须遵守JSExport协议)

    __weak typeof(self) weakSelf = self;
    context[@"conversion_oc"] = ^() {
        NSLog(@"js_oc对象转化");
        [weakSelf.context setObject:weakSelf.people forKeyedSubscript:@"People"];
            
        JSValue *value = [weakSelf.context objectForKeyedSubscript:@"People"];
        People *people = value.toObject;
        NSLog(@"%@",people);
        NSLog(@"名字:%@ - 详情:%@",people.name,people.desc);
    };
    context.exceptionHandler = ^(JSContext *context, JSValue *exception) {
        NSLog(@"Error: %@", exception);
    };
    

    对象转化js代码

    //js代码
    <script type="text/javascript">
        //构造函数
        function People(name, description) {
            this.name = name;
            this.desc = description;
        }
    
        function People_js_Action() {   //onclick点击事件
            conversion_js();
        }
        function People_oc_Action() {   //onclick点击事件
            conversion_oc();
        }
        function PeopleResult(People) {
            var peopleInfo = "姓名:" + People.name + ",他"+ People.desc;
            alert(peopleInfo);
        }
    </script>
    

    二、数据交互

    数据返回给js

    //OC代码
    JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    context[@"scan"] = ^() {
        NSLog(@"扫一扫");
        
        // 将结果返回给js scanResult Js函数名
        NSString *jsStr = [NSString stringWithFormat:@"scanResult('%@','%@','%@')",@"数据1",@"数据2",@"数据3"];
        [[JSContext currentContext] evaluateScript:jsStr];
    };
    context.exceptionHandler = ^(JSContext *context, JSValue *exception) {
        NSLog(@"扫一扫JS Error: %@", exception);
    };
    
     function scanClick() {    //onclick点击事件
         scan();
     }
     function scanResult(result) {
        document.getElementById("returnValue").value = result;
     }
    

    OC对象返回给js(传输的对象必须遵守JSExport协议)

    //OC代码
    JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    context[@"conversion_js"] = ^() {
        NSLog(@"oc_js 对象转化");
        // 将_people返回给js
        JSValue *value = [JSContext currentContext][@"PeopleResult"];
        [value callWithArguments:@[_people]];
    };
    
    //js代码
    //构造函数
    function People(name, description) {
        this.name = name;
        this.desc = description;
    }
    function People_js_Action() {   //onclick点击事件
        conversion_js();
    }
    function PeopleResult(People) {
        var peopleInfo = "姓名:" + People.name + ",他"+ People.desc;
        alert(peopleInfo);
    }
    

    js对象传给OC

    //OC代码
    JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    context[@"payAction"] = ^() {
        NSLog(@"支付");
        NSArray *args = [JSContext currentArguments];
        if (args.count < 4) {
            return ;
        }
            
        NSString *orderNo = [args[0] toString];
        NSString *channel = [args[1] toString];
        long long amount = [[args[2] toNumber] longLongValue];
        NSString *subject = [args[3] toString];
            
        // 支付操作
        NSLog(@"订单号:%@---channel:%@---总价:%lld---subject:%@",orderNo,channel,amount,subject);
            
    //        //1、将支付结果返回给js
    //        NSString *jsStr = [NSString stringWithFormat:@"payResult('%@','%@')",@"支付成功",@"支付成功"];
    //        [[JSContext currentContext] evaluateScript:jsStr];
        //2、
        JSValue *value = [JSContext currentContext][@"payResult"];
        [value callWithArguments:@[@"支付成功",@"支付成功"]];
     };
    context.exceptionHandler = ^(JSContext *context, JSValue *exception) {
            NSLog(@"支付JS Error: %@", exception);
    };
    
    //js代码
    function payClick() {
        payAction('201904091234567','ApplePay',100,'夹克');
    }
    function payResult(str,str) {
        var content = str + "," + str;
        alert(content);
        document.getElementById("returnValue").value = content;
    }
    

    方法三:WKScriptMessageHandler

    //js代码
    function jsToOCClick() {
        window.webkit.messageHandlers.color.postMessage([67,205,128,0.5]);
    }
    
    OC代码
    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
    [configuration.userContentController addScriptMessageHandler:self name:@"color"];
    
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
        NSArray *bodyArray = (NSArray *)message.body;
        NSLog(@"bodyArray -- %@",bodyArray);
        if ([message.name isEqualToString:@"color"]) {
            NSString *JSResult = [NSString stringWithFormat:@"scanResult('%@','%@','%@')",@"数据1",@"数据2",@"数据3"];
            [self.wkWebView evaluateJavaScript:JSResult completionHandler:^(id _Nullable result, NSError * _Nullable error) {
                NSLog(@"结果 %@   ---   错误 %@",result, error);
            }];
        }
    }
    

    方法四: WebViewJavascriptBridge(第三方)

    Demo地址:https://pan.baidu.com/s/1eE_PeDNl1N_CQgxo6KYMGg
    密码:9y0b

    相关文章

      网友评论

          本文标题:原生App与js(web)交互

          本文链接:https://www.haomeiwen.com/subject/uapviqtx.html