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

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

码农世界 2024-06-05 前端 94 次浏览 0个评论

【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 } = 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,
        }
        
      2. 在App.vue中注册事件;将 appMessageHandle.js 里面所有导出的事件进行注册;注意需要条件编译

        // App.vue
        
        

      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 H5
        window[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;
      });
      

转载请注明来自码农世界,本文标题:《【uni-app】App与webview双向实时通信》

百度分享代码,如果开启HTTPS请参考李洋个人博客
每一天,每一秒,你所做的决定都会改变你的人生!

发表评论

快捷回复:

评论列表 (暂无评论,94人围观)参与讨论

还没有评论,来说两句吧...

Top