直奔主題,不貼官方檔案,在支持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
環境說明
webview: react-native-webview
html: 原生js和vue前端均已經測驗驗證
Html向RN通信
html作為發送方,通過window.ReactNativeWebView.postMessage發送訊息,RN端通過onMessage接收
html發送方:
var msg = '向RN發送訊息'
window.ReactNativeWebView.postMessage(msg)
RN接收方:
<WebView
...其他屬性
onMessage={(event)=>{
console.log('RN端接收到訊息,訊息內容='+event.nativeEvent.data)
}
/>
RN向Html通信
injectedJavaScript
這是Webview的一個回呼函式,在網頁第一次加載完成后會立即被Html執行(之后reload都不會再執行),我們需要將這個屬性設定為一串js代碼段字串,在這里我們可以如同在html中一樣呼叫頁面的的函式,(很多博客將這個翻譯成注入js,在此感覺很是不妥當)
// 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的方式執行引數的中內容,
// 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客戶端后,可以通過回呼函式將結果回傳,而不要用過一個代理函式來分發,因此接下來將闡述我在專案中是如何實作這個目標的,實作以下的呼叫形式:
// 在es6中可以使用箭頭函式
userInfo({
success:function(result){
console.log('success',result)
},
fail:function(reason){
console.warn('fail',reason)
}
})
H5 代碼模塊
在h5中將呼叫函式的回呼進行快取(將呼叫者的引數放到一個Map中,回呼的時候通過id找到回呼函式進行結果回呼),保存在rn-bridge.js檔案中
// 回呼函式的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客戶端處理代碼
render(){
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檔案
<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>
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/258039.html
標籤:其他
