import { ensureJssdkReady, normalizeJssdkPageUrl } from './jssdk'; import { getRuntimePlatform, isWechatBrowser } from './env'; import type { WeixinSdkConfig } from './types'; export type WechatShareData = { title: string; desc: string; link: string; imgUrl: string; }; export function canUseWechatShare(): boolean { return isWechatBrowser() || getRuntimePlatform() === 'mini'; } function applyShareData(data: WechatShareData): Promise { return new Promise((resolve, reject) => { const wx = window.wx as | (NonNullable & { onMenuShareAppMessage?: (opts: Record) => void; onMenuShareTimeline?: (opts: Record) => void; invoke?: ( api: string, params: Record, cb?: (res: { err_msg?: string; errMsg?: string }) => void, ) => void; }) | undefined; if (!wx) { reject(new Error('微信 JSSDK 不可用')); return; } let pending = 0; let failed = false; const done = (err?: Error) => { if (err && !failed) { failed = true; reject(err); return; } pending -= 1; if (pending === 0 && !failed) resolve(); }; const payload = { title: data.title, desc: data.desc, link: data.link, imgUrl: data.imgUrl, }; if (wx.updateAppMessageShareData) { pending += 1; wx.updateAppMessageShareData({ ...payload, success: () => done(), fail: (res) => done(new Error(res.errMsg || '设置分享给朋友失败')), }); } if (wx.updateTimelineShareData) { pending += 1; wx.updateTimelineShareData({ title: data.title, link: data.link, imgUrl: data.imgUrl, success: () => done(), fail: (res) => done(new Error(res.errMsg || '设置分享到朋友圈失败')), }); } // 兼容旧微信:同时挂旧版菜单分享(设置即生效,无 success 回调也可继续) if (wx.onMenuShareAppMessage) { wx.onMenuShareAppMessage({ ...payload, success: () => {}, cancel: () => {}, }); } if (wx.onMenuShareTimeline) { wx.onMenuShareTimeline({ title: data.title, link: data.link, imgUrl: data.imgUrl, success: () => {}, cancel: () => {}, }); } if (pending === 0) { if (wx.onMenuShareAppMessage || wx.onMenuShareTimeline) { resolve(); return; } reject(new Error('当前微信版本不支持分享,请升级微信后重试')); } }); } /** 尽量调起系统分享面板(部分微信版本支持;失败则仅完成卡片配置) */ export function tryInvokeSharePanel(data: WechatShareData): Promise { return new Promise((resolve) => { const wx = window.wx as | { invoke?: ( api: string, params: Record, cb?: (res: { err_msg?: string; errMsg?: string }) => void, ) => void; } | undefined; if (!wx?.invoke) { resolve(false); return; } try { wx.invoke( 'shareAppMessage', { title: data.title, desc: data.desc, link: data.link, img_url: data.imgUrl, imgUrl: data.imgUrl, }, (res) => { const msg = `${res?.err_msg || res?.errMsg || ''}`; resolve(/:ok\b/i.test(msg)); }, ); } catch { resolve(false); } }); } /** 配置微信内分享卡片(好友 / 朋友圈) */ export async function setWechatShareData( config: WeixinSdkConfig, data: WechatShareData, ): Promise { if (!canUseWechatShare()) return; await ensureJssdkReady({ apiBase: config.apiBase ?? '/api/v1', clientApp: config.clientApp, getAccessToken: config.getAccessToken, }); await applyShareData(data); } /** * 配置分享并尝试调起分享面板。 * @returns invoked=true 表示已弹出系统分享;否则需引导用户点右上角 */ export async function shareViaWechatSdk( config: WeixinSdkConfig, data: WechatShareData, ): Promise<{ invoked: boolean }> { await setWechatShareData(config, data); const invoked = await tryInvokeSharePanel(data); return { invoked }; } /** 获取当前页分享链接(去掉 hash、OAuth 回跳参数) */ export function getWechatShareLink(rawUrl?: string): string { if (typeof window === 'undefined') return rawUrl ?? ''; return normalizeJssdkPageUrl(rawUrl ?? window.location.href); }