uni-app中App與webview雙向?qū)崟r(shí)通信詳細(xì)代碼示例
在 Uniapp 中,App 與 里面嵌入的 webview 進(jìn)行雙向的實(shí)時(shí)通信
vue2 , 模擬器
主要分為兩部分
webview 向 app 發(fā)送信息
app 向 webview 發(fā)送信息
以下是實(shí)現(xiàn)方式,用一個(gè)例子來說明
(文章最后我會(huì)放這個(gè)例子的github地址)
webview 向 app 發(fā)送信息
示例: webview 里面向 app 發(fā)送 圖片的 base64 , app 保存圖片到系統(tǒng)相冊(cè);
此處分為, app 和 webview 部分:
app 注冊(cè)事件
webview 觸發(fā) app 的事件
app部分
保存到系統(tǒng)相冊(cè)功能(功能具體細(xì)節(jié)不重要)
// utils/appMessageHandler.js // 這里代碼都在app下執(zhí)行 function appSaveImgFile(params) { const { base64, downloadName } = params const bitmap = new plus.nativeObj.Bitmap("test"); bitmap.loadBase64Data( base64, function () { const url = "_doc/" + downloadName + ".png"; // url為時(shí)間戳命名方式 bitmap.save( url, { overwrite: true, // 是否覆蓋 // quality: 'quality' // 圖片清晰度 }, (i) => { plus.gallery.save( i.target, function () { uni.showToast({ title: "APP圖片保存至相冊(cè)", icon: "none", }); bitmap.clear(); }, function (e) { uni.showToast({ title: "APP圖片保存至相冊(cè)失敗:" + JSON.stringify(e), icon: "none", }); bitmap.clear(); } ); }, (e) => { uni.showToast({ title: "圖片保存失敗1:" + JSON.stringify(e), icon: "none", }); bitmap.clear(); } ); }, (e) => { uni.showToast({ title: "圖片保存失敗2:" + JSON.stringify(e), icon: "none", }); bitmap.clear(); } ); } export { appSaveImgFile, }
在App.vue中注冊(cè)事件;將 appMessageHandle.js 里面所有導(dǎo)出的事件進(jìn)行注冊(cè);注意需要條件編譯
// App.vue <script> import * as appPlusMessageHandler from "./utils/appMessageHandler"; export default { data() { return { appRegisterMap: undefined, }; }, onLaunch: function () { console.log("App Launch"); // #ifdef APP-PLUS // 注冊(cè)事件 plus.globalEvent.addEventListener("plusMessage", this.plusMessageHandler); // #endif }, methods: { /** * 將所有導(dǎo)出的 app 事件 * 用 map 建立 函數(shù)名 - 函數(shù) 的聯(lián)系 * 返回 map */ registerAppPlusMap() { if (this.appRegisterMap) { return this.appRegisterMap; } let map = new Map(); Object.keys(appPlusMessageHandler).forEach((item) => { map.set(item, appPlusMessageHandler[item]); }); this.appRegisterMap = map; return map; }, /** * 用 action 獲取的函數(shù)名 * 通過 map 獲取到函數(shù),調(diào)用執(zhí)行 */ plusMessageHandler(msg) { let map = this.registerAppPlusMap(); if (msg.data.args.data.arg?.action) { let handler = map.get(msg.data.args.data.arg?.action); let params = msg.data.args.data.arg?.params; handler && handler(params); } }, }, }; </script>
webview 部分
通過使用 uni.webview.js (文末附錄放源碼,我做了些許修改,邏輯沒改,是一些變量調(diào)整了下) 的功能 postMessage , 向 app 發(fā)送圖片生成的 base64;
main.js 中掛載 uWeb (uni.webview.js)
// main.js // 全局添加uWeb // #ifdef H5 import uWeb from "@/utils/uni.webview.js"; // #endif // #ifdef H5 Vue.prototype.$uWeb = uWeb; // #endif
生成的圖片base64,通過以下方式發(fā)送給 app
此處 action 與 上面 plusMessageHandler方法的 action 是對(duì)應(yīng)的
appSaveImgFile 與 appMessageHandler.js 里的函數(shù)名是對(duì)應(yīng)的
// 某個(gè)頁面或者js this.$uWeb.postMessage({ data: { action: "appSaveImgFile", params: { base64: imgBase64, downloadName, }, }, });
至此,webview 能隨時(shí)向 app 發(fā)送消息了
App 向 webview 發(fā)送消息
使用 evalJS
分兩步:
webview 在 window 注冊(cè)事件
app 使用 evalJs 觸發(fā) webview 的事件
注意: 確保webview 先注冊(cè)好事件之后,app發(fā)送的事件才能被 webview 接收到
具體實(shí)現(xiàn),utils下新建appToWebview.js; appSendMessage 是給 App 用的;webviewGetMessage 是給 webview 注冊(cè)用的
// appToWebview.js // 發(fā)送信息之前,先要有 webviewGetMessage function appSendMessage(_this, action, params) { const self = _this; self.currentWebview = self.$scope?.$getAppWebview()?.children()[0]; //傳遞大量數(shù)據(jù) self.currentWebview?.evalJS(`${action}(${JSON.stringify(params)})`); } function webviewGetMessage(action, callback) { // #ifdef H5 window[action] = (data) => { let params = JSON.parse(JSON.stringify(data)); callback(params); }; // #endif } export { appSendMessage, webviewGetMessage };
webview 部分
用 webviewGetMessage 注冊(cè)一個(gè) msgFromApp 名字的事件,給 App 調(diào)用;
// 某個(gè) webview 頁面, created() { webviewGetMessage("msgFromApp", (params) => { console.log("getAppParams", params); this.appMsg = params; }); },
App
用 appSendMessage 發(fā)送一個(gè)信息給 webview
// 某個(gè)有 webview 的 app 頁面, mounted() { setTimeout(() => { appSendMessage(this, "msgFromApp", { msgFromApp: 233 }); }, 5000); },
至此,完成了 app 向 webview 發(fā)送信息
GitHub 地址
GitHub - adcGG/uniapp-app-webview: Communication between app and webview
這里 uniapp 項(xiàng)目,app 和 用到的 h5 地址是同一個(gè)項(xiàng)目下的
app/index 用到的 webview 的 url 為 webviewUrl: “http://192.168.1.16:8080/#/pages/h5/index”,
附錄
uni.webview.js
!(function (e, n) { "object" == typeof exports && "undefined" != typeof module ? (module.exports = n()) : "function" == typeof define && define.amd ? define(n) : ((e = e || self).webUni = n()); })(this, function () { "use strict"; try { var e = {}; Object.defineProperty(e, "passive", { get: function () { !0; }, }), window.addEventListener("test-passive", null, e); } catch (e) {} var n = Object.prototype.hasOwnProperty; function t(e, t) { return n.call(e, t); } var i = [], a = function (e, n) { var t = { options: { timestamp: +new Date(), }, name: e, arg: n, }; if (window.__dcloud_weex_postMessage || window.__dcloud_weex_) { if ("postMessage" === e) { var a = { data: [n], }; return window.__dcloud_weex_postMessage ? window.__dcloud_weex_postMessage(a) : window.__dcloud_weex_.postMessage(JSON.stringify(a)); } var o = { type: "WEB_INVOKE_APPSERVICE", args: { data: t, webviewIds: i, }, }; window.__dcloud_weex_postMessage ? window.__dcloud_weex_postMessageToService(o) : window.__dcloud_weex_.postMessageToService(JSON.stringify(o)); } if (!window.plus) return window.parent.postMessage( { type: "WEB_INVOKE_APPSERVICE", data: t, pageId: "", }, "*" ); if (0 === i.length) { var r = plus.webview.currentWebview(); if (!r) throw new Error("plus.webview.currentWebview() is undefined"); var d = r.parent(), s = ""; (s = d ? d.id : r.id), i.push(s); } if (plus.webview.getWebviewById("__uniapp__service")) plus.webview.postMessageToUniNView( { type: "WEB_INVOKE_APPSERVICE", args: { data: t, webviewIds: i, }, }, "__uniapp__service" ); else { var w = JSON.stringify(t); plus.webview .getLaunchWebview() .evalJS( 'UniPlusBridge.subscribeHandler("' .concat("WEB_INVOKE_APPSERVICE", '",') .concat(w, ",") .concat(JSON.stringify(i), ");") ); } }, o = { navigateTo: function () { var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, n = e.url; a("navigateTo", { url: encodeURI(n), }); }, navigateBack: function () { var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, n = e.delta; a("navigateBack", { delta: parseInt(n) || 1, }); }, switchTab: function () { var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, n = e.url; a("switchTab", { url: encodeURI(n), }); }, reLaunch: function () { var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, n = e.url; a("reLaunch", { url: encodeURI(n), }); }, redirectTo: function () { var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}, n = e.url; a("redirectTo", { url: encodeURI(n), }); }, getEnv: function (e) { window.plus ? e({ plus: !0, }) : e({ h5: !0, }); }, postMessage: function () { var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}; a("postMessage", e.data || {}); }, }, r = /uni-app/i.test(navigator.userAgent), d = /Html5Plus/i.test(navigator.userAgent), s = /complete|loaded|interactive/; var w = window.my && navigator.userAgent.indexOf("AlipayClient") > -1; var u = window.swan && window.swan.webView && /swan/i.test(navigator.userAgent); var c = window.qq && window.qq.miniProgram && /QQ/i.test(navigator.userAgent) && /miniProgram/i.test(navigator.userAgent); var g = window.tt && window.tt.miniProgram && /toutiaomicroapp/i.test(navigator.userAgent); var v = window.wx && window.wx.miniProgram && /micromessenger/i.test(navigator.userAgent) && /miniProgram/i.test(navigator.userAgent); var p = window.qa && /quickapp/i.test(navigator.userAgent); for ( var l, _ = function () { (window.UniAppJSBridge = !0), document.dispatchEvent( new CustomEvent("UniAppJSBridgeReady", { bubbles: !0, cancelable: !0, }) ); }, f = [ function (e) { if (r || d) return ( window.__dcloud_weex_postMessage || window.__dcloud_weex_ ? document.addEventListener("DOMContentLoaded", e) : window.plus && s.test(document.readyState) ? setTimeout(e, 0) : document.addEventListener("plusready", e), o ); }, function (e) { if (v) return ( window.WeixinJSBridge && window.WeixinJSBridge.invoke ? setTimeout(e, 0) : document.addEventListener("WeixinJSBridgeReady", e), window.wx.miniProgram ); }, function (e) { if (c) return ( window.QQJSBridge && window.QQJSBridge.invoke ? setTimeout(e, 0) : document.addEventListener("QQJSBridgeReady", e), window.qq.miniProgram ); }, function (e) { if (w) { document.addEventListener("DOMContentLoaded", e); var n = window.my; return { navigateTo: n.navigateTo, navigateBack: n.navigateBack, switchTab: n.switchTab, reLaunch: n.reLaunch, redirectTo: n.redirectTo, postMessage: n.postMessage, getEnv: n.getEnv, }; } }, function (e) { if (u) return ( document.addEventListener("DOMContentLoaded", e), window.swan.webView ); }, function (e) { if (g) return ( document.addEventListener("DOMContentLoaded", e), window.tt.miniProgram ); }, function (e) { if (p) { window.QaJSBridge && window.QaJSBridge.invoke ? setTimeout(e, 0) : document.addEventListener("QaJSBridgeReady", e); var n = window.qa; return { navigateTo: n.navigateTo, navigateBack: n.navigateBack, switchTab: n.switchTab, reLaunch: n.reLaunch, redirectTo: n.redirectTo, postMessage: n.postMessage, getEnv: n.getEnv, }; } }, function (e) { return document.addEventListener("DOMContentLoaded", e), o; }, ], m = 0; m < f.length && !(l = f[m](_)); m++ ); l || (l = {}); var E = "undefined" != typeof webUni ? webUni : {}; if (!E.navigateTo) for (var b in l) t(l, b) && (E[b] = l[b]); return (E.webView = l), E; });
總結(jié)
到此這篇關(guān)于uni-app中App與webview雙向?qū)崟r(shí)通信的文章就介紹到這了,更多相關(guān)uni-app App與webview雙向?qū)崟r(shí)通信內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue監(jiān)聽某個(gè)元素以外的區(qū)域被點(diǎn)擊問題
這篇文章主要介紹了Vue監(jiān)聽某個(gè)元素以外的區(qū)域被點(diǎn)擊問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10詳解如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 vuex
本篇文章主要介紹了如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 vuex,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-02-02基于element-ui對(duì)話框el-dialog初始化的校驗(yàn)問題解決
這篇文章主要介紹了基于element-ui對(duì)話框el-dialog初始化的校驗(yàn)問題解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09vuex vue簡(jiǎn)單使用知識(shí)點(diǎn)總結(jié)
在本篇文章里小編給大家整理了關(guān)于vuex vue簡(jiǎn)單使用知識(shí)點(diǎn)總結(jié),有需要的朋友們可以參考下。2019-08-08利用vue組件實(shí)現(xiàn)圖片的拖拽和縮放功能
這篇文章主要給大家介紹了關(guān)于利用vue組件實(shí)現(xiàn)圖片的拖拽和縮放功能的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-01-01解決Vue.js由于延時(shí)顯示了{(lán){message}}引用界面的問題
今天小編就為大家分享一篇解決Vue.js由于延時(shí)顯示了{(lán){message}}引用界面的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-08-08