128 lines
4.9 KiB
TypeScript
128 lines
4.9 KiB
TypeScript
declare const wx: any;
|
|
|
|
/** A terminal gate for this process. Only a real package restart clears it. */
|
|
export default class ClientUpdate {
|
|
private static initialized = false;
|
|
private static manager: any = null;
|
|
private static state: "checking" | "downloading" | "ready" | "unavailable" = "checking";
|
|
private static rejection: any = null;
|
|
private static dialogOpen = false;
|
|
private static waitTimer: any = null;
|
|
|
|
static get blocked(): boolean { return this.rejection !== null; }
|
|
static get blockedResponse(): any { return this.rejection; }
|
|
|
|
static initialize(): void {
|
|
if (this.initialized) return;
|
|
this.initialized = true;
|
|
if (typeof wx !== "undefined" && typeof wx.getUpdateManager === "function") {
|
|
try {
|
|
this.manager = wx.getUpdateManager();
|
|
this.manager.onCheckForUpdate(result => {
|
|
if (this.state === "ready") return;
|
|
this.state = result.hasUpdate ? "downloading" : "unavailable";
|
|
if (this.blocked) this.showPrompt();
|
|
});
|
|
this.manager.onUpdateReady(() => {
|
|
this.state = "ready";
|
|
if (this.blocked) this.showPrompt();
|
|
});
|
|
this.manager.onUpdateFailed(() => {
|
|
this.state = "unavailable";
|
|
if (this.blocked) this.showPrompt();
|
|
});
|
|
} catch (_) { this.state = "unavailable"; }
|
|
} else {
|
|
this.state = "unavailable";
|
|
}
|
|
}
|
|
|
|
/** Also converts late successful responses to the same error after another request blocks us. */
|
|
static handleResponse(response: any): any {
|
|
if (!this.blocked && response?.errorCode === "CLIENT_UPDATE_REQUIRED") {
|
|
this.initialize();
|
|
this.rejection = response;
|
|
this.freezeGame();
|
|
this.showPrompt();
|
|
}
|
|
return this.rejection || response;
|
|
}
|
|
|
|
/** GameManager calls this before its normal foreground resume. */
|
|
static onShow(): boolean {
|
|
if (!this.blocked) return false;
|
|
this.freezeGame();
|
|
this.showPrompt();
|
|
return true;
|
|
}
|
|
|
|
private static freezeGame(): void {
|
|
cc.fx.GameConfig.GM_INFO.gameState = false;
|
|
const scene = cc.director.getScene();
|
|
if (scene) scene.pauseSystemEvents(true);
|
|
cc.audioEngine.pauseAll();
|
|
cc.game.pause();
|
|
}
|
|
|
|
private static clearWait(): void {
|
|
if (this.waitTimer !== null) clearTimeout(this.waitTimer);
|
|
this.waitTimer = null;
|
|
}
|
|
|
|
private static showPrompt(): void {
|
|
if (typeof wx === "undefined" || typeof wx.showModal !== "function") {
|
|
return;
|
|
}
|
|
if (this.state === "checking" || this.state === "downloading") {
|
|
if (this.dialogOpen) return;
|
|
wx.showLoading({ title: "正在准备更新", mask: true });
|
|
if (this.waitTimer === null) {
|
|
this.waitTimer = setTimeout(() => {
|
|
this.waitTimer = null;
|
|
if (this.state !== "ready") {
|
|
this.state = "unavailable";
|
|
this.showPrompt();
|
|
}
|
|
}, 30000);
|
|
}
|
|
return;
|
|
}
|
|
this.clearWait();
|
|
if (this.dialogOpen) return;
|
|
wx.hideLoading();
|
|
const promptState = this.state;
|
|
const ready = promptState === "ready";
|
|
this.dialogOpen = true;
|
|
wx.showModal({
|
|
title: "游戏需要更新",
|
|
content: ready ? "新版本已准备好,请重启更新。"
|
|
: "当前版本已无法继续游戏,暂未取得可用的新版本。请退出后重新进入;仍有问题请稍后再试。",
|
|
showCancel: false,
|
|
confirmText: ready ? "重启更新" : "退出游戏",
|
|
success: result => {
|
|
if (!result.confirm || this.state !== promptState) return;
|
|
if (ready) {
|
|
try { this.manager.applyUpdate(); }
|
|
catch (_) { this.state = "unavailable"; }
|
|
} else if (typeof wx.exitMiniProgram === "function") {
|
|
wx.exitMiniProgram({
|
|
fail: () => {
|
|
wx.showToast({ title: "请手动退出后重新进入", icon: "none", duration: 3000 });
|
|
}
|
|
});
|
|
}
|
|
},
|
|
complete: () => {
|
|
this.dialogOpen = false;
|
|
if (this.state !== promptState) {
|
|
setTimeout(() => this.showPrompt(), 0);
|
|
} else {
|
|
// Keep a visible mask even if the platform refuses to exit/restart or dismisses the modal.
|
|
wx.showLoading({ title: ready ? "请重启游戏" : "请重新进入游戏", mask: true });
|
|
}
|
|
},
|
|
});
|
|
}
|
|
|
|
}
|