uni-app中App與webview雙向?qū)崟r通信詳細代碼示例
在 Uniapp 中,App 與 里面嵌入的 webview 進行雙向的實時通信
vue2 , 模擬器
主要分為兩部分
webview 向 app 發(fā)送信息
app 向 webview 發(fā)送信息
以下是實現(xiàn)方式,用一個例子來說明
(文章最后我會放這個例子的github地址)
webview 向 app 發(fā)送信息
示例: webview 里面向 app 發(fā)送 圖片的 base64 , app 保存圖片到系統(tǒng)相冊;
此處分為, app 和 webview 部分:
app 注冊事件
webview 觸發(fā) app 的事件
app部分
保存到系統(tǒng)相冊功能(功能具體細節(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為時間戳命名方式 bitmap.save( url, { overwrite: true, // 是否覆蓋 // quality: 'quality' // 圖片清晰度 }, (i) => { plus.gallery.save( i.target, function () { uni.showToast({ title: "APP圖片保存至相冊", icon: "none", }); bitmap.clear(); }, function (e) { uni.showToast({ title: "APP圖片保存至相冊失敗:" + 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中注冊事件;將 appMessageHandle.js 里面所有導(dǎo)出的事件進行注冊;注意需要條件編譯
// App.vue <script> import * as appPlusMessageHandler from "./utils/appMessageHandler"; export default { data() { return { appRegisterMap: undefined, }; }, onLaunch: function () { console.log("App Launch"); // #ifdef APP-PLUS // 注冊事件 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 是對應(yīng)的
appSaveImgFile 與 appMessageHandler.js 里的函數(shù)名是對應(yīng)的
// 某個頁面或者js this.$uWeb.postMessage({ data: { action: "appSaveImgFile", params: { base64: imgBase64, downloadName, }, }, });
至此,webview 能隨時向 app 發(fā)送消息了

App 向 webview 發(fā)送消息
使用 evalJS
分兩步:
webview 在 window 注冊事件
app 使用 evalJs 觸發(fā) webview 的事件
注意: 確保webview 先注冊好事件之后,app發(fā)送的事件才能被 webview 接收到
具體實現(xiàn),utils下新建appToWebview.js; appSendMessage 是給 App 用的;webviewGetMessage 是給 webview 注冊用的
// 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 注冊一個 msgFromApp 名字的事件,給 App 調(diào)用;
// 某個 webview 頁面,
created() {
webviewGetMessage("msgFromApp", (params) => {
console.log("getAppParams", params);
this.appMsg = params;
});
},
App
用 appSendMessage 發(fā)送一個信息給 webview
// 某個有 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 項目,app 和 用到的 h5 地址是同一個項目下的
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通信的文章就介紹到這了,更多相關(guān)uni-app App與webview雙向?qū)崟r通信內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于element-ui對話框el-dialog初始化的校驗問題解決
這篇文章主要介紹了基于element-ui對話框el-dialog初始化的校驗問題解決,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09
解決Vue.js由于延時顯示了{{message}}引用界面的問題
今天小編就為大家分享一篇解決Vue.js由于延時顯示了{{message}}引用界面的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08

