OC与JS交互总结

作者: 聪莞 | 来源:发表于2019-03-23 15:38 被阅读8次

    UIWebView篇

    • OC调用JS

    1.在webView加载完成后调用:

    //在oc中调用js的jsFun方法,并传入参数“hi,js”
    [self.webView stringByEvaluatingJavaScriptFromString:@"jsFun('hi,js')"];
    
    1. 通过JavaScriptCore的方式(该方法需要导入JavaScriptCore框架)
      在webView加载完成后调用:
        //JSContext就为其提供着运行环境 H5上下文
        JSContext *jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
        self.jsContext = jsContext;
    
        //给js传参
        [self.jsContext evaluateScript:@"var arr = [3, 'Cooci', 'abc'];"];
    

    也可以用这种方式:

        // 将js方法转换成一个JSValue对象 然后调用并传参数
        JSValue * value = self.jsContext[@"jsFun"];
      
        dispatch_async(dispatch_get_main_queue(), ^{
               [value callWithArguments:@[@"hi",@"js"]];
         });
    
    • JS调用OC
      1.在webView的代理中拦截自定义的scheme
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
        
        NSLog(@"%@",request.URL.scheme); // 标识 我们自己协议
        NSLog(@"%@",request.URL.host);   // 方法名
        NSLog(@"%@",request.URL.pathComponents);  // 参数
    
        // JS 调用OC 的原理就是 拦截URL
        NSString *scheme = request.URL.scheme;
        if ([scheme isEqualToString:@"custom"]) {
            NSLog(@"来了,我们自定义的协议");
            
            NSArray *args = request.URL.pathComponents;
            NSString *methodName = args[1];
            
            // 方法1
    //        if ([methodName isEqualToString:@"getSum"]) {
    //            [self getSum];
    //        }
            // 方法2
            SEL methodSel = NSSelectorFromString(methodName);
            if ([self respondsToSelector:methodSel]) {
    #pragma clang diagnostic push
                // 让编译器忽略错误
    #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
                // 让编译器出栈,恢复状态,继续编译后续的代码!
                [self performSelector:methodSel withObject:args[2]];
    #pragma clang diagnostic pop
            }
            // 方法3
    //        objc_msgSend(self,methodSel,args[2],args[3]);
            
            ((void (*) (id, SEL, id))(objc_msgSend))(self, methodSel,args[2]);
            
            // 定义kc_msgSend 函数指针  (void *) 替代了 (void (*)(id, SEL, id))
            void (*kc_msgSend) (id, SEL, id) = (void *)objc_msgSend;
            kc_msgSend(self,methodSel,args[2]);
            
            return NO;
        }
    }
    
    1. 也可以采用JavaScriptCore的方式
    //实现js里的jsFun方法  [JSContext currentContext]来避免循环引用
    self.jsContext[@"jsFun"] = ^() {
            
            NSArray *args = [JSContext currentArguments];
            NSLog(@"args:%@",args);  //获取js里调用该方法传的参数
            
            NSDictionary *dict = @{@"name":@"cooci",@"age":@18};
            
            //这里可以继续去调用js方法  如此反复
    dispatch_async(dispatch_get_main_queue(), ^{
            [[JSContext currentContext][@"jsFun"] callWithArguments:@[dict]];
     });
        }
    

    JavaScriptCore的另外一些用法:

    JS可以直接调用OC的对象方法:

    OC中建立一个协议,并遵循JSExport协议,建立一个对象,遵循该协议

    @protocol JSObjectProtocol <JSExport>
    - (void)hello;
    //相当于一个方法的简写。js中可以直接通过getSum来调用 getSumWithFirst 方法
    JSExportAs(getSum, -(int)getSumWithFirst:(int)a second:(int)b third:(int)c);
    @end
    
    @interface JSObject : NSObject<JSObjectProtocol>
    @end
    
    @implementation JSObject
    - (void)hello {
        NSLog(@"hello");
    }
    
    - (int)getSumWithFirst:(int)a second:(int)b third:(int)c {
        return a+b+c;
    }
    @end
    
    

    使用:

        //OC中绑定
        JSObject * jsObject = [[JSObject alloc] init];
        self.jsContext[@"jsObject"] = jsObject;
    
        //js中调用
        jsObject.hello()
        jsObject.getSum(1,2,3)
    
    
    JS异常处理:
        self.jsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) {
            context.exception = exception;
            NSLog(@"exception == %@",exception);
            NSLog(@"%@",context);
        };
    

    WKWebView篇

    • OC调用JS
        NSString *jsStr = [NSString stringWithFormat:@"showAlert('%@')",@"登陆成功"];
        [self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
            NSLog(@"%@----%@",result, error);
        }];
    
    • JS调用OC
      1.跟UIWebView类似,通过拦截的方式
    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
    {
        NSURL *URL = navigationAction.request.URL;
        NSString *scheme = [URL scheme];
        if ([scheme isEqualToString:@"custom"]) {
            NSString *host = [URL host];
            if ([host isEqualToString:@"jsCallOC"]) {
                NSMutableDictionary *temDict = [self decoderUrl:URL];
                NSString *username = [temDict objectForKey:@"username"];
                NSString *password = [temDict objectForKey:@"password"];
                NSLog(@"%@---%@",username,password);
    
              具体使用同上 :uiwebview里
            }else{
                NSLog(@"不明地址 %@",host);
            }
            decisionHandler(WKNavigationActionPolicyCancel);
            return;
        }
        decisionHandler(WKNavigationActionPolicyAllow);
    }
    

    2.通过MessageHandle的方式

        WKUserContentController *userContentController = [[WKUserContentController alloc] init];
        [configuration.userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@“jsFun”];
    

    此处,messageHandle对self强引用了,所以需要在viewWillDisAppear里打破循环引用

    [webView.configuration.userContentController removeScriptMessageHandlerForName:@"jsFun"];
    

    写在文末

    还有一些优秀的第三方的oc、js交互框架,例如:WebViewJavascriptBridge,使用起来非常的方便,就是需要前端配合一起开发才可以使用,感兴趣的可以去了解一下。WebViewJavaScriptBridge 基本使用

    相关文章

      网友评论

        本文标题:OC与JS交互总结

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