美文网首页
JS与原生OC交互通信(一)

JS与原生OC交互通信(一)

作者: Leevi_w | 来源:发表于2017-12-22 10:08 被阅读0次

    JavaScript与原生通信

    • UIWebView
    • WKWebView
    • JavaScripCore
    • 第三方库

    JS和OC的交互分为两种方式:JS调用OC和OC调用JS,一般的原则是如果JS想传值给OC就用JS调用OC,相反则用OC调用JS

    UIWebView

    1.JS调用OC

    通过UIWebView的代理方法拦截URL

    - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
    

    当UIWebView在加载之前或者进行网页重定向的会调用这个代理方法,JS调用OC的就这这个代理方法里return YESUIWebView会继续跳转加载,return NO可拦截UIWebView的跳转,例如用UIWebView唤起支付宝客户端 :

    - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
        NSString* reqUrl = request.URL.absoluteString;
        if ([reqUrl hasPrefix:@"alipays://"] || [reqUrl hasPrefix:@"alipay://"]) {
            [[UIApplication sharedApplication]openURL:request.URL];
            return NO;
        }
        return YES;
    }
    

    alipays://为支付宝唤起的协议,当加载支付宝支付的URL时,只需要拦截request.URL是否包含此协议,若包含我们只需通过[[UIApplication sharedApplication]openURL:request.URL]打开这个URL,若安装了支付宝就会唤起支付宝。

    我们再来写一个本地h5界面,来看看具体交互。

    JS代码:

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="UTF-8">
    </head>
    
    <body>
        <h>UIWebView JS 交互</h>
        <div style="margin-top: 16px">
            <input style="width: 120px" type="button" value="登录" onclick="tap('login')">
            <input style="width: 120px" type="button" value="注册" onclick="tap('regist')">
        </div>
        <script>
        function tap(action) {
            window.location.href = "obj://" + action;
        }
       </script>
    </body>
    
    </html>
    

    OC代码:

    初始化UIWebView,加载本地HTML

        UIWebView *webView = [[UIWebView alloc] initWithFrame:self.view.bounds];
        NSString *path = [[NSBundle mainBundle] pathForResource:@"index" ofType:@"html"];
        [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:path]]];
        webView.delegate = self;
        [self.view addSubview:webView];
    
    

    代理方法:

    - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
        NSString *url = request.URL.absoluteString;
        if ([url containsString:@"obj://regist"]) {
           UIAlertController *alert =  [UIAlertController alertControllerWithTitle:@"开始注册" message:@"注册" preferredStyle:UIAlertControllerStyleAlert];
            [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
                
            }]];
            [self presentViewController:alert animated:YES completion:nil];
            return NO;
        }
        return YES;
    }
    
    2017-12-21 17_46_41.gif

    如图运行效果,当我们点击注册的时候,就会重定向我们自定义的URLobj://regist,UIWebView的代理方法就会调用,然后就如上述支付宝一样,拦截后return NO,弹出警告框,当然也可以传递参数给Native。

    2.OC调用JS

    OC最简单就是通过URL传递参数,跟GET请求一样拼接在后面,

    OC还可以通过以下方法直接调取JS并传递参数方法如下

    - (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
    

    还用上述的本地的HTML来演示,我需要在JS中添加一个方法nativeCall
    JS部分如下:

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="UTF-8">
    </head>
    
    <body>
        <h>UIWebView JS 交互</h>
        <div style="margin-top: 16px">
            <input style="width: 120px" type="button" value="登录" onclick="tap('login')">
            <input style="width: 120px" type="button" value="注册" onclick="tap('regist')">
        </div>
        <script>
        function tap(action) {
            window.location.href = "obj://" + action;
        }
    
        function nativeCall(message) {
            alert(message);
        }
        </script>
    </body>
    
    </html>
    

    OC代理方法

    - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
        NSString *url = request.URL.absoluteString;
        if ([url containsString:@"obj://login"]) {
            NSString *message = [NSString stringWithFormat:@"nativeCall('%@')", @"hello javascript"];
            [theWebView stringByEvaluatingJavaScriptFromString:message];
            return NO;
        }
        if ([url containsString:@"obj://regist"]) {
           UIAlertController *alert =  [UIAlertController alertControllerWithTitle:@"开始注册" message:@"注册" preferredStyle:UIAlertControllerStyleAlert];
            [alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
                
            }]];
            [self presentViewController:alert animated:YES completion:nil];
            return NO;
        }
        return YES;
    }
    
    2017-12-21 17_54_52.gif

    当点击登录时,我们拦截了登录,然后用该方法直接调取了JS中的方法nativeCall(), 并传递了参数 hello javascript,此时必须注意,传递参数的时候需要用单引号,参数多的,用,隔开即可。

    我们也可以将一个字典对象通过反序列化成一个NSString来传递给JS,例如:

    JS代码

    <input style="width: 120px" type="button" value="我是谁" onclick="tap('introduce')">
    function introduce (person) {
              var people = JSON.parse(person);
              alert('我是:' + people.name + ',爱好:' + people.like);
    }
    

    OC代码

    if ([url containsString:@"obj://introduce"]) {
        NSDictionary *dic = @{@"name" : @"leevi", @"like" : @"woman"};
        NSData *dicData = [NSJSONSerialization dataWithJSONObject:dic options:0 error:nil];
        NSString *str = [[NSString alloc] initWithData:dicData encoding:NSUTF8StringEncoding];
        NSString *message = [NSString stringWithFormat:@"introduce('%@')", str];
        [theWebView stringByEvaluatingJavaScriptFromString:message];
        return NO;
    }
    

    运行效果如下:


    2017-12-22 09_44_09.gif

    但这个方法只能传字符串给JS,没法传一个OC的对象,之后我们通过JavaScriptCore 可以实现传一个OC对象。

    该方法是有返回值的,我们可以直接在JS的方法中返回给Native参数。
    JS

    function introduce (person) {
        var people = JSON.parse(person);
        alert('我是:' + people.name + ',爱好:' + people.like);
        return '啦啦';
    }  
    

    OC

    NSString *jsReturn =  [theWebView stringByEvaluatingJavaScriptFromString:message];
    NSLog(@"%@", jsReturn);
    

    打印

    15139228701821.jpg

    相关文章

      网友评论

          本文标题:JS与原生OC交互通信(一)

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