
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,下次處理從那條消息之后處理