【uni-app】App与webview双向实时通信

news/2024/12/17 2:22:44/

uni-app】App与webview双向实时通信

在 Uniapp 中,App 与 里面嵌入的 webview 进行双向的实时通信

vue2 , 模拟器

主要分为两部分

  • webview 向 app 发送信息

  • app 向 webview 发送信息

以下是实现方式,用一个例子来说明

(文章最后我会放这个例子的github地址)

webview 向 app 发送信息

示例: webview 里面向 app 发送 图片的 base64 , app 保存图片到系统相册;

此处分为, app 和 webview 部分:

  • app 注册事件

  • webview 触发 app 的事件

app部分
  1. 保存到系统相册功能(功能具体细节不重要)

    // utils/appMessageHandler.js
    // 这里代码都在app下执行
    function appSaveImgFile(params) {const { base64, downloadName } = paramsconst 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,
    }
    
  2. 在App.vue中注册事件;将 appMessageHandle.js 里面所有导出的事件进行注册;注意需要条件编译

    // 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: {/*** 将所有导出的 app 事件* 用 map 建立 函数名 - 函数 的联系* 返回 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 获取的函数名* 通过 map 获取到函数,调用执行*/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 (文末附录放源码,我做了些许修改,逻辑没改,是一些变量调整了下) 的功能 postMessage , 向 app 发送图片生成的 base64;

  1. 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
    
  2. 生成的图片base64,通过以下方式发送给 app

    此处 action 与 上面 plusMessageHandler方法的 action 是对应的

    appSaveImgFile 与 appMessageHandler.js 里的函数名是对应的

    // 某个页面或者js
    this.$uWeb.postMessage({data: {action: "appSaveImgFile",params: {base64: imgBase64,downloadName,},},});
    

至此,webview 能随时向 app 发送消息了

在这里插入图片描述

App 向 webview 发送消息

使用 evalJS

分两步:

  1. webview 在 window 注册事件

  2. app 使用 evalJs 触发 webview 的事件

注意: 确保webview 先注册好事件之后,app发送的事件才能被 webview 接收到

具体实现,utils下新建appToWebview.js; appSendMessage 是给 App 用的;webviewGetMessage 是给 webview 注册用的

// appToWebview.js
// 发送信息之前,先要有 webviewGetMessage
function appSendMessage(_this, action, params) {const self = _this;self.currentWebview = self.$scope?.$getAppWebview()?.children()[0];//传递大量数据self.currentWebview?.evalJS(`${action}(${JSON.stringify(params)})`);
}function webviewGetMessage(action, callback) {// #ifdef H5window[action] = (data) => {let params = JSON.parse(JSON.stringify(data));callback(params);};// #endif
}export { appSendMessage, webviewGetMessage };
webview 部分

用 webviewGetMessage 注册一个 msgFromApp 名字的事件,给 App 调用;

  // 某个 webview 页面,created() {webviewGetMessage("msgFromApp", (params) => {console.log("getAppParams", params);this.appMsg = params;});},
App

用 appSendMessage 发送一个信息给 webview

  // 某个有 webview 的 app 页面,mounted() {setTimeout(() => {appSendMessage(this, "msgFromApp", { msgFromApp: 233 });}, 5000);},

在这里插入图片描述

至此,完成了 app 向 webview 发送信息

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;
});

http://www.ppmy.cn/news/1555741.html

相关文章

用OpenCV给图像加水印,为图像添加个性

一、引言 在数字时代&#xff0c;保护图片的版权和标识越来越重要。无论是企业的Logo&#xff0c;还是个人作品的水印&#xff0c;都可以有效地标记和保护图像内容。本篇博客将介绍如何使用OpenCV为图片添加水印或Logo。我们将通过简单的代码示例&#xff0c;帮助你快速掌握这…

Debezium OracleDefaultValueConverter 分析

Debezium OracleDefaultValueConverter 分析 目录 1. 概述2. 核心功能3. 类型映射4. 特殊处理5. 最佳实践6. 使用示例7. 总结1. 概述 OracleDefaultValueConverter 是 Debezium Oracle 连接器中负责处理列默认值转换的核心类。它主要用于将 Oracle 数据库中的列默认值转换为 …

Linux系统操作03|chmod、vim

上文&#xff1a; Linux系统操作02|基本命令-CSDN博客 目录 六、chmod&#xff1a;给文件设置权限 1、字母法 2、数字法&#xff08;用的最多&#xff09; 七、vim&#xff1a;代码编写和文本编辑 1、启动和退出 1️⃣启动 2️⃣退出 2、vim基本操作 六、chmod&#x…

基于单片机和测频法的频率计设计及proteus仿真

摘要: 传感器广泛应用在自动化测量中,该文利用 51 单片机 2 个 16 位定时器和测量频率中的测频法设计了测量方波的频率计,并用LCD1602 液晶显示频率、 proteus 仿真,测试结果表明设计思路正确、误差小。 关键词: 单片机;测频法;频率计; proteus 1 概述 传感器能感受到…

《Vue进阶教程》第七课:computed()函数详解(下)

往期内容&#xff1a; 《Vue零基础入门教程》合集&#xff08;完结&#xff09; 《Vue进阶教程》第一课&#xff1a;什么是组合式API 《Vue进阶教程》第二课&#xff1a;为什么提出组合式API 《Vue进阶教程》第三课&#xff1a;Vue响应式原理 《Vue进阶教程》第四课&#…

我在广州学 Mysql 系列之 数据“表”的基本操作

ℹ️大家好&#xff0c;我是&#x1f606;练小杰&#xff0c;今天主要讲得是Mysql数据表的基本操作内容~~ 昨天讲了“Mysql 数据“库“的基本操作”~~ 想要了解更多&#x1f236;️MYSQL 数据库的命令行总结&#xff01;&#xff01;&#xff01; “真相永远只有一个”——工藤…

【Redis】Redis 缓存更新策略

1. 更新策略三种方式 缓存更新是redis为了节约内存而设计出来的一个东西&#xff0c;主要是因为内存数据宝贵&#xff0c;当我们向redis插入太多数据&#xff0c;此时就可能会导致缓存中的数据过多&#xff0c;所以redis会对部分数据进行更新&#xff0c;或者把他叫为淘汰更合…

私有云dbPaaS为何被Gartner技术成熟度曲线标记为“废弃”?

当云计算席卷而来&#xff0c;基于云基础设施的数据库部署也改变了数据库。在传统的私有化部署&#xff08;On-premises&#xff09;和公有云部署&#xff08;Public Cloud&#xff09;之间&#xff0c;不断融合的混合IT&#xff08;Mixed IT&#xff09;形式成为最常见的企业级…