Cocos Creator 热更新地址动态化方案

张开发
2026/4/17 9:28:28 15 分钟阅读

分享文章

Cocos Creator 热更新地址动态化方案
基于 Cocos Creator 的 AssetsManager 热更新机制本方案实现以下能力✅CDN 地址运行时动态下发无需发包即可切换更新源✅主备容灾自动切换降低单点故障风险✅灰度发布支持按比例逐步放量✅本地缓存优化优先复用上次可用地址✅可扩展配置体系便于后续增加策略与字段一、整体流程┌──────────────┐ │ App 启动 │ └──────┬───────┘ ↓ ┌────────────────────┐ │ 读取本地缓存 URL │ └──────┬─────────────┘ ↓ ┌────────────────────┐ │ 拉取远程配置 JSON │ └──────┬─────────────┘ ↓ ┌────────────────────┐ │ URL 决策灰度/容灾│ └──────┬─────────────┘ ↓ ┌────────────────────┐ │ 重写 Manifest │ └──────┬─────────────┘ ↓ ┌────────────────────┐ │ 初始化 AssetsManager │ └──────┬─────────────┘ ↓ ┌────────────────────┐ │ checkUpdate │ └────────────────────┘二、模块拆分模块文件职责ConfigServiceconfig-service.ts拉取远程配置UrlSelectorurl-selector.ts灰度与容灾决策ManifestUtilmanifest-util.ts动态重写 manifestHotUpdateManagerhot-update.ts热更新主流程控制三、代码实现1. ConfigService远程配置拉取负责请求配置中心获取 CDN 列表、灰度比例等信息。建议配合 HTTPS、签名校验与缓存策略进一步增强安全性与稳定性。export interface RemoteConfig { version: number; cdn: string[]; gray?: number; } const CONFIG_URL https://config.xxx.com/game.json; const TIMEOUT 3000; export class ConfigService { static async fetch(): PromiseRemoteConfig | null { return new Promise((resolve) { const xhr new XMLHttpRequest(); xhr.timeout TIMEOUT; xhr.open(GET, CONFIG_URL); xhr.onreadystatechange () { if (xhr.readyState 4) { if (xhr.status 200 xhr.status 300) { try { const json JSON.parse(xhr.responseText); resolve(json); } catch { resolve(null); } } else { resolve(null); } } }; xhr.ontimeout () resolve(null); xhr.send(); }); } }2. UrlSelector灰度 容灾将“分流”和“地址选择”抽离成独立模块便于后续替换为更稳定的 hash如 CRC32 库或引入更复杂的路由策略。export class UrlSelector { // CRC32 简化实现可替换为成熟库 static hash(str: string): number { let hash 0; for (let i 0; i str.length; i) { hash (hash 5) - hash str.charCodeAt(i); hash | 0; } return Math.abs(hash); } // 基于 uid 的稳定分流同一 uid 结果尽量保持一致 static pick(uid: string, cdns: string[]): string { const index this.hash(uid) % cdns.length; return cdns[index]; } // 按百分比灰度返回一个候选列表供后续 pick 或容灾逻辑使用 static applyGray(cdns: string[], gray: number): string[] { if (!gray) return cdns; const rand Math.random() * 100; if (rand gray) { return [cdns[0]]; // 新 CDN } return [cdns[1] || cdns[0]]; // 老 CDN兜底 } }3. ManifestUtil动态重写通过重写 manifest 中的地址字段实现热更新源在运行时切换。注意 baseUrl 的尾斜杠处理避免拼接出错。export class ManifestUtil { static rewrite(content: string, baseUrl: string): string { const manifest JSON.parse(content); const root baseUrl.endsWith(/) ? baseUrl : baseUrl /; manifest.packageUrl root; manifest.remoteManifestUrl root project.manifest; manifest.remoteVersionUrl root version.manifest; return JSON.stringify(manifest); } static generateTemp(manifestStr: string): string { const path jsb.fileUtils.getWritablePath() temp.manifest; jsb.fileUtils.writeStringToFile(manifestStr, path); return path; } }4. HotUpdateManager核心流程主流程包含读取缓存、拉取配置、灰度处理、选择最终 URL、重写 manifest、初始化 AssetsManager、触发更新。const DEFAULT_URL https://cdn-default.xxx.com/game/; const STORAGE_PATH jsb.fileUtils.getWritablePath() update/; export class HotUpdateManager { private _am: jsb.AssetsManager | null null; async start(localManifestPath: string, uid: string) { // 1. 本地缓存优先 const cacheUrl cc.sys.localStorage.getItem(HOT_UPDATE_URL); // 2. 拉取远程配置 const config await ConfigService.fetch(); let cdns: string[] [DEFAULT_URL]; if (config config.cdn config.cdn.length 0) { cdns config.cdn; // 灰度处理 cdns UrlSelector.applyGray(cdns, config.gray || 0); } // 3. 选最终 URL缓存命中则直接用缓存 const finalUrl cacheUrl || UrlSelector.pick(uid, cdns); // 4. 读取本地 manifest const content jsb.fileUtils.getStringFromFile(localManifestPath); // 5. 重写 manifest const newManifest ManifestUtil.rewrite(content, finalUrl); // 6. 生成临时文件 const tempPath ManifestUtil.generateTemp(newManifest); // 7. 初始化 this._am new jsb.AssetsManager(tempPath, STORAGE_PATH); // 8. 绑定回调 this._am.setEventCallback(this._onUpdateEvent.bind(this)); // 9. 开始检测 this._am.checkUpdate(); } private _onUpdateEvent(event: jsb.EventAssetsManager) { switch (event.getEventCode()) { case jsb.EventAssetsManager.NEW_VERSION_FOUND: this._am?.update(); break; case jsb.EventAssetsManager.UPDATE_FINISHED: console.log(更新完成); break; case jsb.EventAssetsManager.UPDATE_FAILED: console.warn(更新失败尝试重试); this._am?.downloadFailedAssets(); break; case jsb.EventAssetsManager.ERROR_NO_LOCAL_MANIFEST: console.error(本地 manifest 缺失); break; case jsb.EventAssetsManager.ERROR_DOWNLOAD_MANIFEST: console.error(manifest 下载失败); break; } } }四、关键数据结构远程配置 JSON 示例{version:3,cdn:[https://cdn-a.xxx.com/game/,https://cdn-b.xxx.com/game/],gray:20}五、容灾策略对比策略描述优点缺点单 CDN固定地址简单无容灾主备切换失败后切换稳定切换慢并行探测同时检测多个 CDN切换快成本高灰度路由按用户分流可控实现复杂六、核心时序Client ConfigServer CDN | | | |---- 请求配置 ------------| | |--- 返回 JSON ------------| | | | | |---- 请求 version --------|-------------------| |--- 返回 version ---------|-------------------| | | | |---- 下载资源 -----------|-------------------| |--- 返回资源 ------------|-------------------|

更多文章