如何在 React Native 实现类微信小程序平台:WebView 调用原生组件
2017-09-19 00:00
1231 查看
在《我们是如何将 Cordova 应用嵌入到 React Native 中》 一文中,我们简单地介绍了『React Native 重写 Cordova 插件:复杂插件的调用』步骤:
WebView 调用 RN 方法,并监听 React Native 返回的相应事件
React Native 接收到 WebView 的调用,调用原生代码,并监听原生代码返回的相应事件
原生代码执行 React Native 调用的方法,并响应事件给 React Native
React Native 接收到原生代码的值,执行 injectJavaScript 注入代码到 WebView 里并执行
注入的 JavaScript 执行代码,并发出相应的广播
WebView 调用的地方,接收到广播,执行相应的方法
上面的 4 和 5 可以是:
4.React Native 接收到原生代码的值,并返回给原生代码 5.接收到相应的值,并发出相应的广播。
即:
本文则详细讨论一下这个过程。
这里,我们和《React Native + Cordova WebView 演进:Plugin 篇》中一样,仍然以 DatePicker 为例。
首先,我们需要一个广播:当 React Native 返回值时,我们就发出一个广播,这样可以解耦合代码。下面的代码则监听相应的广播:
然后便是相应的 datePicker 的调用:
先监听从 React Native 发过来的内容,当接收到内容将数据以广播的形式发出。然后,再通过 PostMessage 告诉 React Naitve,我们需要在调用哪个 action,并传递相应的参数。
在 WebView 的 onMessage 方法里,我们需要处理不同的 action:
然后根据传过来的 action 类型,调用相应的方法,如这里是 DatePickerHandler.showDatePicker,其 Android 部分代码如下所示:
iOS 则有一些不同,iOS 没有非标签的组件,需要自己写。而且,由于 iOS 的 DatePicker 是异步的,因此我们需要通过事件的方式进行。如下是写完插件后的调用示例:
如上,由于 iOS 的日期插件是异步的,并且它只能通过方法,而非组件的方式来唤醒 UI,故而需要 sendEventWithName 来返回值
在这个例子里,由于在 WebView 以广播的方式解绑,因此可以直接返回值:
如果是要不断地发送数据,则需要在 RN 代码里执行:
紧接着,就回到步骤一中的 handler:
最后,我们终于到了:
如此复杂的过程,也是。。。
好了,就差一个小程序框架了:
《如何创建一个兼容「微信小程序」的Web框架:WIN》
WebView 调用 RN 方法,并监听 React Native 返回的相应事件
React Native 接收到 WebView 的调用,调用原生代码,并监听原生代码返回的相应事件
原生代码执行 React Native 调用的方法,并响应事件给 React Native
React Native 接收到原生代码的值,执行 injectJavaScript 注入代码到 WebView 里并执行
注入的 JavaScript 执行代码,并发出相应的广播
WebView 调用的地方,接收到广播,执行相应的方法
上面的 4 和 5 可以是:
4.React Native 接收到原生代码的值,并返回给原生代码 5.接收到相应的值,并发出相应的广播。
即:
本文则详细讨论一下这个过程。
步骤1:WebView 调用 RN 方法,并监听 React Native 返回的相应事件
这里,我们和《React Native + Cordova WebView 演进:Plugin 篇》中一样,仍然以 DatePicker 为例。首先,我们需要一个广播:当 React Native 返回值时,我们就发出一个广播,这样可以解耦合代码。下面的代码则监听相应的广播:
$rootScope.$on('Bridge.datePicker', function(event, data) {
// 更新时间
});
然后便是相应的 datePicker 的调用:
function datePicker(options) {
function handler(event) {
event.target.removeEventListener('message', handler);
var data = JSON.parse(event.data);
$rootScope.$broadcast('Bridge.datePicker', data);
}
window.document.addEventListener('message', handler);
window.postMessage(JSON.stringify({
action: 'DATE_PICKER',
payload: payload
}));
}
先监听从 React Native 发过来的内容,当接收到内容将数据以广播的形式发出。然后,再通过 PostMessage 告诉 React Naitve,我们需要在调用哪个 action,并传递相应的参数。
步骤2:React Native 接收到 WebView 的调用,调用原生代码,并监听原生代码返回的相应事件
在 WebView 的 onMessage 方法里,我们需要处理不同的 action:onMessage = (evt, webView) => {
const event = JSON.parse(evt.nativeEvent.data);
const action = event.action;
const payload = event.payload
...
switch (action) {
case 'DATE_PICKER': {
return DatePickerHandler.showDatePicker(payload, webView);
}
}
...
}
然后根据传过来的 action 类型,调用相应的方法,如这里是 DatePickerHandler.showDatePicker,其 Android 部分代码如下所示:
const { action, year, month, day } = await DatePickerAndroid.open(options);
if (action !== DatePickerAndroid.dismissedAction) {
webView.postMessage(JSON.stringify({
type: 'DATE_PICKER',
success: true,
date,
}));
}
iOS 则有一些不同,iOS 没有非标签的组件,需要自己写。而且,由于 iOS 的 DatePicker 是异步的,因此我们需要通过事件的方式进行。如下是写完插件后的调用示例:
const RNNoTagDatepicker = NativeModules.RNNoTagDatepicker;
const DatePickerEvent = new NativeEventEmitter(NativeModules.RNNoTagDatepicker);
...
const showPicker = async (options) => {
RNNoTagDatepicker.show(options);
};
步骤3:原生代码执行 React Native 调用的方法,并响应事件给 React Native
如上,由于 iOS 的日期插件是异步的,并且它只能通过方法,而非组件的方式来唤醒 UI,故而需要 sendEventWithName 来返回值RCT_EXPORT_METHOD(show:(NSDictionary *) options) {
dispatch_async(dispatch_get_main_queue(), ^{
}
}
#pragma mark - Actions
- (IBAction)doneAction:(id)sender {
dispatch_async(dispatch_get_main_queue(), ^{
NSTimeInterval seconds = [self.datePicker.date timeIntervalSince1970];
[self sendEventWithName:@"DATEPICKER_NATIVE_INVOKE" body: @{@"status": @"success", @"value": [NSString stringWithFormat:@"%f", seconds]}];
[self hide];
});
}
步骤4:React Native 接收到原生代码的值,并返回给原生代码
在这个例子里,由于在 WebView 以广播的方式解绑,因此可以直接返回值:DatePickerEvent.addListener('DATEPICKER_NATIVE_INVOKE', (evt: Event) => {
...
webView.postMessage(JSON.stringify({
type: 'DATE_PICKER',
success: true,
date
}));
...
});
如果是要不断地发送数据,则需要在 RN 代码里执行:
let js = 'var event = new CustomEvent("' + action + '", {detail: ' + JSON.stringify(detail) + '});';
js += 'window.document.dispatchEvent(event);';
webView.injectJavaScript(js);
步骤5:接收到相应的值,并发出相应的广播
紧接着,就回到步骤一中的 handler:function handler(event) {
event.target.removeEventListener('message', handler);
var data = JSON.parse(event.data);
$rootScope.$broadcast('Bridge.datePicker', data);
}
步骤6:WebView 调用的地方,接收到广播,执行相应的方法
最后,我们终于到了:$rootScope.$on('Bridge.datePicker', function(event, data) {
// 更新时间
});
如此复杂的过程,也是。。。
好了,就差一个小程序框架了:
《如何创建一个兼容「微信小程序」的Web框架:WIN》
相关文章推荐
- 微信小程序开发之webview组件内网页实现微信原生支付
- 微信小程序例子——如何使用scroll-view组件实现视图垂直滚动
- Android如何区分app原生和webview实现
- 微信小程序 scroll-view组件实现列表页实例代码
- 在开发中实现点击 WebView 中的图片,调用原生控件放大展示
- 微信小程序例子——如何使用view组件显示文字
- Android中如何实现WebView与JavaScript的相互调用
- React Native WebView组件实现的BarCode(条形码)、(QRCode)二维码
- react native 中webview内的点击事件传到外部原生调用
- 微信小程序scroll-view组件实现滚动动画
- 小程序web-view用wx.scanQRCode实现微信扫一扫功能,识别二维码——微信序web-view高级用法8
- webview打开微信支付,web view h5页面中调用小程序支付——小程序web-view高级用法11
- 了解Android微信里的WebView是如何实现分享的功能
- 微信小程序如何实现通过点击view改变背景颜色
- Android如何区分app原生和webview实现
- 微信小程序如何实现scroll-view隐藏滚动条
- 小程序webview使用jssdk,微信小程序web-view调用JSSDK
- (三)微信小程序之容器组件view实现水平和纵向布局
- webview实现支付后的业务逻辑处理,小程序webview完成微信支付后的处理方法——微信web-view高级用法12
- android webview javascriptinterface实现从HTML JS调用ANDROID内部程序