直奔主题,不贴官方文档。在支持RN客户端和基于vue开发的前端页面信息交互的期间,记录一下关于WebView和html的交互过程,主要通过一下三点来记录:
- html向RN通信
- RN向Html通信
- 在项目中使用
官方文档有介绍如何进行交互,官网传送门
- React Native -> Web: The injectedJavaScript prop
- React Native -> Web: The injectJavaScript method
- Web -> React Native: The postMessage method and onMessage prop
涉及到的主要函数有:onMessage
、window.ReactNativeWebView.postMessage
、injectedJavaScript
、injectJavaScript
环境说明
1
2
3webview: react-native-webview html: 原生js和vue前端均已经测试验证
Html向RN通信
html作为发送方,通过window.ReactNativeWebView.postMessage
发送消息,RN端通过onMessage
接收
html发送方:
1
2
3var msg = '向RN发送消息' window.ReactNativeWebView.postMessage(msg)
RN接收方:
1
2
3
4
5
6
7<WebView ...其他属性 onMessage={(event)=>{ console.log('RN端接收到消息,消息内容='+event.nativeEvent.data) } />
RN向Html通信
injectedJavaScript
这是Webview的一个回调函数,在网页第一次加载完成后会立即被Html执行(之后reload都不会再执行),我们需要将这个属性设置为一串js代码段字符串。在这里我们可以如同在html中一样调用页面的的函数。(很多博客将这个翻译成注入js,在此感觉很是不妥当)
1
2
3
4
5
6
7
8
9
10
11// html中有个js代码 function onRNMessage(data){ // 为了更好的查看效果,建议采用document.get console.log('html收到RN端的调用,并传递了数据,data = '+data) } // rn中webview执行方式 <WebView ...其他属性 injectedJavaScript={'onRNMessage("RN load success!")'} />
injectJavaScript
RN客户端可以通过webview直接调用这个函数,参数是字符串,在我的理解来看,调用这个方法后,会在html端以js的方式执行参数的中内容。
1
2
3
4
5
6
7
8
9
10
11
12
13
14// html中有个js代码 function onRNMessage(data){ // 为了更好的查看效果,建议采用document.get console.log('html收到RN端的调用,并传递了数据,data = '+data) } // rn中webview执行方式 <WebView ref={(webview)=>this.webview=webview} avaScript={'onRNMessage("RN load success!")'} /> // 可以在RN客户端主动调用 let data = 'RN called injectJavaScript!' this.webview.injectJavaScript(`onRNMessage(${data})`)
使用postMessage进行消息通信(强烈不推荐)
在部分博客上看到通过this.webview.postMessage
发送消息,在html端通过document.addEventListener('message',function(data){})
的方式进行数据消息通信,但是此方案有以下问题:
- 不是官方推荐方案,并且在webview的函数中是没有对postMessage进行声明(编译器会提示这个方法不存在)
- android设备上可行,但ios平台下不起作用
- html中的message接收还需要区分是来源(这是一个公共通道)
在项目中使用
调用效果
在真实项目中,我们一般期望调用RN客户端后,可以通过回调函数将结果返回,而不要用过一个代理函数来分发,因此接下来将阐述我在项目中是如何实现这个目标的,实现以下的调用形式:
1
2
3
4
5
6
7
8
9
10// 在es6中可以使用箭头函数 userInfo({ success:function(result){ console.log('success',result) }, fail:function(reason){ console.warn('fail',reason) } })
H5 代码模块
在h5中将调用函数的回调进行缓存(将调用者的参数放到一个Map中,回调的时候通过id找到回调函数进行结果回调),保存在rn-bridge.js
文件中
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52// 回调函数的map,用于app回调结果后,将结果返回给调用者,数据格式:<string, object>, // 其中object:{model:string,functionId:string,success:function,compile:function,fail:function} var mCallbackFunctionMap = new Map(); window.RN_WebViewBridge = { onMessage: function (data) { RNCallback(data); }, // app在加载网页时候,会第一时间通过WebVeiw的injectedJavaScript执行这个函数,此时将mIsRNApp设置为true onRNApp: function () { mIsRNApp = true; }, }; /** * 医网信app执行后的结果回调 * @param result 回调结果(对象) */ function RNCallback (result) { var callbackFun = mCallbackFunctionMap.get(result.functionId); mCallbackFunctionMap.delete(result.functionId); // RN客户端会对请求进行判断,返回‘0’表示业务操作成功 if (result.status === '0') { callbackFun.success && callbackFun.success(result.value); } else { callbackFun.fail && callbackFun.fail(result.value); } callbackFun.compile && callbackFun.compile(result.value); }; /** * * modelName 在RN客户端中会根据modelName来进行具体的业务操作 */ requestRN(requestParams,modelName){ var functionId = `${modelName}-${Date.now()}` requestParmas.functionId = functionId requestParmas.modelName = modelName // 将请求通过postMessage发送给RN客户端 window.ReactNativeWebView.postMessage(JSON.stringify(requestParmas)); } /** * 模仿获取用户信息 * params:{ * success:function(res){}, * fail:function(res){}, * compile:function(res){} * } */ userInfo(params){ requestRN(params,'userInfo') }
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60render(){ return ( <WebView {//...其他内容} ref={(webView)=>this.webView = webView} onMessage={this.onMessage} javaScriptEnabled={true} /> ) } onMessage = (event: WebViewMessageEvent) => { console.log('onMessage ',event) let data = event.nativeEvent.data let params=null try { params = JSON.parse(data) } catch (e) { console.warn('json parse error!! data = ' + data) } if (!params) { return } // 可以根据params.modelName来判断处理什么业务 this.disposeWebMessage(params) } disposeWebMessage(params){ switch(params.modelName){ case 'userInfo': this.userInfo(params) break default: break } } userInfo(params){ let value={ userName:'daizhenhong' } this.postMessageToWeb(value) } /** * 封装了webview进行函数回调的方式 * params H5调用时候的参数,包含了functionId和modelName * value 需要返回的value对象 */ postMessageToWeb(params, value) { let response = { model: params.model, functionId: params.functionId, value: value ? value : undefined, status: value?.status ? value?.status : '0', //默认都返回0表示js-sdk调用成功,当value中有status时,则使用value中的status message: `${params.model}:ok`, } let responseStr = JSON.stringify(response) const jsString = `(function() {window.RN_WebViewBridge && window.RN_WebViewBridge.onMessage(${responseStr});})()` this.webView?.injectJavaScript(jsString) }
H5调用示例
需要运行在RN客户端中,并且html需要依赖上面提到的rn-bridge.js
文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<html> <body> <div onclick="onClickGetUserInfo()">获取用户信息</div> </body> <script language="JavaScript" src="./rn-bridge.js"></script> <script language="JavaScript"> function onClickGetUserInfo () { userInfo({ success: function (value) { console.log('onClickGetUserInfo value = ' + JSON.stringify(value)); }, compile: function (result) { console.warn('onClickGetUserInfo value = ' + JSON.stringify(result)); }, }); } </script> </html>
最后
以上就是大气夏天最近收集整理的关于react-native-webview和h5通信的全部内容,更多相关react-native-webview和h5通信内容请搜索靠谱客的其他文章。
发表评论 取消回复