使用javascriptcore实现供h5调用的native接口
来源:互联网 发布:青岛海尔软件怎么样 编辑:程序博客网 时间:2024/05/29 19:43
在app开发中使用webview,经常需要从js端调用和原生相关的交互功能。那么这样一层bridge的开发工作具体采用什么方案来实现呢?
JS call OC:
方案1:
最古老也是使用最广泛、且跨平台的方案是在页面内嵌入一个iframe,然后通过该iframe触发的webview相关事件来进行hook,从而达到通信的目的。
其中回调方法的传递是通过生成一个id并保存,来回传递id,在js端再通过id获取到对应的fuction实现回调。大名鼎鼎的cordova就是采用了这种方案实现了bridge。
方案2:
iOS7 苹果引入了javascriptcore引擎;而该引擎可以用作js 和原生代码交互的桥梁。 那具体到webview里面是怎样实现的呢?
javascriptcore的使用,离不开的是jscontext。
对于UIWebview,我们可以在webview的代理方法(比如webViewDidFinishLoad)中使用如下代码获取到jscontext并保存:
// Undocumented access to UIWebView's JSContext // TODO: base64 of documentView.webView.mainFrame.javaScriptContext self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
但是对于wkwebview,因为其内部实现的原因,我们无法获取到jscontext,所以这里我们不展开(在文章结尾处我们会大概说一下wkwebview可以采用的方案)。
UIwebview下实现供h5调用的native接口有两种方式:
1. block
在webViewDidFinishLoad末尾插入如下代码(扫码示例):
@weakify_self; self.context[@"scanQRCode"] = ^(JSValue *cb) { @strongify_self; self.scanQRCB = cb; OrderCapture *capture = [[OrderCapture alloc] init]; capture.scanType = OrderCaptureScanTypeAll; capture.targetDelegate = self; [capture showDecodeView]; };
这里的cb是js传递过来的回调函数,通过scanQRCB这个属性保存了起来,后面在扫码的delegate方法中可以通过它来调用回调函数:
//条形码返回结果- (void)didFinishReader:(NSString *)value{ [self.scanQRCB callWithArguments:@[value]];}
js调用的形式(注意:在window上直接调用):
<button onclick = "window.scanQRCode(callback)">点击我弹出原生的扫码!</button>
- 通过JSExport协议包装方法
首先我们要为这些方法注册一个共同的命名空间了(这里叫wq):
- (void)webViewDidFinishLoad:(UIWebView *)webView{ // Undocumented access to UIWebView's JSContext // TODO: base64 of documentView.webView.mainFrame.javaScriptContext self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]; // do the bridge below... here we use jsexport to do the bridge. self.context[@"wq"] = self;}
实现原生的方法:
- (void)nativeAlert:(NSString *)title cb:(JSValue *)value{ self.alertCB = value; @weakify_self; dispatch_async(dispatch_get_main_queue(), ^{ @strongify_self; self.alert = [[UIAlertView alloc] initWithTitle:title message:@"" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:nil, nil]; [self.alert show]; });}
这里的参数应该是和js调用时的顺序对应,jsvalue可以对应js的function。
下面就是实现jsexport协议了,可以放在你的webview容器vc的.h最上面。
@protocol WqJSExport <JSExport>JSExportAs(openUrl, - (void)openUrlWithUrl:(NSString *)url title:(NSString *)title );//- (void)nativeAlert:(NSString *)title;JSExportAs(nativeAlert, - (void)nativeAlert:(NSString *)title cb:(JSValue *)value );@end
这里实现了3个方法,分别演示了多参数、单参数、带回调的export实现。
因js只支持单个参数,因此需要使用JSExportAs来对多参数的情况进行包装。
如果只有一个参数,不需要用jsexportAs来包装。
3个方法的调用示例:
<button onclick = "window.wq.openUrl(url, title)">通过原生打开页面!</button><button onclick = "window.wq.nativeAlert(biaoti, alertCallback)">点击我弹出原生的alert!</button><button onclick = "window.wq.nativeAlert(biaoti, alertCallback)">点击我弹出原生的alert!</button>
那么这样jscore在uiwebview上提供给js的bridge实现就讲完了,这种方法的好处是实现非常清晰,且没有额外的iframe开销;不失为一种优雅的bridge解决方案。
而对于wkwebview来说,需要采用另外的方式来实现(window.webkit.messageHandlers.xxxMethod.postMessage),和上面的方法完全不同,就不再展开了。
而如果使用iframe的方案,可以同时在wkwebview和uiwebview上起作用,考虑同时支持两种webview的情况下使用这种方案是比较合理的,无需做很多额外的处理;关于这套方案的具体实现,有时间再来细说一下(其实不复杂)。
补充:
对于wkwebview,不会自动弹出alert、prompt还有另外一个什么来着,而是可以通过代理方法,需要处理好相应的代理方法才可以完成交互(别以为是bug了,哈哈)。
例(对于alert):
webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:
- 使用javascriptcore实现供h5调用的native接口
- python 接口实现 供第三方调用
- 在Android Native层直接调用MediaCodec接口的实现
- Android 中最简单的实现 HTML(H5)调用native原生页面的方法
- 使用javascriptcore实现oc与js的交互
- IOS中 使用JavaScriptCore 实现OC与JS的交互
- IOS中 使用JavaScriptCore 实现OC与JS的交互
- java native 接口的使用
- JavaScriptCore, WebKit的JS实现
- JavaScriptCore, WebKit的JS实现(
- Android--实现H5与Native交互的两种方式
- Android中实现Native与H5的通信方案汇总
- javascriptcore库的使用详解
- JavaScript :浅谈 iOS 与 H5 的交互- JavaScriptCore 框架
- h5调用支付宝接口
- h5调用微信底层接口的一些知识
- native 和 H5 的交互
- native 和 H5 的交互
- Redis与Memcached的区别
- CentOS 6.5 安装tomcat集群,配置Apache做负载均衡
- Linux下定时任务浅用
- mybatis和hibernate的区别---Mybatis的学习笔记(四)
- 第四十四篇:iOS使用 runtime 与 响应式编程 KVO 原理
- 使用javascriptcore实现供h5调用的native接口
- 使用 Clipper 库的一些问题记录
- react1
- 遇到的防爬虫问题的解决方案
- 剑指offer——按之字形顺序打印二叉树
- 移动或复制虚拟机到其他真机后,Xshell CRT WinSCP 等客户端连不上虚拟机的解决办法
- hdu 3706 Second My Problem First(单调队列)
- php处理redis的例子
- Application的应用和生命周期