美文网首页我爱编程
iOS Native 与 JS 交互

iOS Native 与 JS 交互

作者: 流星Meteor | 来源:发表于2017-11-06 17:03 被阅读179次

    对于 iOS Native 与 JS 交互我们先从调用方向上分为两种情况来看:

    JS 调用 Native
    Native 调用 JS

    1. JS 调用 Native

    其实 JS 调用 iOS Native 也分为两种实现方式:

    a. 假 Request 方法
    b. JavaScriptCore 方法

    a. 假 Request 方法

    原理:其实这种方式就是利用了 webview 的代理方法,在 webview 开始请求的时候截获请求,判断请求是否为约定好的假请求。如果是假请求则表示是 JS 想要按照约定调用我们的 Native 方法,按照约定去执行我们的 Native 代码就好。

    ① UIWebView

    UIWebView 代理有用于截获请求的函数,在里面做判断就好:

    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
        NSURL *url = request.URL;
        // 与约定好的函数名作比较
        if ([[url scheme] isEqualToString:@"your_func_name"]) {
            // just do it
        }
    }
    

    ② WKWebView

    WKWebView 有两个代理,一个是 WKNavigationDelegate,另一个是 WKUIDelegate。WKUIDelegate 在另一篇文章中讲到,这里我们需要设置并实现它的 WKNavigationDelegate 方法:

    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
        NSURL *url = navigationAction.request.URL;
        // 与约定好的函数名作比较
        if ([[url scheme] isEqualToString:@"your_func_name"]) {
            // just do it
            decisionHandler(WKNavigationActionPolicyCancel);
            return;
        }
    
        decisionHandler(WKNavigationActionPolicyAllow);
    }
    

    decisionHandler 是当你的应用程序决定是允许还是取消导航时,要调用的代码块。 该代码块使用单个参数,它必须是枚举类型 WKNavigationActionPolicy 的常量之一。如果不调用 decisionHandler 会引起 crash。

    这里补充一下 JS 代码:

    function callNative() {
        loadURL("your_func_name://xxx");
    }   
    

    然后用一下就好了

    b. JavaScriptCore 方法

    iOS 7 有了 JavaScriptCore 专门用来做 Native 与 JS 的交互。我们可以在 webview 完成加载之后获取 JSContext,然后利用 JSContext 将 JS 中的对象引用过来用 Native 代码对其作出解释或响应:

    // 首先引入 JavaScriptCore 库
    #import <JavaScriptCore/JavaScriptCore.h>
    
    // 然后再 UIWebView 的完成加载的代理方法中
    - (void)webViewDidFinishLoad:(UIWebView *)webView {
        // 获取 JS 上下文
        jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
        // 做引用,将 JS 内的元素引用过来解释,比如方法可以解释成 Block,对象也可以指向 OC 的 Native 对象哦
        jsContext[@"iosDelegate"] = self;
        jsContext[@"yourFuncName"] = ^(id parameter){
            // 注意这里的线程默认是 web 处理的线程,如果涉及主线程操作需要手动转到主线程
            dispatch_async(dispatch_get_main_queue(), ^{
            // your code
            });
        }
    }
    

    而 JS 这边代码更简单了,干脆声明一个不解释的函数(约定好名字的),用于给 Native 做引用:

    var parameter = xxx;
    yourFuncName(parameter);
    
    1. iOS Native 调用 JS

    iOS Native 调用 JS 的实现方法也被 JavaScriptCore 划分开来:

    a. webview 直接注入 JS 并执行
    b. JavaScriptCore 方法

    a. webview 直接注入 JS 并执行

    在 iOS 平台,webview 有注入并执行 JS 的 API。

    UIWebView

    UIWebView 有直接注入 JS 的方法:

    NSString *jsStr = [NSString stringWithFormat:@"showAlert('%@')", @"alert msg"];
    [_webView stringByEvaluatingJavaScriptFromString:jsStr];
    

    这个方法会返回运行 JS 的结果(nullable NSString *),它是一个同步方法,会阻塞当前线程!尽管此方法不被弃用,但最佳做法是使用 WKWebView 类的 evaluateJavaScript:completionHandler:method。

    WKWebView

    不同于 UIWebView,WKWebView 注入并执行 JS 的方法不会阻塞当前线程。因为考虑到 webview 加载的 web content 内 JS 代码不一定经过验证,如果阻塞线程可能会挂起 App。

    NSString *jsStr = [NSString stringWithFormat:@"setLocation('%@')", @"北京市东城区南锣鼓巷纳福胡同xx号"];
    [_webview evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
        NSLog(@"%@----%@", result, error);
    }];
    

    这个方法不会阻塞线程,而且它的回调代码块总是在主线程中运行。

    b. JavaScriptCore 方法

    // 首先引入 JavaScriptCore 库
    #import <JavaScriptCore/JavaScriptCore.h>
    
    // 先获取 JS 上下文
    self.jsContext = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
    // 如果涉及 UI 操作,切回主线程调用 JS 代码中的 YourFuncName,通过数组@[parameter] 入参
    dispatch_async(dispatch_get_main_queue(), ^{
        JSValue *jsValue = self.jsContext[@"YourFuncName"];
        [jsValue callWithArguments:@[parameter]];
    });
    

    上面的代码调用了 JS 代码中 YourFuncName 函数,并且给函数加了 @[parameter] 作为入参。这里再贴一下 JS 代码:

    function YourFuncName(arguments){
        var result = arguments;
        // do what u want to do
    }

    相关文章

      网友评论

        本文标题:iOS Native 与 JS 交互

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