美文网首页
总结一些JS和OC交互的几种用法

总结一些JS和OC交互的几种用法

作者: Jason__Zhou | 来源:发表于2019-11-22 17:56 被阅读0次

    序言

    oc和js交互是现在开发中经常容易碰到的需求,那么有哪些交互方法呢?

    一. 以UIWebview为例 使用JavaScriptCore来实现

    1. 初始化webview
    self.webView = [[UIWebView alloc]initWithFrame:rect];
     [self.webView loadHTMLString:htmlString baseURL:nil];
     self.webView.delegate = self;
     [self.view addSubview:self.webView];
    
    1. 实现代理方法
      - (void)webViewDidFinishLoad:(UIWebView *)webView

    2. 初始化JSContext
      JSContext *jsContext = [self.webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
      获取JavaScript运行的上下文环境

    下面我们来动态的写入js代码:
    [jsContext evaluateScript:@"var name = ['hello','123','我是按钮']"];
    这里我们往js上下文中插入了一个name数组,当然也可以添加其他js代码。

    还有一种方式,直接为js定义变量或者直接赋值

    NameModel *model = [[NameModel alloc]init];
    model.name = @"跳转到WK";
    jsContext[@"ocModel"] = model;
    

    这样我们就可以把model对象赋值到js的ocModel变量中,在js中也可以取到name的值

    同样我们知道在js里,方法也是一种对象,所以我们还可以为js里的方法用oc重写方法的实现:

    jsContext[@"showMessage"] = ^(){
            NSArray *args = [JSContext currentArguments];
            NSLog(@"回调到了 -- %@",args);  
    };
    

    如此在js中调用了showMessage方法便会回调到oc的这个block中来。 [JSContext currentArguments]指的是方法传过来的参数,因为可能有多个,所以返回的是一个数组

    那么OC同样也可以直接调用js里的方法用callWithArguments方法,具体例子:

    [[JSContext currentContext][@"addItems"] callWithArguments:@[@"按钮啊"]];

    上诉代码的意思是,OC直接调用JS的addItems方法,并传入一个内容为String的参数。

    二. 通过WKWebView来实现交互

    1. 初始化WKWebView
    self.webView = [[WKWebView alloc]initWithFrame:rect configuration:config];
    self.webView.navigationDelegate = self;
     self.webView.UIDelegate = self;
    [self.webView loadHTMLString:htmlString baseURL:nil];
    [self.view addSubview:self.webView];
    

    注意:

    初始化WKWebView的时候需要传入一个config, 这里也整理了config相关参数的定义及其设置:

    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
        // 创建设置对象
         WKPreferences *preference = [[WKPreferences alloc]init];
         //最小字体大小 当将javaScriptEnabled属性设置为NO时,可以看到明显的效果
         preference.minimumFontSize = 0;
         //设置是否支持javaScript 默认是支持的
         preference.javaScriptEnabled = YES;
         // 在iOS上默认为NO,表示是否允许不经过用户交互由javaScript自动打开窗口
         preference.javaScriptCanOpenWindowsAutomatically = YES;
         config.preferences = preference;
         
         // 是使用h5的视频播放器在线播放, 还是使用原生播放器全屏播放
         config.allowsInlineMediaPlayback = YES;
         //设置视频是否需要用户手动播放  设置为NO则会允许自动播放
         config.mediaTypesRequiringUserActionForPlayback = YES;
         //设置是否允许画中画技术 在特定设备上有效
         config.allowsPictureInPictureMediaPlayback = YES;
         //设置请求的User-Agent信息中应用程序名称 iOS9后可用
         config.applicationNameForUserAgent = @"ChinaDailyForiPad";
    //      //自定义的WKScriptMessageHandler 是为了解决内存不释放的问题
    //     WeakWebViewScriptMessageDelegate *weakScriptMessageDelegate = [[WeakWebViewScriptMessageDelegate alloc] initWithDelegate:self];
    //     //这个类主要用来做native与JavaScript的交互管理
    //     WKUserContentController * wkUController = [[WKUserContentController alloc] init];
    //     //注册一个name为jsToOcNoPrams的js方法
    //     [wkUController addScriptMessageHandler:weakScriptMessageDelegate  name:@"jsToOcNoPrams"];
    //     [wkUController addScriptMessageHandler:weakScriptMessageDelegate  name:@"jsToOcWithPrams"];
    //    config.userContentController = wkUController;
    

    其实做完上述步骤,并不能正常显示一个h5,打开你会发现里面的内容变的很小。
    这时候 你需要加这么一段代码 就可以恢复正常大小了:

    //以下代码适配文本大小,由UIWebView换为WKWebView后,会发现字体小了很多,这应该是WKWebView与html的兼容问题,解决办法是修改原网页,要么我们手动注入JS
        NSString *jSString = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
        //用于进行JavaScript注入
        WKUserScript *wkUScript = [[WKUserScript alloc] initWithSource:jSString injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
        [config.userContentController addUserScript:wkUScript];
    

    以上完成了一个WKWebView正常展示的步骤。

    1. 插入一段js代码:
    [self.webView evaluateJavaScript:@"addItems2('测试测试')" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
            NSLog(@"%@ ---- %@",result,error.localizedDescription);
        }];
    
    1. WKWebView还可以截获Alert弹框,通过UIDelegate
    - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
        NSLog(@"here showed alert");
        UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"提醒" message:message preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *action = [UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            [self.webView evaluateJavaScript:@"messageHandle:OC" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
            }];
        }];
        [controller addAction:action];
        [self presentViewController:controller animated:YES completion:^{
           completionHandler();
        }];
    }
    

    注意:

    这里completionHandler();是必须要调用的 不然会crash!

    三. 通过WebViewJavascriptBridge来实现交互

    这种方式,是OC最省力的一种方式,反而h5需要做的事情稍微多点。

    1. 先导入WebViewJavascriptBridge
      pod 'WebViewJavascriptBridge', '~> 6.0'

    2. 将webview与WebViewJavascriptBridge关联起来:

    _bridge = [WebViewJavascriptBridge bridgeForWebView:self.webView];
     [_bridge setWebViewDelegate:self];
    

    3.oc调用js的方法:
    oc代码:

      [_bridge registerHandler:@"testObjcCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
            NSLog(@"testObjcCallback called: %@", data);
    //    在这里可以调用responseCallback告诉js oc收到了
    //        responseCallback(@"Response from testObjcCallback");
        }];
    

    js代码:

    callbackButton.onclick = function() {
                bridge.callHandler('testObjcCallback', {'foo': 'bar'}, function(response) {
                    log('JS got response', response)
                })
            }
    

    这里的data将会接收到内容为{'foo': 'bar'}的一个json字符串,内容可以自由传输

    1. js调用oc的方法:
      oc代码:
    [_bridge registerHandler:@"openAblum" handler:^(id data, WVJBResponseCallback responseCallback) {
          ...
        }];
    

    js代码:

    bridge.callHandler('openAblum', {'index': '1'}, function(response) { });
    

    传输的内容可以自定义!

    以上便是我总结的几种常用的方法!!
    附加一个实现oc从相册选择一个图片 并传到h5的demo

    (写了两个比较蹩脚的h5,纯属展示功能需要~~~)

    相关文章

      网友评论

          本文标题:总结一些JS和OC交互的几种用法

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