加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 资源网站 > 资源 > 正文

微信小程序 webview 与 h5 实时通讯的实现

发布时间:2020-12-14 19:12:06 所属栏目:资源 来源:网络整理
导读:在做 React Native 应用时,如果需要在 App 里面内嵌 H5 页面,那么 H5 与 App 之间可以通过 Webview 的 PostMessage 功能实现实时的通讯,但是在小程序里面,虽然也提供了一个 webview ?组件,但是,在进行 postMessage ?通讯时,官方文档里面给出了一条很

在做 React Native 应用时,如果需要在 App 里面内嵌 H5 页面,那么 H5 与 App 之间可以通过 Webview 的 PostMessage 功能实现实时的通讯,但是在小程序里面,虽然也提供了一个 webview?组件,但是,在进行 postMessage?通讯时,官方文档里面给出了一条很变态的说明:

网页向小程序 postMessage?时,会在特定时机(小程序后退、组件销毁、分享)触发并收到消息。 e.detail = { data }?, data?是多次 postMessage?的参数组成的数组

这里面已经说的很明白了,不管我们从 H5 页面里面 postMessage?多少次,小程序都是收不到的,除非:

  1. 用户做了回退到上一页的操作
  2. 组件销毁
  3. 用户点击了分享

这里面其实我没有完全说对,官方其实说的是 小程序后退?,并没有说是用户做回退操作,经过我的实测,确实人家表达得很清楚了,我们通过微信官方的SDK调起的回退也是完全可行的:

wx.miniProgram.navigateBack()

大体思路

从上面的分析和实测中我们可以知道,要实现无需要用户操作即可完成的通讯,第三种情况我们是完全不需要考虑了的,那么来仔细考虑第 1 和第 2 种场景。

第 1 种方式:回退

当我们想通过网页向小程序发送数据,同时还可以回退到上一个页面时,我们可以在 wx.miniProgram.postMessage?之后,立马调用一次 wx.miniProgram.navigateBack()?,此时小程序的操作是:

postMessage

我们在处理 postMessage?的时候做一些特殊操作,可以将这些数据保存下来

第 2 种方式:组件销毁

这是我感觉最合适的一种方式,可以让小程序拿到数据,同时还保留在当前页面,只需要销毁一次 webview?即可,大概的流程就是:

  1. 小程序 postMessage
  2. 小程序 navigateTo?将小程序页面导向一个特殊的页面
  3. 小程序的那个特殊页面立马回退到 webview?所在的页面
  4. webview?所在的页面的 onShow?里面,做一次处理,将 webview?销毁,然后再次打开
  5. 触发 onMessage?拿到数据
  6. H5 页面再次被打开

这种方式虽然变态,但是至少可以做到实时拿到数据,同时还保留在当前 H5 页面,唯一需要解决的是,在做这整套操作前,H5 页面需要做好状态的缓存,要不然,再次打开之后,H5 的数据就清空了。

第 1 种方式:通过回退,将数据提交给小程序之后传递给 webview?的上一页面

这种方式实现起来其实是很简单的,我们现在新建两个页面:

sandbox/canvas-by-webapp/index.js

const app = getApp();

Page({
  data: {
    url: '',dimension: null,mime: handleSaveTap: function() {
    wx.navigateTo({
      url: '/apps/browser/index',events: {
        receiveData: data => {
          console.log('receiveData from web browser: ',data);
          if (typeof data === 'object') {
            const { url,mime,dimension } = data;
            if (url && mime && dimension) {
              this.setData({
                url,dimension,});

              this.save(data);
            }
          }
        }
      }
    })
  },save: async function({ url,dimension }) {
    try {
      await app.saveImages([url]);
      app.toast('保存成功!');
    } catch (error) {
      console.log(error);
      app.toast(error.message || error);
    }
  },});

上面的代码中,核心点,就在于 wx.navigateTo?调用时,里面的 events?参数,这是用来进行与 /apps/browser/index?页面通讯,接收数据用的。

apps/browser/index.js

我省略了绝大多数与本文无关的代码,保存最主要的三个:

Page({
  onLoad() {
    this.getOpenerEventChannel) {
      this.eventChannel = this.getOpenerEventChannel();
    }
  },handleMessage: function(message) {
    const { action,data } = message;
    if (action === 'postData') {
      this.eventChannel) {
        this.eventChannel.emit('receiveData',51); font-weight: 700;">data);
      }
    }
  },handlePostMessage: function(e) {
    const { data } = e.detail;
    if (Array.isArray(data)) {
      const messages = data.map(item => {
        try {
          const object = JSON.parse(item);
          this.handleMessage(object);
          return object;
        } catch (error) {
          return item;
        }
      });

      this.setData({
        messages: [...messages],});
    }
  },})

其实, onLoad?方法中,我们使用了自微信 SDK 2.7.3?版本开始提供的 getOpenerEventChannel?方法,它可以创建一个与上一个页面的事件通讯通道,这个我们会在 handleMessage?中使用。

handlePostMessage?就是被 bindmessage?至 webview?上面的方法,它用于处理从 H5 页面中 postMessage?过来的消息,由于小程序是将多次 postMessage?的消息放在一起发送过来的,所以,与其它的Webview不同点在于,我们拿到的是一个数组: e.detail.data?, handlePostMessage的作用就是遍历这个数组,取出每一条消息,然后交由 handleMessage?处理。

handleMessage?在拿到 message?对象之后,将 message.action?与 message.data?取出来(*这里需要注意,这是我们在 H5 里面的设计的一种数据结构,你完全可以在自己的项目中设计自己的结构),根据 action?作不同的操作,我在这里面的处理是,当 action === 'postData'?时,就通过 getOpenerEventChannel?得到的消息通道 this.eventChannel?将数据推送给上一级页面,也就是 /sandbox/canvas-by-webapp?,但是不需要自己执行 navigateBack?,因为这个需要交由H5?页面去执行。

H5 页面的实现

我的 H5 主要就是使用 html2canvas?库生成 Canvas 图(没办法,自己在小程序里面画太麻烦了),但是这个不在本文讨论过程中,我们就当是已经生成了 canvas?图片了,将其转为 base64文本了,然后像下面这样做:

,data: 'BASE 64 IMAGE STRING'
  })
});

.navigateBack()

将数据 postMessage?之后,立即 navigateBack()?,来触发一次回退,也就触发了 bindmessage?事件。

使用销毁 webview?实现实时通讯

接下来,咱就开始本文的重点了,比较变态的方式,但是也没想到更好的办法,所以,大家将就着交流吧。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读