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

2019-11-22  本文已影响0人  Jason__Zhou

序言

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,纯属展示功能需要~~~)

上一篇下一篇

猜你喜欢

热点阅读