OC和JS交互

作者: 大师的书 | 来源:发表于2019-05-24 12:08 被阅读1次

    前言

    最近有朋友问我OC和JS交互的问题,我又翻开看了一下之前的代码,发现了一个对jscore理解非常方便的方法,分享给大家。这篇文章我主要讲js调用OC,OC调用js不在该范围内

    JavaScriptCore做OC交互的方法

    主要分为两种:

    1. 使用block在js代码里注入方法
    2. 使用JSExport协议在js代码里注入一个对象

    方法一

    使用Block

    OC代码:

    controller.m
    
    - (void)webViewDidFinishLoad:(UIWebView *)webView {
        JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
        context[@"testClick"] = ^(NSString * p1, NSString * p2) {
            NSLog(@"p1:%@, p2:%@", p1, p2);
        };
    }  
    
    1. 这里我在- (void)webViewDidFinishLoad:(UIWebView *)webViewwebview的加载结束代理方法中调用了JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];拿到上下文。
    2. 然后给JSContext上下文添加了testClickblock,这个block有两个参数。

    JS代码:

    <html>
    <head>
        <script>
            function func3Click() {
                testClick("参数一", "参数二");
            }
        </script>
    </head>
    <body>
    
        <button onclick="func3Click()">button3</button>
        
    </body>
    </html>
    
    1. 在js代码中大家可以注意到testClick("参数一", "参数二");对应的是OC中的 context[@"testClick"] = ^(NSStri ...。这样就完成了js和OC的交互。

    方法二

    使用JSExport协议

    OC代码:

    JSHandler.h
    
    @import JavaScriptCore;
    
    @protocol JSHandlerDelegate <JSExport>
    
    - (void)twoparamWithOne:(NSString *)p1 two:(NSString *)p2;
    
    @end
    
    @interface JSHandler : NSObject<JSHandlerDelegate>
    
    @end
    
    JSHandler.m
    
    @implementation JSHandler
    
    - (void)twoparamWithOne:(NSString *)p1 two:(NSString *)p2 {
        NSLog(@"p1:%@, p2:%@", p1, p2);
    }
    
    @end
    
    controller.m
    
    - (void)webViewDidFinishLoad:(UIWebView *)webView {
        JSContext *context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
        JSHandler * handler = [[JSHandler alloc] init];
        context[@"abchaha"] = handler;
    }  
    

    我将关键代码抽离了出来

    1. 我创建了一个JSHandler类,该类有一个- (void)twoparamWithOne:(NSString *)p1 two:(NSString *)p2的方法,用来供js调用。
    2. 在我的controller中有一个webview,- (void)webViewDidFinishLoad:(UIWebView *)webView是webview的加载结束代理方法。我该方法中通过[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]拿到方法拿到jscore的上下文变量(用来操作js)。
    3. contextp[@"abchaha"] = handler,来将我创建的JSContext对象传给jscore,这样在js里就可以使用abchaha这个变量来调用JSHandler的协议里声明的方法了。下面我们来看看JS部分的代码。

    JS代码:

    <html>
    <head>
        <script>
            function func3Click() {
                abchaha.twoparamWithOneTwo("参数一", "参数二");
            }
        </script>
    </head>
    <body>
    
        <button onclick="func3Click()">button3</button>
        
    </body>
    </html>
    

    注意这里abchaha.twoparamWithOneTwo("参数一", "参数二");这行是关键代码。

    1. 大家可以看到,OC中 contextp[@"abchaha"] = handler 的key对应了js中abchaha.twoparamWithOneTwo("参数一", "参数二");
    2. OC协议中的方法- (void)twoparamWithOne:(NSString *)p1two:(NSString *)p2;,对应了js中的twoparamWithOne Two("参数一", "参数二");,在js中使用驼峰原则就可以调用到OC协议中的方法。

    JavaScriptCore在干什么

    上述两个方法方法一明显比方法二要简单的多,但其实不知道大家有没有发现一个规律。那就是他们都是使用documentView.webView.mainFrame.javaScriptContext拿到了JSContext上下文,我们可以用这个JSContext使用[]给他设置字段。

    其实可以这样理解。下面我用js和oc对应的代码来做一下我的理解。

    方法一

    1. 当我们的webview代理里什么都没写的时候,是这样的。
    JS
    
    
    OC
    
    
    1. 当我们在webview代理里使用context[@"abchaha"] = handler;设置实现JSExport协议的类的对象时,是这样的。
    JS
    
    var abchaha = 实现JSExport的对象;
    
    OC
    
    id <继承JSExport的协议> abchaha = 实现JSExport的对象;
    
    1. 当我们在JS里调用abchaha.twoparamWithOneTwo("参数一", "参数二");的时候,是这样的。
    JS
    
    var abchaha = 实现JSExport的对象;
    abchaha.twoparamWithOneTwo("参数一", "参数二");
    
    OC
    
    id <继承JSExport的协议> abchaha = 实现JSExport的对象;
    [abchaha twoparamWithOne:@"参数一" two:@"参数二"];
    

    方法二

    1. 什么都没写的时候就不展示了,就是NoCode。

    2. 当我们在webview代理里使用context[@"testClick"] = ^(NSStri ...设置Block的时候,是这样的。

    JS
    
    var testClick = (var p1){
      ...
    }
    
    OC
    
    void(^ testClick)(NSString * p1, NSString * p2) = ^() {
      ...
    };
    
    1. 当我们在JS里调用abchaha.twoparamWithOneTwo("参数一", "参数二");的时候,是这样的。
    JS
    
    var testClick = (var p1) {
      ...
    }
    testClick("参数一", "参数二");
    
    OC
    
    void(^ testClick)(NSString * p1, NSString * p2) = ^() {
      ...
    };
    testClick(@"参数一", @"参数二");
    

    总结

    其实方法一方法二都是拿到JSContext对象以后,给它设置变量,你可以理解为在往js里写代码。

    方法一是给了js一个我们声明好协议的对象,让js可以直接调用对象协议中的方法。而方法二是给js设置了一个闭包(block)让js可以回调我们的方法。

    我甚至可以使用context[@"aStr"] = @"哈哈哈";直接给js设置一个字符串,然后在js中使用alert(aStr);来弹出它。

    至此,我建议大家可以把JSContext按它的本意来理解,这个JSContext就是拿到js上下文,然后给js代码通过[]设置变量

    相关文章

      网友评论

        本文标题:OC和JS交互

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