import Taro from '@tarojs/taro'; import { captureIosJssdkEntryUrl } from '@dukang/weixin-sdk'; import { useEffect, useRef } from 'react'; import { finishLoginNavigate, forceReloadAfterAccountMerge, goLogin } from '../lib/auth-nav'; import { toast } from '../lib/api'; import { capturePromoSceneAndTouchScan } from '../lib/promo'; import { initClientVersionChecks } from '../lib/client-version'; import { saveWechatLoginResult } from '../lib/pay-wechat'; import { applyWechatShare } from '../lib/wechat-share'; import { handleWechatAuthCallback } from '../lib/wechat-auth'; import { isWechatEnv } from '../lib/weixin'; function currentPagePathWithQuery(): string { const pages = Taro.getCurrentPages(); const cur = pages[pages.length - 1] as | { route?: string; options?: Record } | undefined; if (!cur?.route) { if (typeof window !== 'undefined') { return `${window.location.pathname}${window.location.search}`; } return ''; } const path = cur.route.startsWith('/') ? cur.route : `/${cur.route}`; const opts = cur.options ?? {}; const qs = Object.entries(opts) .filter(([k, v]) => v != null && v !== '' && k !== 'code' && k !== 'state') .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`) .join('&'); return qs ? `${path}?${qs}` : path; } /** * H5 App 根节点:iOS 签名 URL + 默认分享 + OAuth code 回调。 * 小程序:冷启动时捕获推广码 scene 并回传扫码埋点。 */ export default function WechatShareBootstrap() { const handlingCode = useRef(false); useEffect(() => { void capturePromoSceneAndTouchScan(); initClientVersionChecks(); }, []); useEffect(() => { if (process.env.TARO_ENV !== 'h5') return; if (typeof window === 'undefined') return; captureIosJssdkEntryUrl(); function refreshShare() { void applyWechatShare().catch(() => {}); } function tryHandleOAuth() { if (!isWechatEnv()) return; const params = new URLSearchParams(window.location.search); if (!params.get('code')) return; if (handlingCode.current) return; handlingCode.current = true; const returnFromLogin = (() => { const path = currentPagePathWithQuery(); if (path.includes('/pages/login/')) { try { return decodeURIComponent(params.get('return') || '') || undefined; } catch { return undefined; } } return undefined; })(); handleWechatAuthCallback() .then((result) => { if (!result) return; if (saveWechatLoginResult(result)) { toast('微信授权成功', 'success'); const ret = returnFromLogin || params.get('return') || undefined; if (result.accountMerged) { forceReloadAfterAccountMerge(ret); return; } if ( returnFromLogin !== undefined || currentPagePathWithQuery().includes('/pages/login/') ) { finishLoginNavigate(ret); } return; } // 兼容旧接口:仅 needBindPhone 时引导可选绑定,不阻塞浏览 if (result.needBindPhone && result.wxSessionKey) { goLogin(returnFromLogin, { bindMode: '1', wxSessionKey: result.wxSessionKey, }); } }) .catch((e) => { toast(e instanceof Error ? e.message : '微信授权失败'); }) .finally(() => { handlingCode.current = false; }); } refreshShare(); tryHandleOAuth(); const onVisible = () => { if (document.visibilityState === 'visible') refreshShare(); }; const onLocation = () => { refreshShare(); tryHandleOAuth(); }; document.addEventListener('visibilitychange', onVisible); window.addEventListener('popstate', onLocation); const { pushState, replaceState } = window.history; window.history.pushState = function (...args) { const ret = pushState.apply(this, args); window.dispatchEvent(new Event('dukang-h5-route')); return ret; }; window.history.replaceState = function (...args) { const ret = replaceState.apply(this, args); window.dispatchEvent(new Event('dukang-h5-route')); return ret; }; window.addEventListener('dukang-h5-route', onLocation); return () => { document.removeEventListener('visibilitychange', onVisible); window.removeEventListener('popstate', onLocation); window.removeEventListener('dukang-h5-route', onLocation); window.history.pushState = pushState; window.history.replaceState = replaceState; }; }, []); return null; }