h5概念很热,咱们不多多说,但是在移动端的App中某些需要快速开发的地方也是很有好处--可以把一部分不想做的,不方便做的甩给web端去做,咱么只需要做好native与web的通信就好啦?
今天的主角就是JSCore这个哥们,苹果爸爸开放出来很久被大家忽略的角色。这是一个很方便的进行JS与WebView进行通信的神器。既然是神器就理所当然能够方便的进行两端的相互通信。
在开始之前我们先来一个简单相互通信实例(大图)
1 native主动与WebView通信
2 webview调用native
在说通信之前我们先需要搞明白一个东西:WebView调用Native,native调用WebView肯定是相互知道对方的存在保存了对方的instance才行。我们先看一官方的文档
那么这个context我们怎么获取到呢?
代码语言:javascript复制[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
通过kvo我们可以从WebView中获取到,这个就是我们主动与js打招呼的桥梁。那么有了桥梁我们同样需要给WebView说一声让他知道native的存在---
self.ctx[@"App"] = self;
这样相互直接就知道对方的存,js通过App这个作为native的引用,native通过context进行发消息
1 native 主动发消息给WebView
上文我们拿到了js上下文,就可以直接调用js的function啦,例如我们传递网络中的token
代码语言:javascript复制 [self.ctx[@"getToken"] callWithArguments:@[[AppManager manager].token]];
2 js主动发送数据给native
这个过程稍微复杂点,需要通过Protocol来实现,可以拆分为两步:
① 声明通信接口
@protocol App <JSExport>
JSExportAs(popBack, -(void)popBack:(NSString *) action );
JSExportAs(look, -(void)lookGameDetail:(NSString *)spotid type:(NSInteger) type );
JSExportAs(refreshToken, -(void)refreshToken:(NSString *) action );
JSExportAs(pushToFishSpot, -(void)pushToFishSpot:(NSInteger) spotId );
@end
这里的JSExportAs是给我们的函数起了一个js调用的function起了个别名,进而兼容转换一线js的function与OC的函数的差异。
但是有一个点需要注意,我们暴露出的共js调用至少需要一个形参,也就是说,不传递数据也要有一个参数
② 传递给WebView的引用实现协议与函数
这里我们只看一个实现
-(void)popBack:(NSString *)action{
@weakify(self)
dispatch_async(dispatch_get_main_queue(), ^{
[weak_self.navigationController popViewControllerAnimated:YES];
});
}
这里有点需要注意:回来进行UI的操作请在主线程中操作
最后是一个兼容性的彩蛋,也是最坑的一点---alert
UIAlert在iOS 9之后慢慢被禁用,而到了iOS13之后这问题异常严重,然鹅直接js进行alert居然报错,好在是哟办法的
这里附上几种带和不带输入和提示框的webview的alert的处理方法
代码语言:javascript复制 self.ctx[@"window"][@"alert"] = ^(JSValue *message) {
dispatch_async(dispatch_get_main_queue(), ^{
//自定义原生提示框替换原来的提示框
// message.isString message.isBoolean
// [message toString]
// [message toBool]
UIAlertController * alerVc = [UIAlertController alertControllerWithTitle:@"alert"
message: [message toString] preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction * cancelAction = [UIAlertAction actionWithTitle:@"OK" style:0
handler:^(UIAlertAction * _Nonnull action) {
}];
[alerVc addAction:cancelAction];
[self presentViewController:alerVc
animated:YES
completion:^{
}];
});
};
//解决confirm提示框显示异常问题
self.ctx[@"window"][@"confirm"]=^(JSValue *message) {
dispatch_async(dispatch_get_main_queue(), ^{
//自定义原生提示框替换原来的提示框
UIAlertController * alerVc = [UIAlertController alertControllerWithTitle:@"alert"
message: [message toString] preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction * cancelAction = [UIAlertAction actionWithTitle:@"OK" style:0
handler:^(UIAlertAction * _Nonnull action) {
}];
[alerVc addAction:cancelAction];
[self presentViewController:alerVc
animated:YES
completion:^{
}];
});
};
//解决prompt提示框显示异常问题
self.ctx[@"window"][@"prompt"] = ^(JSValue *message) {
dispatch_async(dispatch_get_main_queue(), ^{
//自定义原生提示框替换原来的提示框
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"alert" message:[message toString] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
});
};