diff --git a/apps/mini-user/src/components/WechatShareBootstrap.tsx b/apps/mini-user/src/components/WechatShareBootstrap.tsx index da5132f..a101541 100644 --- a/apps/mini-user/src/components/WechatShareBootstrap.tsx +++ b/apps/mini-user/src/components/WechatShareBootstrap.tsx @@ -1,4 +1,4 @@ -import Taro, { useDidShow } from '@tarojs/taro'; +import Taro from '@tarojs/taro'; import { captureIosJssdkEntryUrl } from '@dukang/weixin-sdk'; import { useEffect, useRef } from 'react'; import { finishLoginNavigate, goLogin } from '../lib/auth-nav'; @@ -29,66 +29,105 @@ function currentPagePathWithQuery(): string { } /** - * H5 全局: - * 1. 默认分享卡片 - * 2. 公众号 OAuth ?code= 统一回调(避免各页重复消费 code) + * H5 App 根节点专用:不可用 useDidShow(App 无页面 Context)。 + * - 首次进页:捕获 iOS 签名 URL + 默认分享 + OAuth code 回调 + * - 路由/回前台:刷新默认分享卡片 */ export default function WechatShareBootstrap() { const handlingCode = useRef(false); useEffect(() => { - if (process.env.TARO_ENV === 'h5') { - captureIosJssdkEntryUrl(); - } - }, []); - - useDidShow(() => { if (process.env.TARO_ENV !== 'h5') return; - void applyWechatShare().catch(() => {}); - - if (!isWechatEnv()) return; if (typeof window === 'undefined') 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; - })(); + captureIosJssdkEntryUrl(); - handleWechatAuthCallback() - .then((result) => { - if (!result) return; - if (result.needBindPhone && result.wxSessionKey) { - goLogin(returnFromLogin, { - bindMode: '1', - wxSessionKey: result.wxSessionKey, - }); - return; - } - if (saveWechatLoginResult(result)) { - toast('微信授权成功', 'success'); - if (returnFromLogin !== undefined || currentPagePathWithQuery().includes('/pages/login/')) { - finishLoginNavigate(returnFromLogin || params.get('return') || undefined); + 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; } } - }) - .catch((e) => { - toast(e instanceof Error ? e.message : '微信授权失败'); - }) - .finally(() => { - handlingCode.current = false; - }); - }); + return undefined; + })(); + + handleWechatAuthCallback() + .then((result) => { + if (!result) return; + if (result.needBindPhone && result.wxSessionKey) { + goLogin(returnFromLogin, { + bindMode: '1', + wxSessionKey: result.wxSessionKey, + }); + return; + } + if (saveWechatLoginResult(result)) { + toast('微信授权成功', 'success'); + if ( + returnFromLogin !== undefined || + currentPagePathWithQuery().includes('/pages/login/') + ) { + finishLoginNavigate(returnFromLogin || params.get('return') || undefined); + } + } + }) + .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; }