您现在的位置: 微信小程序 > 微信小程序运营 > 经验 >

小程序webview分享

来源:微信小程序 编辑:Yiyongtong.com 发布时间:2020-05-18 11:03热度:

webview中的h5页面做某些操作后需要修改当前的分享页面,但是,此时H5页面的链接没有改变。需要有一个机制通知小程序页面要修改分享参数了。

技术解决

根据小程序文档,支持webview中页面以postMessage的形式向小程序通信(仅在分享,返回等特殊操作时,才触发)

要点:

  • 使用wx.miniProgram.postMessage向小程序通信,当用户转发时页面可以监听到消息
  • 页面监听到的消息为历史列表,且不清除,需要自行处理
  • 小程序页面设置了onShareAppMessage可以支持分享,默认分享为当前页面
  • 用户点击转发后,会先触发webview的onMessage,再调用onShareAppMessage设置分享配置

h5和小程序约定的postMessage消息格式:

{
    type:'消息类型',//setShareOption
    ...restData // 其他参数
}
复制代码

h5页面设置分享参数:

/**
 * 设置weapp分享链接
 * @param option 
 * @example setWeappShareOption({title:"分享标题",path:"分享链接",imageUrl:'分享图片可为空'})
 */
export function setWeappShareOption(option:{title:string,path:string,imageUrl:string}){
    if(window['wx'] && window['wx'].miniProgram && window['wx'].miniProgram.postMessage){
        window['wx'].miniProgram.postMessage({
            type:'setShareOption',
            title:option.title,
            path:option.path,
            imageUrl:option.imageUrl
        });
    }
}
复制代码

小程序页面支持分享:

 

import Taro from '@tarojs/taro'
import { WebView } from '@tarojs/components'
import {
  getCurrentChannelEventHash,
  resetChannelHash,
} from './WebViewHashChannelData'
import { unpackUrl,packUrl } from '../../src/core/UrlHelper'

const DEFAULT_WEB_PATH = 'https://xxx.x.com/xxx' // to 参数默认的域名前缀
/**
 * 小程序Page页面
 * @param to 要跳转的h5页面地址 e.g:/xxx/xxx or 完整地址 https://xxx....
 * @param title 要跳转的h5页面标题
 */
export default class H5WebView extends Taro.Component {
  config = {
    navigationBarTitleText: ' ',
  }

  state = {
    url: '', // url不支持Hash
    hash: '',
  }

  isBack = false

  shareOption = {
    title: null,
    path: null,
  }

  componentWillMount() {
    this.isBack = false
    const to = decodeURIComponent(this.$router.params.to || '')
    const urlObj = unpackUrl(to)
    let url = urlObj.pathWithSearch
    let hash = urlObj.hash
    let title = this.$router.params.title
    if (title) {
      title = decodeURIComponent(title)
      Taro.setNavigationBarTitle({ title: title })
    }
    this.setState({
      url,
      hash,
    })
    console.log('[H5WebView] mount', url, hash)
  }

  componentDidShow() {
    // onShow
    if (this.isBack) {
      // 小程序页面回退,通知h5
      let channelEventHash = getCurrentChannelEventHash()
      // if (!channelEventHash) {// TODO 仅白名单的页面增加backPush 通过postMessage??
      //     channelEventHash = getBackEventHash();// 通知游戏,上层的Page 移走了
      // }
      this.setState({
        hash: channelEventHash,
      })
      // 通知完毕 重置
      resetChannelHash()
      console.log('[H5WebView] show set hash', channelEventHash, this.state.url)
    } else {
      console.log('[H5WebView] show first')
    }
    this.isBack = true
  }
 
  _getLastData(itemList, type) {
    if (!itemList || itemList.length === 0) {
      return null
    }
    let lastIdx = itemList.length - 1
    while (lastIdx >= 0) {
      let item = itemList[lastIdx]
      if (item && item.type === type) {
        return item
      }
    }
  }
  handleMessage(e) {
    let { data } = e.detail
    // 设置最后一条share
    let shareOption = this._getLastData(data, 'setShareOption')
    if (shareOption) {
      this.shareOption = {
        title: shareOption.title,
        imageUrl: shareOption.imageUrl,
        path: shareOption.path,
      }
    }
    console.log('withWV handleMessage', data)
  }

  /**
   * 支持分享消息
   */
  onShareAppMessage() {
    if (this.shareOption) {
      let path = null
      if (this.shareOption.path) {
        path = packUrl(this.$router.path, {
          to: this.shareOption.path,
          title: this.shareOption.title,
        })
      }
      return {
        title: this.shareOption.title,
        path,
        imageUrl: this.shareOption.imageUrl,
      }
    }
  }

  onWebViewLoad(e) {
    console.log('withWV onWebViewLoad', e.detail.src, this.state.hash)
    this.shareOption.path = e.detail.src //默认分享页面为当前页面
  }

  _normalizeTo() {
    let to = this.state.url
    if (!to) {
      return null
    }
    if (to.substr(0, 4) !== 'http') {
      to = DEFAULT_WEB_PATH + to
    }
    if (this.state.hash) {
      to += '#' + this.state.hash
    }
    return to
  }

  render() {
    let to = this._normalizeTo()
    if (!to) {
      return null
    }
    return (
      <WebView
        src={to}
        onMessage={this.handleMessage}
        onLoad={this.onWebViewLoad}
      />
    )
  }
}

复制代码

TODO

可以在postMessage中加一个字段id,每次处理完后,记录上次处理的最后一条消息的id,下次处理从那条消息之后处理