Files
mp-xieyingeng/assets/scripts/utils/ShareLaunchHandler.ts
2026-05-19 22:56:31 +08:00

148 lines
5.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { WxSDK } from './WxSDK';
import { ShareManager } from './ShareManager';
import { AuthManager } from './AuthManager';
import { ViewManager } from '../core/ViewManager';
/**
* 分享启动监听器
*
* 微信小游戏未被杀掉、只是退到后台时,再次通过好友分享卡片打开小游戏,
* 不会重新走启动链路PageLoading 不会再跑),因此 `wx.getLaunchOptionsSync()`
* 取到的 query 可能是上一次启动的旧值。这个 handler 通过 `wx.onShow`
* 拿到最新的 query检测 shareCode 变化后:
* 1. 清掉旧的分享态
* 2. 调用 `ShareManager.joinShare(code)` 拉取新的题单
* 3. 直接打开 `PageLevel` 进入分享挑战
*
* 对应在 PageLevel 那侧通过 `onViewShow` 检测到 ShareManager.shareCode
* 变化,重新走 `_reinitLevelSession`。
*/
export class ShareLaunchHandler {
private static _instance: ShareLaunchHandler | null = null;
static get instance(): ShareLaunchHandler {
if (!this._instance) {
this._instance = new ShareLaunchHandler();
}
return this._instance;
}
/** 已经处理过的 shareCode相同则不再重复 join */
private _activeShareCode: string | null = null;
/** 是否正在处理一次 onShow 触发的 join 流程,避免并发 */
private _isHandlingShow: boolean = false;
/** 是否已经初始化 */
private _initialized: boolean = false;
private _showHandler = (res: { query?: Record<string, any> } | undefined) => {
const code = WxSDK.extractShareCodeFromQuery(res?.query);
if (!code) {
return;
}
// 同一个 shareCode 且当前已经处于该分享态,无需重复处理
if (code === this._activeShareCode && ShareManager.instance.isShareMode) {
return;
}
// 即使不是新的 code但如果 ShareManager 已经丢失了分享态(例如挑战完成被 clear
// 用户重新点同一个分享卡片仍然应当重新加入。
void this._handleShareCode(code);
};
private _hideHandler = () => {
// 目前不在 onHide 时做任何破坏性操作;保留监听只为方便后续扩展
// (比如:暂停倒计时、上报埋点)。
console.log('[ShareLaunchHandler] 小游戏切到后台');
};
/**
* 在 main.onLoad 中调用,注册 wx.onShow / wx.onHide。
* 同时把当前启动参数中的 shareCode 作为种子,避免初次冷启动时
* 因 wx.onShow 也会被调用一次而重复触发分享流程。
*/
init(): void {
if (this._initialized) {
return;
}
this._initialized = true;
if (!WxSDK.isWechat()) {
return;
}
// 冷启动时先把当前 launch 中的 shareCode 标记成已处理,
// 避免 wx.onShow 在初始展示时拿到同一个 code 又走一遍 join。
this._activeShareCode = WxSDK.getShareCodeFromLaunch();
WxSDK.onAppShow(this._showHandler);
WxSDK.onAppHide(this._hideHandler);
console.log('[ShareLaunchHandler] 已注册 onShow/onHide 监听');
}
/**
* 由 PageLoading 在初始 join 之后调用,把已处理的 shareCode 显式同步过来,
* 让 onShow 收到相同 code 时不会重复 join。
*/
markActiveShareCode(code: string | null): void {
this._activeShareCode = code;
}
/**
* 主动取消监听(一般无需调用,留作扩展)
*/
dispose(): void {
if (!this._initialized) return;
this._initialized = false;
WxSDK.offAppShow(this._showHandler);
WxSDK.offAppHide(this._hideHandler);
}
private async _handleShareCode(code: string): Promise<void> {
if (this._isHandlingShow) {
console.log('[ShareLaunchHandler] 已有 onShow 分享流程在执行,跳过', code);
return;
}
this._isHandlingShow = true;
try {
console.log('[ShareLaunchHandler] 检测到新的 shareCode准备切换:', code);
// 确保已登录initialize 内部对已有 token 做了校验,幂等可重复调用)
const loginOk = await AuthManager.instance.initialize();
if (!loginOk) {
console.warn('[ShareLaunchHandler] 登录失败,放弃 onShow 分享切换');
return;
}
// 切到新的分享前清掉旧分享态,避免 ShareManager 内残留旧题单导致 PageLevel 错位
if (ShareManager.instance.isShareMode) {
ShareManager.instance.clearShareMode();
}
const joinOk = await ShareManager.instance.joinShare(code);
if (!joinOk) {
console.warn('[ShareLaunchHandler] 加入分享失败:', code);
return;
}
// 标记当前激活的分享码
this._activeShareCode = code;
// 跳过中间页,直接打开 PageLevel 进入分享挑战。
// PageLevel 会在 onViewShow 中根据 ShareManager.shareCode 与本地缓存比对,
// 决定是否需要 `_reinitLevelSession`。
ViewManager.instance.open('PageLevel', {
params: { shareMode: true },
});
console.log('[ShareLaunchHandler] 已切换到分享挑战:', code);
} catch (err) {
console.error('[ShareLaunchHandler] 处理 shareCode 异常:', err);
} finally {
this._isHandlingShow = false;
}
}
}