最近公司很多项目涉及到在原生中嵌入H5的需求,h5多为vue页面,第一个项目使用的UIWebView加载,第二个项目使用WKWebView,转为WK的原因是因为前者对vue的兼容总会有些瑕疵,后者是苹果主推的控件,像微信这种巨头也在17年3月1号起正式启用WK,用它必有原因的,在此并不陈诉。用起来还是不是很熟,虽然简单但是细节较多,故记录提醒自己,也希望可以帮到其他人。项目中难免遇到两者选其一的时候,与web交互总会出现一些无法预知的问题,有时候UIWebView没有问题WKWebView出问题,反之亦然。
此篇介绍了两者与vue交互的粗略方法。
我们写好一个vue网页片段
<el-button type="primary" id="one" v-on:click="OCcallJSClick()">OC调用JS方法</el-button>
<el-button type="primary" id="two" v-on:click="clickVUE('我是网页的数据')">JS调用OC方法</el-button>
注意:我们如果是在局域网内测试,比如本文,vue npm run dev后的网址是 localhost:8080/#/,所谓localhost其实是本机的ip地址,我们要保证手机和电脑在同一个局域网内,并且,我们需要在vue中稍作修改,在工程文件夹config下index.js中 ,把host:'localhost'改成0.0.0.0,这样在ios中填写网址时,把0.0.0.0换成pc端ip地址就可以在手机上访问这个网页了。
UIWebView
先看老家伙
UIWebView *web = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2)];
self.webview = web;
//这里换成pc端ip地址
NSURLRequest *req = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://192.168.31.127:8082/#/"]];
[web loadRequest:req];
[(UIScrollView *)[[web subviews] objectAtIndex:0] setBounces:NO];
web.scalesPageToFit = NO;
web.delegate = self;
[self.view addSubview:web];
入正题;
JS调用OC 并传参数给OC使用
要实现原生与网页的交互,我们使用苹果自带的框架 <JavaScriptCore/JavaScriptCore.h> iOS7后引入的新框架。
并且我们在网页加载完成后创建这个工具实例
// 当页面开始加载的时候调用
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
self.jsContext = [self.webview valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
//括号内的方法需与vue中的方法相同
self.jsContext[@"JScallOCClick"] = ^(NSString *str) {
NSLog(@"+++++++JScallOCClick+++++++");
return [self jsCallOC:str];
};
}
//注意,这里vue响应的是clickVUE方法,JScallOCClick是在这个方法内部,直接去响应这个方法是无效的
clickVUE(b){
JScallOCClick(b);
},
原生view中创建一个Button,然后相应方法,调用JS
self.view.backgroundColor = [UIColor lightGrayColor];
self.ocButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.ocButton.frame = CGRectMake(30, SCREEN_HEIGHT - 200, SCREEN_WIDTH - 60, 50);
[self.ocButton setTitle:@"OC按钮调用JS代码" forState:UIControlStateNormal];
[self.ocButton setBackgroundColor:[UIColor redColor]];
[self.ocButton addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.ocButton];
- (void)buttonClick:(UIButton *)sender
{
//此方法名称必须与vue中的方法相同 括号内携带参数
NSString *textJS = [NSString stringWithFormat:@"OCcallJSClick('%@')",@"我是参数"];
[self.jsContext evaluateScript:textJS];
}
OC调用JS 并传参数给JS使用
//这里可以直接调用,绑定vue的事件 弹出ios传来的字符串
OCcallJSClick(a){
alert(a);
console.log(a);
},
这里需要注意的是 oc调用js需要事先把这个方法暴露在外部 将方法名字挂载在mounted处
mounted(){
window.OCcallJSClick = this.OCcallJSClick;
},
ios中创建button,并绑定事件
self.view.backgroundColor = [UIColor lightGrayColor];
self.ocButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.ocButton.frame = CGRectMake(30, SCREEN_HEIGHT - 200, SCREEN_WIDTH - 60, 50);
[self.ocButton setTitle:@"OC按钮调用JS代码" forState:UIControlStateNormal];
[self.ocButton setBackgroundColor:[UIColor redColor]];
[self.ocButton addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.ocButton];
- (void)buttonClick:(UIButton *)sender
{
NSString *textJS = [NSString stringWithFormat:@"OCcallJSClick('%@')",@"我是参数"];
[self.jsContext evaluateScript:textJS];
}
WKWebView
再看新家伙
头文件倒入,并遵循三个协议
#import <WebKit/WebKit.h>
@interface WKWebViewDemoViewController ()<WKNavigationDelegate,WKUIDelegate,WKScriptMessageHandler>
JS调用OC 并传参数给OC使用
这里在创建WKWebView中,凡是js调用oc的,需要在创建WKWebView的时候注册一下这个方法
//创建webview
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
WKUserContentController *userController = [[WKUserContentController alloc] init];
config.preferences.javaScriptEnabled = YES;
config.userContentController = userController;
[userController addScriptMessageHandler:self name:@"JScallOCClick"];
WKWebView *web = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2) configuration:config];
在vue中不能再简单的写方法去响应了,应该改成
//注意,如果是无参 括号内写null,不能写‘’ 也不能什么都不写 这个被坑了一天。。。
window.webkit.messageHandlers.JScallOCClick.postMessage(b);
同样在代理中响应js的事件
#pragma mark - 处理与js交互回调
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
{
//message中包含了js中所有的信息
//有两个重要的属性,一个是name,进行区分判断具体响应某个方法
//body中就是js传过来的参数
if ([message.name isEqualToString:@"JScallOCClick"]) {
NSLog(@"%@",message.body);
[self jsCallOC:message.body];
}
}
OC调用JS 并传参数给JS使用
- (void)buttonClick:(UIButton *)sender
{
NSString *param = @"我是原生的数据";
NSString * jsStr =[NSString stringWithFormat:@"OCcallJSClick('%@')",param];
[self.webView evaluateJavaScript:jsStr completionHandler:^(id _Nullable result, NSError * _Nullable error) {
NSLog(@"--------error %@",error);
//此处可以打印error.
NSLog(@"--------result %@",result);
}];
}
注意 WKWebView加载的web中如果有弹窗,需要额外写一个代理处理一下弹窗,不然不会弹出
#pragma mark - WKUIDelegate
- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提醒" message:message preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"知道了" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
completionHandler();
}]];
[self presentViewController:alert animated:YES completion:nil];
}
以上简单清晰的描述完了两个框架与VUE的交互,简单如此,但值得整理一下。
end:如果
看完这篇
web和原生总是没有响应
别着急
盖上电脑
然后
砸了吧 ~ 😆