fix: 修复一系列 bug
This commit is contained in:
@@ -101,7 +101,7 @@ export class AchievementTitleManager {
|
||||
titleText: currentStage.titleText,
|
||||
nextTitleText: nextStage.titleText,
|
||||
nextTitleProgress,
|
||||
progressText: `还差${remainingToNextTitle}题获得${nextStage.titleText}`,
|
||||
progressText: `还差${remainingToNextTitle}题,解锁新成就等级`,
|
||||
completedLevelCount,
|
||||
currentTitleStartCount: currentStage.startCount,
|
||||
nextTitleRequiredCount: nextStage.startCount,
|
||||
|
||||
147
assets/scripts/utils/ShareLaunchHandler.ts
Normal file
147
assets/scripts/utils/ShareLaunchHandler.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
assets/scripts/utils/ShareLaunchHandler.ts.meta
Normal file
9
assets/scripts/utils/ShareLaunchHandler.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "0709f849-66c8-4e4c-aec5-044c3c414c3e",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -398,15 +398,82 @@ export class WxSDK {
|
||||
|
||||
try {
|
||||
const options = wxApi.getLaunchOptionsSync();
|
||||
if (options?.query?.shareCode) {
|
||||
console.log('[WxSDK] 检测到分享码:', options.query.shareCode);
|
||||
return options.query.shareCode;
|
||||
const code = WxSDK.extractShareCodeFromQuery(options?.query);
|
||||
if (code) {
|
||||
console.log('[WxSDK] 检测到分享码:', code);
|
||||
return code;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[WxSDK] 获取启动参数失败:', err);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从查询对象(来自 launch options 或 onShow 回调)中提取 shareCode
|
||||
*/
|
||||
static extractShareCodeFromQuery(query: Record<string, any> | null | undefined): string | null {
|
||||
const code = query?.shareCode;
|
||||
return typeof code === 'string' && code.length > 0 ? code : null;
|
||||
}
|
||||
|
||||
// ==================== 前后台生命周期 ====================
|
||||
|
||||
/**
|
||||
* 监听小游戏切到前台事件。
|
||||
* 同一个回调可重复注册多次:内部用 wx.onShow,请确保业务层做幂等处理或在卸载时调用 offAppShow。
|
||||
* @param callback 切前台时触发,包含本次显示对应的 query / scene 等参数
|
||||
*/
|
||||
static onAppShow(callback: (res: { query?: Record<string, any>; scene?: number; path?: string } | undefined) => void): void {
|
||||
const wxApi = WxSDK.getWx();
|
||||
if (!wxApi) return;
|
||||
|
||||
if (typeof wxApi.onShow !== 'function') {
|
||||
console.warn('[WxSDK] 当前微信版本不支持 onShow');
|
||||
return;
|
||||
}
|
||||
|
||||
wxApi.onShow(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消监听小游戏切到前台事件
|
||||
*/
|
||||
static offAppShow(callback: (res: any) => void): void {
|
||||
const wxApi = WxSDK.getWx();
|
||||
if (!wxApi) return;
|
||||
|
||||
if (typeof wxApi.offShow === 'function') {
|
||||
wxApi.offShow(callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听小游戏切到后台事件
|
||||
*/
|
||||
static onAppHide(callback: () => void): void {
|
||||
const wxApi = WxSDK.getWx();
|
||||
if (!wxApi) return;
|
||||
|
||||
if (typeof wxApi.onHide !== 'function') {
|
||||
console.warn('[WxSDK] 当前微信版本不支持 onHide');
|
||||
return;
|
||||
}
|
||||
|
||||
wxApi.onHide(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消监听小游戏切到后台事件
|
||||
*/
|
||||
static offAppHide(callback: () => void): void {
|
||||
const wxApi = WxSDK.getWx();
|
||||
if (!wxApi) return;
|
||||
|
||||
if (typeof wxApi.offHide === 'function') {
|
||||
wxApi.offHide(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 隐私授权相关 ====================
|
||||
|
||||
Reference in New Issue
Block a user