前言
在開發中,使用uniapp開發的項目開發效率是極高的,使用一套代碼就能夠同時在多端上線,像筆者之前寫過的使用Flutter端和webview端
之間的相互通信方法和問題,這種方式本質上實際上是h5和h5之間的通信
,網上有非常多的方案,最簡單的就是使用postMessage和addEventListener
的方式,這個在我之前的文章有講解,這里不再贅述。
那么今天的問題,是使用uniapp開發的App端和H5端(webview)之間的通信問題。
注意前提,是使用uniapp同時去開發app端和h5端。
問題
uniapp本質開發的app實際上還是web,那么能不能用postMessage的方式呢?
答案當然是可以的,但是你要區分情況,仔細看看官方文檔:
平臺差異說明:App-nvue,是App-nvue的方法,這是個坑!!!
所以,這個時候就需要去區分情況了,你使用的是vue寫的webview還是nvue寫的webview。
vue類型的webview
<web-view :src="src" ref="webview" :fullscreen="false" @message="receiveData"></web-view>
app傳遞數據給h5
本質:h5在webview環境中提取放入一個函數,app調用該函數傳遞數據進去。
h5端接收:可以在app.vue的onLaunch階段
window.msgFromUniapp = (res) =>{console.log("原生傳遞過來的數據:",res)
}
app端發送:
methods: {//給webview傳遞數據postMess(msg) {const currentWebview = this.$scope.$getAppWebview();const wv = currentWebview.children()[0];wv.evalJS(`msgFromUniapp('${JSON.stringify(msg)}')`)}},onLoad(item) {this.src = decodeURIComponent(item.url)// 傳入需要跳轉的鏈接 使用web-view標簽進行跳轉this.title = item.title// #ifdef APP-PLUSconst currentWebview = this.$scope.$getAppWebview();const that = thissetTimeout(function() {let wv = currentWebview.children()[0];that.postMess({type: 'app/systemInfo',data: {sys: 'ios'},code: 1,})}, 500);// #endif}
h5傳遞給app
app端接收:
添加監聽即可
@message="receiveData"
h5端發送:
//傳遞url給原生應用uni.webView.postMessage({data:{action:'openUrl',url:this.orderDetail.url}})
注意事項
app端要延遲再去獲取webview實例,等webview加載完成。
官方寫的是uni.posMessage,筆者親試,沒用的,注意是是 uni.webView.postMessage
。
nvue類型的webview
vue頁面和nvue頁面的區別,這里不做贅述,官方文檔寫的很清楚。
這個時候就可以使用官方文檔的postMessage方式來
app傳遞數據給h5
綁定一個ref,獲取webview實例
<web-view ref="webview" :src="src" @onPostMessage="handlePostMessage":style="{height:mbHeight,width:mbWidth,top:mbTop}" fullscreen="false"></web-view>
this.$refs.webview.postMessage(data, '*')
或者
// 調用 webview 內部邏輯evalJs: function() {this.$refs.webview.evalJs("document.body.style.background ='#00FF00'");}
- 然后h5使用window.addEventListener接收
h5傳遞數據給app
app接收消息:
<web-view ref="webview" class="webview" @onPostMessage="handlePostMessage"></web-view>
handlePostMessage: function(data) {console.log("接收到消息:" + JSON.stringify(data.detail));},
注意事項
頁面空白
如果你是nvue頁面:
大概率是你沒指定寬高,不信你放入一個百度的url試試,如果還是空白,請你設置style指定寬高。
如果你是vue頁面,可能就是網頁本身就打不開
環境問題
這是一個非常頭疼的問題,我怎么知道這個web頁面是在app環境打開還是在h5打開的,為什么需要去區分環境問題,因為你可能有一個這樣的場景,你開發的app需要打開一個網頁,然后撐滿全屏,本質還是用webview容器去打開的,h5不知道自己所處的環境是app端,那么就會帶來導航欄區域和底部安全區域怎么獲取和處理的問題。
你可以選擇從app端下手,前提是這個webview必須是nvue頁面,因為vue頁面默認webview是撐滿全屏的,撐滿全屏,撐滿全屏。
如果你是vue頁面,那么你可以通知h5端當前所處的環境,當前的導航欄高度和安全區域高度,在h5端單獨去做樣式兼容
如果你是nvue頁面,除了上述方式,你還可以自己去指定webview的樣式。
我還是建議都使用第一種方案吧,筆者自己去設置webview的樣式發現在全屏階段還是有一些問題的,不如默認撐滿全屏,在h5端去做調整,畢竟調整h5端端成本最小,上架之后的app還需要提審等一些列步驟。
側滑返回問題
可能有小伙伴發現,我打開一個webview,網頁里面本身有好多跳轉,為什么沒辦法側滑返回。
原因是,本質上,在app端你打開的實際上只有一個webview頁面,它只有一個頁面,你的h5頁面是在里面打開的,無論你h5的路由棧有多少層多沒用,對于app來說,就只有一個webview頁面。
所以,一定要注意放一個返回按鈕提供給用戶返回的機會,如果你要跳轉外部網頁,也不要用window.location去進行跳轉,到時候就會返回不了了,你可以通知app端使用plus方法去打開網頁
總結
官方文檔并沒有詳細去區分兩者的區別,網上的信息也很雜亂,所以在此特別去做區分和處理,如果你有更好的建議和方案,歡迎在評論區提出。