OC与JS交互

作者: Code_人生 | 来源:发表于2019-05-21 20:38 被阅读110次

    一、UIWebView

    1.1 直接URL拦截

    • 1.1.1 JS调用OC:shouldStartLoadWithRequest 拦截URL(自定义的),request.URL.scheme(标识 我们自己协议)、request.URL.host(方法名)、request.URL.pathComponents(参数)
    • 1.1.2 OC调用JS:stringByEvaluatingJavaScriptFromString 这里直接执行JS代码
        UIWebView *web = [[UIWebView alloc] initWithFrame:self.webView.frame];
        [self.view insertSubview:web belowSubview:self.viewNavBg];
    
        NSString *javascript1 = [NSString stringWithFormat:@"window.mapInfo = '%@'",data.mj_JSONString];
        [web stringByEvaluatingJavaScriptFromString:javascript1];//给window.mapInfo 赋值
    
        [web stringByEvaluatingJavaScriptFromString:@"var aa = 'hello wolrd'"];//给aa 赋值
        [web stringByEvaluatingJavaScriptFromString:@"shiwu()"];//执行shiwu函数
    

    1.2 JavaScriptCore

    • 1.2.1 OC调用JS 1、jsContext evaluateScript2、jsContext callWithArguments
    • 1.2.2 JS调用OC: self.jsContext[@"showMessage"] = ^() {} 这样的 block 回调执行代码块
    • 1.2.3 注意
      • 异常收集 jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) {}
      • 全局变量 [self.jsContext evaluateScript:@"var arr = [3, 'Cooci', 'abc'];"
      • JS 操作对象 JSExport
      • 循环引用
      • block 回来是子线程
        //JSContext就为其提供着运行环境 H5上下文
        //一开始写在web创建([self.view addSubview:self.webView])之后,然后可以给web传值,之后等加载完毕(webViewDidFinishLoad)再赋一次值
        JSContext *jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    
        jsContext[@"aa"] = @"你好 世界";//给aa 赋值
        [jsContext evaluateScript:@"var aa = 'hello wolrd'"];//给aa 赋值
    
        JSValue *arrValue = self.jsContext[@"arr"];//取值
        //toString、toDictionary、toDate、toInt32 等等
    
        //OC调用JS
        [self.jsContext evaluateScript:@"shiwu()"];//执行shiwu函数
        //提供全局变量
        [self.jsContext evaluateScript:@"var arr = [3, 'Cooci', 'abc'];"];
        //OC调用JS的ocCalljs方法,以数组的形式传入参数
        [self.jsContext[@"ocCalljs"] callWithArguments:@[dict]];
    
        //JS调用OC
        self.jsContext[@"showMessage"] = ^() {
            JSValue *thisValue = [JSContext currentThis];
            NSLog(@"thisValue = %@",thisValue);
            JSValue *cValue = [JSContext currentCallee];
            NSLog(@"cValue = %@",cValue);
            NSArray *args = [JSContext currentArguments];
            NSLog(@"来了:%@",args);
            NSDictionary *dict = @{@"name":@"cooci",@"age":@18};
            [[JSContext currentContext][@"ocCalljs"] callWithArguments:@[dict]];
        };
    
        self.jsContext[@"showDict"] = ^(JSValue *value) {
            NSArray *args = [JSContext currentArguments];
            JSValue *dictValue = args[0];
            NSDictionary *dict = dictValue.toDictionary;
            NSLog(@"%@",dict);
            
            // 模拟用
            int num = [[arrValue.toArray objectAtIndex:0] intValue];
            num += 10;
            NSLog(@"arrValue == %@   num == %d",arrValue.toArray,num);
            dispatch_async(dispatch_get_main_queue(), ^{
                weakSelf.showLabel.text = dict[@"name"];
            });
    
            function openAlbumImage(){
                getImage();
                kcObject.letShowImage();
                alert(kcObject.getS(10,30));
            }
        };
    
        // JS 操作对象
        KC_JSObject *kcObject = [[KC_JSObject alloc] init];
        self.jsContext[@"kcObject"] = kcObject;
        NSLog(@"kcObject == %d",[kcObject getSum:20 num2:40]);
    
    
    
    html 代码
            function openAlbumImage(){
                getImage();
                kcObject.letShowImage();
                alert(kcObject.getS(10,30));
            }
    
    ---------.h------------
    #import <Foundation/Foundation.h>
    #import <JavaScriptCore/JavaScriptCore.h>
    
    @protocol KCProtocol <JSExport>
    
    - (void)letShowImage;
    // 协议 - 协议方法 
    JSExportAs(getS, -(int)getSum:(int)num1 num2:(int)num2);
    
    @end
    
    @interface KC_JSObject : NSObject<KCProtocol>
    @end
    
    ---------.m------------
    
    #import "KC_JSObject.h"
    
    @implementation KC_JSObject;
    
    - (void)letShowImage{
        NSLog(@"打开相册,上传图片");
    }
    
    - (int)getSum:(int)num1 num2:(int)num2{
        NSLog(@"来了");
        // int (nil) - jsvalue (0)
        return num1+num2;
    }
    
    @end
    

    二、WKWebView

    2.1 直接URL拦截

    • 2.1.1 JS调用OC:
      • - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler{}
      • decisionHandler(WKNavigationActionPolicyCancel) 取消跳转
    • 2.1.2 OC调用JS:[self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {回调}];
    //JS调用OC
    #pragma mark - WKNavigationDelegate
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
    {
        NSURL *URL = navigationAction.request.URL;
        NSString *scheme = [URL scheme];
        if ([scheme isEqualToString:@"lgedu"]) {
            NSString *host = [URL host];
            if ([host isEqualToString:@"jsCallOC"]) {
    
            }else{
                NSLog(@"不明地址 %@",host);
            }
            decisionHandler(WKNavigationActionPolicyCancel);
            return;
        }
        decisionHandler(WKNavigationActionPolicyAllow);
    }
    
    //OC调用JS
        NSString *jsStr = [NSString stringWithFormat:@"showAlert('%@')",@"登陆成功"];
        [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
            NSLog(@"%@----%@",result, error);
        }];
    

    2.2 MessageHandler

    • 2.2.1 OC调用JS:[self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {回调}]; 同上
    • 2.2.2 JS调用OC:
      • [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"messgaeOC"]
      • [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"messgaeOC"] 循环引用 移除
      • - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{} 代理 回调
    //self - webView - configuration - userContentController - self
    - (void)viewWillAppear:(BOOL)animated{
        [super viewWillAppear:animated];
        [self.webView.configuration.userContentController addScriptMessageHandler:self name:@"messgaeOC"];
    }
    - (void)viewWillDisappear:(BOOL)animated{
        [super viewWillDisappear:animated];
        [self.webView.configuration.userContentController removeScriptMessageHandlerForName:@"messgaeOC"];
    }
    #pragma mark - WKScriptMessageHandler
    - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message{   
        if (message.name) {
            // OC 层面的消息
        }    
        NSLog(@"message == %@ --- %@",message.name,message.body);    
    }
    
    .html
            function messgaeHandle(){
                // js -- android
                window.webkit.messageHandlers.messgaeOC.postMessage("Cooci 消息");
            }
    

    三、WebViewJavascriptBridge

    pod 'WebViewJavascriptBridge'

    3.1、JS端

    • 3.1.1 setupWebViewJavascriptBridge
      目的是加载一次wvjbscheme://BRIDGE_LOADED,来触发往HTML中注入一些已经写好的JS方法。
    • 3.1.2 setupWebViewJavascriptBridge()调用
      bridge.registerHandler('OCCallJSFunction', function(data, responseCallback) {}) 所有要被调用OC的,都需要在这里注册
    • 3.1.3 WebViewJavascriptBridge.callHandler('jsCallsOC', {'Cooci': '18'}, function(response) {}) js 调用OC 的区域,可以穿参数
        <script>
         
           function setupWebViewJavascriptBridge(callback) {
               if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
               if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
               window.WVJBCallbacks = [callback];
               var WVJBIframe = document.createElement('iframe');
               WVJBIframe.style.display = 'none';
               WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
               document.documentElement.appendChild(WVJBIframe);
               setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
           }
        
            setupWebViewJavascriptBridge(function(bridge) {
             // JS 被调用的方法  OCCallJSFunction 定义的标识
                //OC调用JS     
                bridge.registerHandler('OCCallJSFunction', function(data, responseCallback) {
                    alert('JS方法被调用:'+data);
                    responseCallback('js执行过了');//这句注掉,OC中responseCallback就不会走
                })
             })
                                     
             //JS调用OC                        
             function showWBJ(){
                 WebViewJavascriptBridge.callHandler('jsCallsOC', {'Cooci': '18'}, function(response) {
                      alert(response);
                  })
             }
           
        </script>
    
    <body>
        <input type="button" value="提交" onclick="showWBJ()" /> <br />
    </body>
    

    3.2、OC端

    • 3.2.1 [self.wjb registerHandler:@"jsCallsOC" handler:^(id data, WVJBResponseCallback responseCallback) {}]; 被JS 调用回来的地方
    • 3.2.2 [self.wjb callHandler:@"OCCallJSFunction" data:@"oc调用JS咯" responseCallback:^(id responseData) { }]; OC调用JS
        self.wjb = [WebViewJavascriptBridge bridgeForWebView:self.webView];
        // 如果你要在VC中实现 UIWebView的代理方法 就实现下面的代码(否则省略)
         [self.wjb setWebViewDelegate:self];
    
        //JS调用OC
        [self.wjb registerHandler:@"jsCallsOC" handler:^(id data, WVJBResponseCallback responseCallback) {
            NSLog(@"currentThread == %@",[NSThread currentThread]);
            NSLog(@"data == %@ -- %@",data,responseCallback);
    //        responseCallback(@"123");//这句注掉,JS中回调就不会走
        }];
    
        //OC调用JS
        [self.wjb callHandler:@"OCCallJSFunction" data:@"oc调用JS咯" responseCallback:^(id responseData) {
            NSLog(@"currentThread == %@",[NSThread currentThread]);
            NSLog(@"调用完JS后的回调:%@",responseData);
        }];
    

    四、Cordova

    相关文章

      网友评论

        本文标题:OC与JS交互

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