/** * @Author: Gongxh * @Date: 2025-03-20 * @Description: 热更新管理器 */ import { native } from "cc"; import { ICheckUpdatePromiseResult } from "../interface/PromiseResult"; import { Platform } from "../kunpocc"; import { log } from "../tool/log"; import { HotUpdate, HotUpdateCode } from "./HotUpdate"; const TAG = "hotupdate:"; export class HotUpdateManager { private static instance: HotUpdateManager; public static getInstance(): HotUpdateManager { if (!HotUpdateManager.instance) { HotUpdateManager.instance = new HotUpdateManager(); } return HotUpdateManager.instance; } /** 是否初始化了 */ private _isInitialized: boolean = false; /** 本地manifest路径 */ private _manifestUrl: string = ''; /** 版本号 */ private _version: string = ''; /** 资源版本号 */ private _resVersion: string = null; /** 可写路径 */ private _writablePath: string = ''; /** 是否正在更新 或者 正在检查更新 */ private _updating: boolean = false; /** 更新实例 */ private _hotUpdate: HotUpdate = null; /** * 热更新文件存放的可写路径 */ public get writablePath(): string { return this._writablePath; } /** * 本地manifest路径 */ public get manifestUrl(): string { return this._manifestUrl; } /** * 传入的游戏版本号 */ public get version(): string { return this._version; } /** * 获取资源版本号, 须初始化成功后再使用 * @return 资源版本号 默认值 ‘0’ */ public get resVersion(): string { if (this._resVersion === null) { this._resVersion = new HotUpdate().resVersion; } return this._resVersion; } public set resVersion(version: string) { if (this._resVersion === null) { this._resVersion = version; } } /** * 1. 初始化热更新管理器 * @param manifestUrl 传入本地manifest文件地址 资源的assets.nativeUrl * @param version 游戏版本号 eg: 1.0.0 */ public init(manifestUrl: string, version: string): void { if (this._isInitialized) { log(`${TAG} 热更新管理器不需要重复初始化`); return; } this._isInitialized = true; this._manifestUrl = manifestUrl; this._version = version; let writablePath = native?.fileUtils?.getWritablePath() || ""; if (!writablePath.endsWith("/")) { writablePath += "/"; } this._writablePath = `${writablePath}hot-update/${version}/`; log(`${TAG}可写路径:${this._writablePath}`); } /** * 检查是否存在热更新 * 提供一个对外的方法检查是否存在热更新 * @return {Promise} */ public checkUpdate(): Promise { return new Promise((resolve, reject) => { if (!Platform.isNativeMobile) { reject({ code: HotUpdateCode.PlatformNotSupported, message: "当前平台不需要热更新" }); return; } if (!this._isInitialized) { reject({ code: HotUpdateCode.NotInitialized, message: "未初始化, 需要先调用init方法" }); return; } if (this._updating) { reject({ code: HotUpdateCode.Updating, message: "正在更新或者正在检查更新中" }); return; } this._updating = true; this._hotUpdate = new HotUpdate(); this._hotUpdate.checkUpdate().then((res) => { this._updating = false; // 有更新 resolve(res); }).catch((res: ICheckUpdatePromiseResult) => { this._updating = false; // 无更新 reject(res); }); }); } /** * 开始热更新 * @param res.skipCheck 是否跳过检查更新 * @param res.progress 更新进度回调 kb: 已下载的资源大小, total: 总资源大小 (kb) * @param res.complete 更新结束回调 根据错误码判断 跳过还是重试失败资源 */ public startUpdate(res: { skipCheck: boolean, progress: (kb: number, total: number) => void, complete: (code: HotUpdateCode, message: string) => void }): void { if (!Platform.isNativeMobile) { res.complete(HotUpdateCode.PlatformNotSupported, "当前平台不需要热更新"); return; } if (!this._isInitialized) { res.complete(HotUpdateCode.NotInitialized, "未初始化, 需要先调用init方法"); return; } if (this._updating) { res.complete(HotUpdateCode.Updating, "正在更新或者正在检查更新"); return; } this._updating = true; if (res.skipCheck && this._hotUpdate) { this._hotUpdate.startUpdate({ skipCheck: res.skipCheck, progress: res.progress, complete: (code: HotUpdateCode, message: string) => { this._updating = false; res.complete(code, message); } }); } else { this._hotUpdate = new HotUpdate(); this._hotUpdate.startUpdate({ skipCheck: false, progress: res.progress, complete: (code: HotUpdateCode, message: string) => { this._updating = false; res.complete(code, message); } }); } } /** 重试失败的资源 */ public retryUpdate(): void { if (!this._hotUpdate) { throw new Error(`${TAG} 使用前 必须使用过startUpdate方法`); } this._hotUpdate.retryUpdate(); } }