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 () } } 复制代码
TODO
可以在postMessage中加一个字段id,每次处理完后,记录上次处理的最后一条消息的id,下次处理从那条消息之后处理