react-native与webview的双向通信

react native 在官网的文档中,并没有详细介绍http://facebook.github.io/react-native/docs/webview.html#onmessage如何实现RN与WebView中JavaScript的通信。 关于 onMessage的描述如下,

onMessage?: function 
A function that is invoked when the webview calls window.postMessage. Setting this property will inject a postMessage global into your webview, but will still call pre-existing values of postMessage.
window.postMessage accepts one argument, data, which will be available on the event object, event.nativeEvent.data. data must be a string.

从上只能看出,RN可以接受来自于webview的消息,然而并无法得知如何从RN往Webview内部发送消息,读源码的时候,发现了 RN的webview组件中除了onMessage 还有个posMessage方法,由此可以推出能搞定RN与Webview内H5的双向通信https://github.com/facebook/react-native/blob/0150bc76eb8d2baa84ba040aead8131228c1185e/Libraries/Components/WebView/WebView.ios.js#L506

  • 在RN中 onMessage负责接收Weview的消息 postMessage 负责发送消息给Webview
  • 通过监听message事件来接收RN的消息,通过window.postMessage在Webview中向RN中发送消息

于是写代码验证下。在html中放置两个输入框A、B,点击按钮把A、B的值发送给RN端,返会两个数的和并展示

H5的代码

1
2
3
4
5
  <div style="padding-top:50px;">
<input id='A' />
<input id='B' />
</div>
<Button id='cacl'>计算</Button> <span>AB相加为</span><span id='sum'></span>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 var bt= document.getElementById('cacl');
bt.addEventListener('click',function(){
var valA = document.getElementById('A').value;
var valB = document.getElementById('B').value;
window.postMessage(JSON.stringify({
type:'add',
data:{
A:valA,
B:valB
}
}))
});
document.addEventListener('message',function(e){
document.getElementById('sum').innerText = JSON.parse(e.data).result;
})

RN 中的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 export default class RNWebbViewMessage extends Component {
constructor(props){
super(props);
this.onMessage = this.onMessage.bind(this);
}
onMessage(e){
var event =e.nativeEvent;
var data=JSON.parse(event.data);
if(data.type ==='add'){
let args= data.data;
let a = Number(args.A);
let b = Number(args.B);
this.refs.webviewRef.postMessage(JSON.stringify({
result:a+b
}))
}
}
render() {
return (
<View style={{flex:1}}>
<WebView ref={'webviewRef'} automaticallyAdjustContentInsets={false} onMessage={this.onMessage} javaScriptEnabled={true} source={{uri:'http://localhost/work/study/rnwebviewmessage/index.html?ss'}} />
</View>
);
}
}

经过验证结论是成立的。

  • webview网页可以使用window.postMessage 发送消息, document.addEventListener('message',callback)来监听消息
  • RN 中onMessage 通过 参数中nativeEvent.data获得webview传递过来的字符串。然后把结果通过webview实例的postMessage方法发送到H5中

以上只是通信api的介绍,如果生产环境中使用的话,还可以对调用形式进一步封装,比如H5中方法调用RN中的分享,并且要求知道分享结果是否成功,可以使用 webviewBridgecallRN('share',{title:'微信分享',content:"分享内容"},callback)这种类似的方式,同时RN中可根据事件的名字进行分模块来实现。

备注