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

打印 上一主题 下一主题

主题 873|帖子 873|积分 2619

【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
    2. // 这里代码都在app下执行
    3. function appSaveImgFile(params) {
    4.   const { base64, downloadName } = params
    5.   const bitmap = new plus.nativeObj.Bitmap("test");
    6.   bitmap.loadBase64Data(
    7.     base64,
    8.     function () {
    9.       const url = "_doc/" + downloadName + ".png"; // url为时间戳命名方式
    10.       bitmap.save(
    11.         url,
    12.         {
    13.           overwrite: true, // 是否覆盖
    14.           // quality: 'quality'  // 图片清晰度
    15.         },
    16.         (i) => {
    17.           plus.gallery.save(
    18.             i.target,
    19.             function () {
    20.               uni.showToast({
    21.                 title: "APP图片保存至相册",
    22.                 icon: "none",
    23.               });
    24.               bitmap.clear();
    25.             },
    26.             function (e) {
    27.               uni.showToast({
    28.                 title: "APP图片保存至相册失败:" + JSON.stringify(e),
    29.                 icon: "none",
    30.               });
    31.               bitmap.clear();
    32.             }
    33.           );
    34.         },
    35.         (e) => {
    36.           uni.showToast({
    37.             title: "图片保存失败1:" + JSON.stringify(e),
    38.             icon: "none",
    39.           });
    40.           bitmap.clear();
    41.         }
    42.       );
    43.     },
    44.     (e) => {
    45.       uni.showToast({
    46.         title: "图片保存失败2:" + JSON.stringify(e),
    47.         icon: "none",
    48.       });
    49.       bitmap.clear();
    50.     }
    51.   );
    52. }
    53. export {
    54.   appSaveImgFile,
    55. }
    复制代码
  • 在App.vue中注册事件;将 appMessageHandle.js 里面所有导出的事件进行注册;留意需要条件编译
    1. // App.vue
    2. <script>
    3. import * as appPlusMessageHandler from "./utils/appMessageHandler";
    4. export default {
    5.   data() {
    6.     return {
    7.       appRegisterMap: undefined,
    8.     };
    9.   },
    10.   onLaunch: function () {
    11.     console.log("App Launch");
    12.     // #ifdef APP-PLUS
    13.     // 注册事件
    14.     plus.globalEvent.addEventListener("plusMessage", this.plusMessageHandler);
    15.     // #endif
    16.   },
    17.   methods: {
    18.     /**
    19.      * 将所有导出的 app 事件
    20.      * 用 map 建立 函数名 - 函数 的联系
    21.      * 返回 map
    22.      */
    23.     registerAppPlusMap() {
    24.       if (this.appRegisterMap) {
    25.         return this.appRegisterMap;
    26.       }
    27.       let map = new Map();
    28.       Object.keys(appPlusMessageHandler).forEach((item) => {
    29.         map.set(item, appPlusMessageHandler[item]);
    30.       });
    31.       this.appRegisterMap = map;
    32.       return map;
    33.     },
    34.     /**
    35.      * 用 action 获取的函数名
    36.      * 通过 map 获取到函数,调用执行
    37.      */
    38.     plusMessageHandler(msg) {
    39.       let map = this.registerAppPlusMap();
    40.       if (msg.data.args.data.arg?.action) {
    41.         let handler = map.get(msg.data.args.data.arg?.action);
    42.         let params = msg.data.args.data.arg?.params;
    43.         handler && handler(params);
    44.       }
    45.     },
    46.   },
    47. };
    48. </script>
    复制代码
webview 部分

通过使用 uni.webview.js (文末附录放源码,我做了些许修改,逻辑没改,是一些变量调解了下) 的功能 postMessage , 向 app 发送图片生成的 base64;

  • main.js 中挂载 uWeb (uni.webview.js)
    1. // main.js
    2. // 全局添加uWeb
    3. // #ifdef H5
    4. import uWeb from "@/utils/uni.webview.js";
    5. // #endif
    6. // #ifdef H5
    7. Vue.prototype.$uWeb = uWeb;
    8. // #endif
    复制代码
  • 生成的图片base64,通过以下方式发送给 app
    此处 action 与 上面 plusMessageHandler方法的 action 是对应的
    appSaveImgFile 与 appMessageHandler.js 里的函数名是对应的
    1. // 某个页面或者js
    2. this.$uWeb.postMessage({
    3.         data: {
    4.           action: "appSaveImgFile",
    5.           params: {
    6.             base64: imgBase64,
    7.             downloadName,
    8.           },
    9.         },
    10.       });
    复制代码
至此,webview 能随时向 app 发送消息了

App 向 webview 发送消息

使用 evalJS
分两步:

  • webview 在 window 注册事件
  • app 使用 evalJs 触发 webview 的事件
留意: 确保webview 先注册好事件之后,app发送的事件才能被 webview 接收到
具体实现,utils下新建appToWebview.js; appSendMessage 是给 App 用的;webviewGetMessage 是给 webview 注册用的
  1. // appToWebview.js
  2. // 发送信息之前,先要有 webviewGetMessage
  3. function appSendMessage(_this, action, params) {
  4.   const self = _this;
  5.   self.currentWebview = self.$scope?.$getAppWebview()?.children()[0];
  6.   //传递大量数据
  7.   self.currentWebview?.evalJS(`${action}(${JSON.stringify(params)})`);
  8. }
  9. function webviewGetMessage(action, callback) {
  10.   // #ifdef H5
  11.   window[action] = (data) => {
  12.     let params = JSON.parse(JSON.stringify(data));
  13.     callback(params);
  14.   };
  15.   // #endif
  16. }
  17. export { appSendMessage, webviewGetMessage };
复制代码
webview 部分

用 webviewGetMessage 注册一个 msgFromApp 名字的事件,给 App 调用;
  1.   // 某个 webview 页面,
  2.   created() {
  3.     webviewGetMessage("msgFromApp", (params) => {
  4.       console.log("getAppParams", params);
  5.       this.appMsg = params;
  6.     });
  7.   },
复制代码
App

用 appSendMessage 发送一个信息给 webview
  1.   // 某个有 webview 的 app 页面,
  2.   mounted() {
  3.     setTimeout(() => {
  4.       appSendMessage(this, "msgFromApp", { msgFromApp: 233 });
  5.     }, 5000);
  6.   },
复制代码

至此,完成了 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

  1. !(function (e, n) {
  2.   "object" == typeof exports && "undefined" != typeof module
  3.     ? (module.exports = n())
  4.     : "function" == typeof define && define.amd
  5.     ? define(n)
  6.     : ((e = e || self).webUni = n());
  7. })(this, function () {
  8.   "use strict";
  9.   try {
  10.     var e = {};
  11.     Object.defineProperty(e, "passive", {
  12.       get: function () {
  13.         !0;
  14.       },
  15.     }),
  16.       window.addEventListener("test-passive", null, e);
  17.   } catch (e) {}
  18.   var n = Object.prototype.hasOwnProperty;
  19.   function t(e, t) {
  20.     return n.call(e, t);
  21.   }
  22.   var i = [],
  23.     a = function (e, n) {
  24.       var t = {
  25.         options: {
  26.           timestamp: +new Date(),
  27.         },
  28.         name: e,
  29.         arg: n,
  30.       };
  31.       if (window.__dcloud_weex_postMessage || window.__dcloud_weex_) {
  32.         if ("postMessage" === e) {
  33.           var a = {
  34.             data: [n],
  35.           };
  36.           return window.__dcloud_weex_postMessage
  37.             ? window.__dcloud_weex_postMessage(a)
  38.             : window.__dcloud_weex_.postMessage(JSON.stringify(a));
  39.         }
  40.         var o = {
  41.           type: "WEB_INVOKE_APPSERVICE",
  42.           args: {
  43.             data: t,
  44.             webviewIds: i,
  45.           },
  46.         };
  47.         window.__dcloud_weex_postMessage
  48.           ? window.__dcloud_weex_postMessageToService(o)
  49.           : window.__dcloud_weex_.postMessageToService(JSON.stringify(o));
  50.       }
  51.       if (!window.plus)
  52.         return window.parent.postMessage(
  53.           {
  54.             type: "WEB_INVOKE_APPSERVICE",
  55.             data: t,
  56.             pageId: "",
  57.           },
  58.           "*"
  59.         );
  60.       if (0 === i.length) {
  61.         var r = plus.webview.currentWebview();
  62.         if (!r) throw new Error("plus.webview.currentWebview() is undefined");
  63.         var d = r.parent(),
  64.           s = "";
  65.         (s = d ? d.id : r.id), i.push(s);
  66.       }
  67.       if (plus.webview.getWebviewById("__uniapp__service"))
  68.         plus.webview.postMessageToUniNView(
  69.           {
  70.             type: "WEB_INVOKE_APPSERVICE",
  71.             args: {
  72.               data: t,
  73.               webviewIds: i,
  74.             },
  75.           },
  76.           "__uniapp__service"
  77.         );
  78.       else {
  79.         var w = JSON.stringify(t);
  80.         plus.webview
  81.           .getLaunchWebview()
  82.           .evalJS(
  83.             'UniPlusBridge.subscribeHandler("'
  84.               .concat("WEB_INVOKE_APPSERVICE", '",')
  85.               .concat(w, ",")
  86.               .concat(JSON.stringify(i), ");")
  87.           );
  88.       }
  89.     },
  90.     o = {
  91.       navigateTo: function () {
  92.         var e =
  93.             arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
  94.           n = e.url;
  95.         a("navigateTo", {
  96.           url: encodeURI(n),
  97.         });
  98.       },
  99.       navigateBack: function () {
  100.         var e =
  101.             arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
  102.           n = e.delta;
  103.         a("navigateBack", {
  104.           delta: parseInt(n) || 1,
  105.         });
  106.       },
  107.       switchTab: function () {
  108.         var e =
  109.             arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
  110.           n = e.url;
  111.         a("switchTab", {
  112.           url: encodeURI(n),
  113.         });
  114.       },
  115.       reLaunch: function () {
  116.         var e =
  117.             arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
  118.           n = e.url;
  119.         a("reLaunch", {
  120.           url: encodeURI(n),
  121.         });
  122.       },
  123.       redirectTo: function () {
  124.         var e =
  125.             arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {},
  126.           n = e.url;
  127.         a("redirectTo", {
  128.           url: encodeURI(n),
  129.         });
  130.       },
  131.       getEnv: function (e) {
  132.         window.plus
  133.           ? e({
  134.               plus: !0,
  135.             })
  136.           : e({
  137.               h5: !0,
  138.             });
  139.       },
  140.       postMessage: function () {
  141.         var e =
  142.           arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
  143.         a("postMessage", e.data || {});
  144.       },
  145.     },
  146.     r = /uni-app/i.test(navigator.userAgent),
  147.     d = /Html5Plus/i.test(navigator.userAgent),
  148.     s = /complete|loaded|interactive/;
  149.   var w = window.my && navigator.userAgent.indexOf("AlipayClient") > -1;
  150.   var u =
  151.     window.swan && window.swan.webView && /swan/i.test(navigator.userAgent);
  152.   var c =
  153.     window.qq &&
  154.     window.qq.miniProgram &&
  155.     /QQ/i.test(navigator.userAgent) &&
  156.     /miniProgram/i.test(navigator.userAgent);
  157.   var g =
  158.     window.tt &&
  159.     window.tt.miniProgram &&
  160.     /toutiaomicroapp/i.test(navigator.userAgent);
  161.   var v =
  162.     window.wx &&
  163.     window.wx.miniProgram &&
  164.     /micromessenger/i.test(navigator.userAgent) &&
  165.     /miniProgram/i.test(navigator.userAgent);
  166.   var p = window.qa && /quickapp/i.test(navigator.userAgent);
  167.   for (
  168.     var l,
  169.       _ = function () {
  170.         (window.UniAppJSBridge = !0),
  171.           document.dispatchEvent(
  172.             new CustomEvent("UniAppJSBridgeReady", {
  173.               bubbles: !0,
  174.               cancelable: !0,
  175.             })
  176.           );
  177.       },
  178.       f = [
  179.         function (e) {
  180.           if (r || d)
  181.             return (
  182.               window.__dcloud_weex_postMessage || window.__dcloud_weex_
  183.                 ? document.addEventListener("DOMContentLoaded", e)
  184.                 : window.plus && s.test(document.readyState)
  185.                 ? setTimeout(e, 0)
  186.                 : document.addEventListener("plusready", e),
  187.               o
  188.             );
  189.         },
  190.         function (e) {
  191.           if (v)
  192.             return (
  193.               window.WeixinJSBridge && window.WeixinJSBridge.invoke
  194.                 ? setTimeout(e, 0)
  195.                 : document.addEventListener("WeixinJSBridgeReady", e),
  196.               window.wx.miniProgram
  197.             );
  198.         },
  199.         function (e) {
  200.           if (c)
  201.             return (
  202.               window.QQJSBridge && window.QQJSBridge.invoke
  203.                 ? setTimeout(e, 0)
  204.                 : document.addEventListener("QQJSBridgeReady", e),
  205.               window.qq.miniProgram
  206.             );
  207.         },
  208.         function (e) {
  209.           if (w) {
  210.             document.addEventListener("DOMContentLoaded", e);
  211.             var n = window.my;
  212.             return {
  213.               navigateTo: n.navigateTo,
  214.               navigateBack: n.navigateBack,
  215.               switchTab: n.switchTab,
  216.               reLaunch: n.reLaunch,
  217.               redirectTo: n.redirectTo,
  218.               postMessage: n.postMessage,
  219.               getEnv: n.getEnv,
  220.             };
  221.           }
  222.         },
  223.         function (e) {
  224.           if (u)
  225.             return (
  226.               document.addEventListener("DOMContentLoaded", e),
  227.               window.swan.webView
  228.             );
  229.         },
  230.         function (e) {
  231.           if (g)
  232.             return (
  233.               document.addEventListener("DOMContentLoaded", e),
  234.               window.tt.miniProgram
  235.             );
  236.         },
  237.         function (e) {
  238.           if (p) {
  239.             window.QaJSBridge && window.QaJSBridge.invoke
  240.               ? setTimeout(e, 0)
  241.               : document.addEventListener("QaJSBridgeReady", e);
  242.             var n = window.qa;
  243.             return {
  244.               navigateTo: n.navigateTo,
  245.               navigateBack: n.navigateBack,
  246.               switchTab: n.switchTab,
  247.               reLaunch: n.reLaunch,
  248.               redirectTo: n.redirectTo,
  249.               postMessage: n.postMessage,
  250.               getEnv: n.getEnv,
  251.             };
  252.           }
  253.         },
  254.         function (e) {
  255.           return document.addEventListener("DOMContentLoaded", e), o;
  256.         },
  257.       ],
  258.       m = 0;
  259.     m < f.length && !(l = f[m](_));
  260.     m++
  261.   );
  262.   l || (l = {});
  263.   var E = "undefined" != typeof webUni ? webUni : {};
  264.   if (!E.navigateTo) for (var b in l) t(l, b) && (E[b] = l[b]);
  265.   return (E.webView = l), E;
  266. });
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

九天猎人

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表