feat: 支持UI包从指定的Asset Bundle中加载

- 现在可以为每个FairyGUI包配置其所在的Asset Bundle名称。
- WindowManager和WindowResPool已更新,以处理从不同bundle加载UI包的逻辑。
- 这使得UI资源可以不打包在中,方便进行更灵活的资源管理和分包加载。
This commit is contained in:
gongxh 2025-07-15 14:31:00 +08:00
parent c77e047fe7
commit bc77e45562
4 changed files with 60 additions and 14 deletions

View File

@ -7,6 +7,10 @@
interface IPackageConfig { interface IPackageConfig {
/** UI所在resources中的路径 */ /** UI所在resources中的路径 */
uiPath: string; uiPath: string;
/** 如果UI不在 resources 中,则需要配置 所在bundle下的路径名*/
bundlePaths?: { [bundleName: string]: string };
/** /**
* *
* 1. UI包, * 1. UI包,

View File

@ -40,6 +40,8 @@ export namespace _uidecorator {
pkg: string; pkg: string;
/** 窗口名 */ /** 窗口名 */
name: string; name: string;
/** 窗口bundle名 */
bundle: string;
}; };
} }
/** 用来存储窗口注册信息 @internal */ /** 用来存储窗口注册信息 @internal */
@ -56,7 +58,7 @@ export namespace _uidecorator {
* @param {string} pkgName fgui包名 * @param {string} pkgName fgui包名
* @param {string} name (fgui中的组件名一一对应) * @param {string} name (fgui中的组件名一一对应)
*/ */
export function uiclass(groupName: string, pkgName: string, name: string): Function { export function uiclass(groupName: string, pkgName: string, name: string, bundle?: string): Function {
/** target 类的构造函数 */ /** target 类的构造函数 */
return function (ctor: any): void { return function (ctor: any): void {
// debug(`uiclass >${JSON.stringify(res)}<`); // debug(`uiclass >${JSON.stringify(res)}<`);
@ -71,6 +73,7 @@ export namespace _uidecorator {
group: groupName, group: groupName,
pkg: pkgName, pkg: pkgName,
name: name, name: name,
bundle: bundle || "",
}, },
}); });
}; };
@ -127,6 +130,8 @@ export namespace _uidecorator {
pkg: string; pkg: string;
/** 组件名 */ /** 组件名 */
name: string; name: string;
/** headerbundle名 */
bundle: string;
}; };
} }
/** 用来存储组件注册信息 @internal */ /** 用来存储组件注册信息 @internal */
@ -142,7 +147,7 @@ export namespace _uidecorator {
* @param {string} pkg * @param {string} pkg
* @param {string} name * @param {string} name
*/ */
export function uiheader(pkg: string, name: string): Function { export function uiheader(pkg: string, name: string, bundle?: string): Function {
return function (ctor: any): void { return function (ctor: any): void {
// log(`pkg:【${pkg}】 uiheader prop >${JSON.stringify(ctor[UIPropMeta] || {})}<`); // log(`pkg:【${pkg}】 uiheader prop >${JSON.stringify(ctor[UIPropMeta] || {})}<`);
uiheaderMap.set(ctor, { uiheaderMap.set(ctor, {
@ -154,6 +159,7 @@ export namespace _uidecorator {
res: { res: {
pkg: pkg, pkg: pkg,
name: name, name: name,
bundle: bundle || "",
} }
}); });
}; };

View File

@ -213,13 +213,13 @@ export class WindowManager {
// 窗口注册 // 窗口注册
for (const { ctor, res } of _uidecorator.getWindowMaps().values()) { for (const { ctor, res } of _uidecorator.getWindowMaps().values()) {
debug(`窗口注册 窗口名:${res.name} 包名:${res.pkg} 组名:${res.group}`); debug(`窗口注册 窗口名:${res.name} 包名:${res.pkg} 组名:${res.group}`);
this._resPool.add(ctor, res.group, res.pkg, res.name); this._resPool.add(ctor, res.group, res.pkg, res.name, res.bundle);
} }
// 窗口header注册 // 窗口header注册
for (const { ctor, res } of _uidecorator.getHeaderMaps().values()) { for (const { ctor, res } of _uidecorator.getHeaderMaps().values()) {
debug(`header注册 header名:${res.name} 包名:${res.pkg}`); debug(`header注册 header名:${res.name} 包名:${res.pkg}`);
this._resPool.addHeader(ctor, res.pkg, res.name); this._resPool.addHeader(ctor, res.pkg, res.name, res.bundle);
} }
// 组件注册 // 组件注册
ComponentExtendHelper.register(); ComponentExtendHelper.register();

View File

@ -4,6 +4,7 @@
* @Description: * @Description:
*/ */
import { assetManager, resources } from "cc";
import { UIObjectFactory, UIPackage } from "fairygui-cc"; import { UIObjectFactory, UIPackage } from "fairygui-cc";
import { warn } from "../kunpocc"; import { warn } from "../kunpocc";
import { IPackageConfigRes } from "./IPackageConfig"; import { IPackageConfigRes } from "./IPackageConfig";
@ -17,11 +18,17 @@ export interface WindowInfo {
pkg: string; pkg: string;
/** 窗口名 */ /** 窗口名 */
name: string; name: string;
/** bundle名 */
bundle: string;
} }
export interface HeaderInfo { export interface HeaderInfo {
/** 类的构造函数 */
ctor: any; ctor: any;
/** fgui包名 */
pkg: string; pkg: string;
/** bundle名 */
bundle: string;
} }
/** @internal */ /** @internal */
@ -30,6 +37,8 @@ export class WindowResPool {
protected _windowInfos: Map<string, WindowInfo> = new Map<string, any>(); protected _windowInfos: Map<string, WindowInfo> = new Map<string, any>();
/** 窗口header信息池 @internal */ /** 窗口header信息池 @internal */
protected _headerInfos: Map<string, HeaderInfo> = new Map<string, any>(); protected _headerInfos: Map<string, HeaderInfo> = new Map<string, any>();
/** UI包所在的bundle名 */
private _pkgBundles: Map<string, string> = new Map<string, string>();
/** 是否设置过配置内容 @internal */ /** 是否设置过配置内容 @internal */
private _isInit: boolean = false; private _isInit: boolean = false;
@ -37,8 +46,12 @@ export class WindowResPool {
private _windowPkgs: Map<string, string[]> = new Map(); private _windowPkgs: Map<string, string[]> = new Map();
/** 包的引用计数 @internal */ /** 包的引用计数 @internal */
private _pkgRefs: { [pkg: string]: number } = {}; private _pkgRefs: { [pkg: string]: number } = {};
/** UI包路径 @internal */ /** UI包路径 @internal */
private _uipath: string = ""; // private _uipath: string = "";
/** UI包在bundle中的路径 @internal */
private _uiPaths: { [bundle: string]: string } = {};
/** 手动管理的包 @internal */ /** 手动管理的包 @internal */
private _manualPackages: Set<string> = new Set(); private _manualPackages: Set<string> = new Set();
/** 立即释放的包 @internal */ /** 立即释放的包 @internal */
@ -58,7 +71,7 @@ export class WindowResPool {
* *
* @param info * @param info
*/ */
public add(ctor: any, group: string, pkg: string, name: string): void { public add(ctor: any, group: string, pkg: string, name: string, bundle: string): void {
if (this.has(name)) { if (this.has(name)) {
return; return;
} }
@ -66,8 +79,10 @@ export class WindowResPool {
ctor: ctor, ctor: ctor,
group: group, group: group,
pkg: pkg, pkg: pkg,
name: name name: name,
bundle: bundle
}); });
this._pkgBundles.set(pkg, bundle || "resources");
this.addWindowPkg(name, pkg); this.addWindowPkg(name, pkg);
// 窗口组件扩展 // 窗口组件扩展
UIObjectFactory.setExtension(`ui://${pkg}/${name}`, ctor); UIObjectFactory.setExtension(`ui://${pkg}/${name}`, ctor);
@ -88,14 +103,16 @@ export class WindowResPool {
* header信息 * header信息
* @param info * @param info
*/ */
public addHeader(ctor: any, pkg: string, name: string): void { public addHeader(ctor: any, pkg: string, name: string, bundle: string): void {
if (this.hasHeader(name)) { if (this.hasHeader(name)) {
return; return;
} }
this._headerInfos.set(name, { this._headerInfos.set(name, {
ctor: ctor, ctor: ctor,
pkg: pkg pkg: pkg,
bundle: bundle
}); });
this._pkgBundles.set(pkg, bundle || "resources");
// 窗口header扩展 // 窗口header扩展
UIObjectFactory.setExtension(`ui://${pkg}/${name}`, ctor); UIObjectFactory.setExtension(`ui://${pkg}/${name}`, ctor);
} }
@ -124,10 +141,13 @@ export class WindowResPool {
this._hideWaitWindow = res?.hideWaitWindow; this._hideWaitWindow = res?.hideWaitWindow;
this._fail = res?.fail; this._fail = res?.fail;
this._uipath = res.config?.uiPath || ""; this._uiPaths = res.config?.bundlePaths || {};
// 如果uipath不以/结尾 则添加/ this._uiPaths["resources"] = res.config?.uiPath || "";
if (this._uipath != "" && !this._uipath.endsWith("/")) {
this._uipath += "/"; for (const bundle in this._uiPaths) {
if (this._uiPaths[bundle] != "" && !this._uiPaths[bundle].endsWith("/")) {
this._uiPaths[bundle] += "/";
}
} }
this._manualPackages = new Set(res.config.manualPackages || []); this._manualPackages = new Set(res.config.manualPackages || []);
@ -249,7 +269,12 @@ export class WindowResPool {
return; return;
} }
for (const pkg of needLoadPkgs) { for (const pkg of needLoadPkgs) {
UIPackage.loadPackage(this._uipath + pkg, (err: any) => { let bundleName = this.getPkgBundle(pkg);
let bundle = bundleName === "resources" ? resources : assetManager.getBundle(bundleName);
if (!bundle) {
throw new Error(`UI包【${pkg}】所在的bundle【${bundleName}】未加载`);
}
UIPackage.loadPackage(bundle, this.getPkgPath(pkg), (err: any) => {
total--; total--;
err ? failPkgs.push(pkg) : successPkgs.push(pkg); err ? failPkgs.push(pkg) : successPkgs.push(pkg);
if (total > 0) { if (total > 0) {
@ -264,6 +289,17 @@ export class WindowResPool {
} }
} }
/** 获取UI包所在的bundle名 */
private getPkgBundle(pkg: string): string {
return this._pkgBundles.get(pkg) || "resources";
}
/** 获取UI包在bundle中的路径 */
private getPkgPath(pkg: string): string {
let bundle = this._pkgBundles.get(pkg);
return this._uiPaths[bundle] + pkg;
}
/** 获取窗口对应的包名列表 */ /** 获取窗口对应的包名列表 */
private getWindowPkgs(windowName: string): string[] { private getWindowPkgs(windowName: string): string[] {
if (this._windowPkgs.has(windowName)) { if (this._windowPkgs.has(windowName)) {