高人制作的CocosCreator分包插件
cocos论坛链接:https://forum.cocos.org/t/cocoscreator-assetsbundle/88349
///////这里只是自己备注下,做个记录,下面是论坛原作者原文描述:
assets-bundle插件基于官方的分包策略。
之前完成过另一款分包插件 subpackage-tools 项目上线一年,没有任何问题。该插件完全基于分包热更完成。现在插件商店已经看不到它了,插件的核心只是分离资源而已,真正需要在项目中使用,必须要自己完成分包热更的项目逻辑,所以一直没有出使用demo,被不少人诟病,汗颜!
官方的分包加载已经基本可以用于原生环境,其中代码的分包在原生环境App启动速度上有较大帮助,但是原生资源的分包仅对小游戏环境有降低包体的作用,对原生环境没有任何作用。
插件在官方分包的策略上 加强了对原生环境的支持: 资源分包插件核心功能
:
- 接管官方分包策略
- 追加分离出非原生资源(import资源)
- 对分包追加热更功能
支持三种分包模式- 本地包: 官方分包
- 热更包: 在本地包的基础上对分包最佳热更功能 使用前先检查资源版本
- 远程包: 在热更包的基础上将分包从构建项目中分离出来 使用前必须先下载远程包
插件作用: 降低App包体大小,加快App启动速度。适用于大厅游戏和关卡游戏
唯一遗憾的事没能降低setting.js的大小,研究发现资源不放在 resources 目录下也是可以动态加载的,但是不放在该目录下又需要动态加载的资源大部分都不会参与项目构建,全部堆在一个场景里倒是可以解决问题,但是明显不怎么优雅。斟酌后还是放下了对setting.js的手术刀
插件支持自动 zip 压缩 import 和 raw-assets 目录
基于 2.3.0版本Mac下开发,目测在 2.x版本都是可以跑的 至于win环境好不好使我就不知道了 ,欢迎提Bug。
插件简单介绍:
- 所有.manifest文件都放在 assets/resources/Manifest 目录 插件会完全操作(删除、写入)这个目录,如果冲突请自行转移目录内资源
- 生成的子包全部放在 ${project}/HotUpdate/${项目分支}/目录 同样是完全操作这个目录,如果冲突请自行转移目录内资源
- 支持Debug模式,启动该模式 分包会被统一放进 ${project}/HotUpdate/${项目分支}/Debug目录 对应的远程热更地址也会追加 "http://host.com/${项目分支}/Debug"
- 支持包名搜索,当子包较多时可以使用包名搜索功能
- 插件自动和手动校验子包的资源安全性(是否丢失资源和是否引用了其他私有子包的资源)
- 插件支持自动校验当前项目的分包设置与插件的分包设置是否一致
- 支持手动清空和设置项目分包
- 支持自动和手动向Manifest目录中导入远程分包的空清单文件
- 支持 zip 压缩子包资源
- 支持三种分包模式
- 如果不设置任何子包 则该插件为一个简单的热更插件
- 如果不需要本插件,卸载或者不打开本插件即可
使用方法:
- 编辑器面板->扩展->assets-bundle
- 配置好主包以及子包信息
- 打开构建面板->构建 必须至少构建两次以上
- 检查控制台是否有爆红 如果有,必须要先解决爆红问题
- 检测HotUpdate目录是否生成对应的主包和子包 检测主包和子包是否完整(初次使用小心点)
- 检查无误后,打开AndroidStudio或者xcode编译App
目前插件已经完成了资源分离的测试,仅初步完成了分包热更下载的测试
本插件仅是一个项目分包的工具,分包热更的逻辑代码请自行根据自身项目完成
没有demo,完全开源
被第一版插件(subpackage-tools)的地狱回调恶心到了,这版插件采用了 await 写法,逻辑上清晰一些,但是本次插件的核心逻辑写在了主线程上,修改代码会造成编辑器奔溃或插件无法打开的情况
插件刚完成,还是热乎的。
https://github.com/zPiggy/assets-bundle200
注意
1.插件目前不支持 win 环境使用,非常抱歉,等我找个 win 电脑。。。。 有兴趣的朋友可以提交PR
2.插件不支持勾选【内联所有 SpriteFrame】和 【合并图集中的 SpriteFrame】
3.目测插件兼容 2.x 版本
///////下面我记录点使用体会:
使用该插件的CocosCreator版本是2.2.2
使用目标:从项目中把某些实现抽出为prefab资源(不带js),再动态加载该资源
原作者的方式,应该是走的热更新思路,把资源热更新完整后,再进游戏
为了达到动态加载分包资源,对插件做了一些修改,对所有分包分别生成对应的setting.json(格式类似build/jsb-link/src/settings.js)
使用的某个分包时,先把其setting.json追加到settings.js里,在loadSubpackage,再loadRes使用
接入流程
1.把插件放到node_modules下
2.启动Creator,打开插件面板,设置分包,类型为远程,设置按钮都点一遍
3.在插件面板打开的条件下,开始针对ios平台构建
4.会在保存分包资源的目录下看到分包资源,最后使用的是:分包名的文件
5.客户端代码里需要实现资源的下载和移动 到对应位置
6.creator的js引擎engine里需要添加两个add方法
7.客户端实现SubpackageManager,实现加载分包配置问题件setting.json和分包资源
8.可以像resources下的资源使用方式一样使用
动态加载settings.js配置
// .1 引擎修改
pack-downloader.js
addPacks: function (packs) {
Object.assign(packIndices, packs);
for (var packUuid in packs) {
var uuids = packs[packUuid];
for (var i = 0; i < uuids.length; i++) {
var uuid = uuids[i];
// the smallest pack must be at the beginning of the array to download more first
var pushFront = uuids.length === 1;
if (uuidToPack[uuid]) {
if (typeof uuidToPack[uuid] == 'string') {
if (uuidToPack[uuid] != packUuid) {
pushToMap(uuidToPack, uuid, packUuid, pushFront);
globalUnpackers[packUuid] = new UnpackerData();
}
} else if (typeof uuidToPack[uuid] == 'object') {
if (uuidToPack[uuid].indexOf(packUuid) == -1) {
pushToMap(uuidToPack, uuid, packUuid, pushFront);
globalUnpackers[packUuid] = new UnpackerData();
}
}
} else {
pushToMap(uuidToPack, uuid, packUuid, pushFront);
globalUnpackers[packUuid] = new UnpackerData();
}
}
}
},
// .2 引擎修改
CCAssetLibrary.js
add: function (options) {
if (CC_EDITOR && _libraryBase) {
cc.errorID(6402);
return;
}
console.log("CCAssetLibrary ——add",JSON.stringify(options));
// 这里将路径转 url,不使用路径的原因是有的 runtime 不能解析 "\" 符号。
// 不使用 url.format 的原因是 windows 不支持 file:// 和 /// 开头的协议,所以只能用 replace 操作直接把路径转成 URL。
var libraryPath = options.libraryPath;
libraryPath = libraryPath.replace(/\\/g, '/');
_libraryBase = cc.path.stripSep(libraryPath) + '/';
_rawAssetsBase = options.rawAssetsBase;
if (options.subpackages) {
var subPackPipe = new SubPackPipe(options.subpackages);
cc.loader.insertPipeAfter(cc.loader.assetLoader, subPackPipe);
cc.loader.subPackPipe = subPackPipe;
}
var md5AssetsMap = options.md5AssetsMap;
if (md5AssetsMap && md5AssetsMap.import) {
// decode uuid
var i = 0, uuid = 0;
var md5ImportMap = js.createMap(true);
var md5Entries = md5AssetsMap.import;
for (i = 0; i < md5Entries.length; i += 2) {
uuid = decodeUuid(md5Entries[i]);
md5ImportMap[uuid] = md5Entries[i + 1];
}
var md5RawAssetsMap = js.createMap(true);
md5Entries = md5AssetsMap['raw-assets'];
for (i = 0; i < md5Entries.length; i += 2) {
uuid = decodeUuid(md5Entries[i]);
md5RawAssetsMap[uuid] = md5Entries[i + 1];
}
var md5Pipe = new MD5Pipe(md5ImportMap, md5RawAssetsMap, _libraryBase);
cc.loader.insertPipeAfter(cc.loader.assetLoader, md5Pipe);
cc.loader.md5Pipe = md5Pipe;
}
// init raw assets
var assetTables = Loader._assetTables;
// for (var mount in assetTables) {
// assetTables[mount].reset();
// }
var rawAssets = options.rawAssets;
if (rawAssets) {
for (var mountPoint in rawAssets) {
var assets = rawAssets[mountPoint];
for (var uuid in assets) {
var info = assets[uuid];
var url = info[0];
var typeId = info[1];
var type = cc.js._getClassById(typeId);
if (!type) {
cc.error('Cannot get', typeId);
continue;
}
// backward compatibility since 1.10
_uuidToRawAsset[uuid] = new RawAssetEntry(mountPoint + '/' + url, type);
// init resources
var ext = cc.path.extname(url);
if (ext) {
// trim base dir and extname
url = url.slice(0, - ext.length);
}
var isSubAsset = info[2] === 1;
if (!assetTables[mountPoint]) {
assetTables[mountPoint] = new AssetTable();
}
assetTables[mountPoint].add(url, uuid, type, !isSubAsset);
}
}
}
if (options.packedAssets) {
PackDownloader.addPacks(options.packedAssets);
}
// init cc.url
//cc.url._init((options.mountPaths && options.mountPaths.assets) || _rawAssetsBase + 'assets');
}
// .3 实际使用 配置
settings.js一样的json变量
let settings = {
platform: "ios",
groupList: [
"default"
],
collisionMatrix: [
[
true
]
],
rawAssets: {
assets: {
"81eZ4OBP5K8aodrm0mUeUx": [
"Manifest/GG1/project.manifest",
"cc.Asset"
],
b1mieGwm9AvYveQiL5J9Ua: [
"Manifest/GG1/version.manifest",
"cc.Asset"
],
"63mugu3iZOj48reHFL0PpW": [
"Manifest/GG2/project.manifest",
"cc.Asset"
],
"a7IRMZApZP05+cIjIyYosD": [
"Manifest/GG2/version.manifest",
"cc.Asset"
],
f2WiYLVw1HW62wvwgXkBxf: [
"Manifest/GG3/project.manifest",
"cc.Asset"
],
f3RsjV8FdA0LKiGKFJ4N69: [
"Manifest/GG3/version.manifest",
"cc.Asset"
],
"6e8a2Bt6RD56C+449klPgK": [
"animation/flowers.anim",
"cc.AnimationClip"
],
"2dlpEdpTBG+Ir+siKhVGn9": [
"animation/flowers.plist",
"cc.SpriteAtlas"
],
f1CoDbA31A6oxWDQCh4rJr: [
"animation/flowers.png",
"cc.Texture2D"
],
"98v1T2ow9KirOlKXmERSKB": [
"animation/flowers.prefab",
"cc.Prefab"
],
"588mxohQ9PMIn2SXzlRvSs": [
"other/CloseNormal",
"cc.SpriteFrame",
1
],
dav7r5oUxIA6I8PXxNwrvA: [
"other/CloseNormal.png",
"cc.Texture2D"
],
"4cOT4SRmNNvbiuUbXWfJwC": [
"texutres/content",
"cc.SpriteFrame",
1
],
"43YDW93n1HaponMKBSdm9J": [
"texutres/content.png",
"cc.Texture2D"
],
"15l8P5pThPRpevCrnVQ1x8": [
"texutres/dlrb",
"cc.SpriteFrame",
1
],
"0fG14ZFJBJ/aIEGnJ6D70W": [
"texutres/dlrb.jpeg",
"cc.Texture2D"
],
"79kA4i8eRPj5onAzFCzUHO": [
"texutres/image",
"cc.SpriteFrame",
1
],
"2cQFeyIvFCZ5XSs99fErRi": [
"texutres/image.jpg",
"cc.Texture2D"
],
"7eQ/1cS+5GnokLdeCxfyBj": [
"texutres/wcard",
"cc.SpriteFrame",
1
],
bfxkrin9FK9oONXkkWtJQm: [
"texutres/wcard.png",
"cc.Texture2D"
]
},
internal: {
"14TDKXr2NJ6LjvHPops74o": [
"effects/builtin-2d-gray-sprite.effect",
"cc.EffectAsset"
],
"0ek66qC1NOQLjgYmi04HvX": [
"effects/builtin-2d-spine.effect",
"cc.EffectAsset"
],
"28dPjdQWxEQIG3VVl1Qm6T": [
"effects/builtin-2d-sprite.effect",
"cc.EffectAsset"
],
c0BAyVxX9JzZy8EjFrc9DU: [
"effects/builtin-clear-stencil.effect",
"cc.EffectAsset"
],
"796vrvt+9F2Zw/WR3INvx6": [
"effects/builtin-unlit-transparent.effect",
"cc.EffectAsset"
],
"6dkeWRTOBGXICfYQ7JUBnG": [
"effects/builtin-unlit.effect",
"cc.EffectAsset"
],
"6fgBCSDDdPMInvyNlggls2": [
"materials/builtin-2d-base.mtl",
"cc.Material"
],
"3ae7efMv1CLq2ilvUY/tQi": [
"materials/builtin-2d-gray-sprite.mtl",
"cc.Material"
],
"7a/QZLET9IDreTiBfRn2PD": [
"materials/builtin-2d-spine.mtl",
"cc.Material"
],
"ecpdLyjvZBwrvm+cedCcQy": [
"materials/builtin-2d-sprite.mtl",
"cc.Material"
],
cffgu4qBxEqa150o1DmRAy: [
"materials/builtin-clear-stencil.mtl",
"cc.Material"
],
"2aKWBXJHxKHLvrBUi2yYZQ": [
"materials/builtin-unlit.mtl",
"cc.Material"
]
}
},
launchScene: "db://assets/Scene/helloworld.fire",
scenes: [
{
url: "db://assets/Scene/helloworld.fire",
uuid: "2dL3kvpAxJu6GJ7RdqJG5J"
}
],
packedAssets: {
"020e176f2": [
"02delMVqdBD70a/HSD99FK",
"0fG14ZFJBJ/aIEGnJ6D70W",
"2cQFeyIvFCZ5XSs99fErRi",
"43YDW93n1HaponMKBSdm9J",
"bfxkrin9FK9oONXkkWtJQm",
"dav7r5oUxIA6I8PXxNwrvA",
"f1CoDbA31A6oxWDQCh4rJr"
],
"041f9227c": [
"2dlpEdpTBG+Ir+siKhVGn9",
"7a13M2gK9F3qMGpI+Sc8v8",
"c0fMgQNWFEw5HlwgSQQ7GJ",
"ccRsWQ6LpNk5SbfMaTZyw9",
"d8xyHtt9pDtJ3wvHEZ8Y/x",
"e0UT0oa8BOFK+82UvU/2b6",
"e7wu7ggnpObpJcyfHzwLYo",
"f9fY9cyhZCKbGFPr9RbI1+"
],
"05917af62": [
"7a13M2gK9F3qMGpI+Sc8v8",
"98v1T2ow9KirOlKXmERSKB",
"a2MjXRFdtLlYQ5ouAFv/+R",
"c0fMgQNWFEw5HlwgSQQ7GJ",
"ccRsWQ6LpNk5SbfMaTZyw9",
"d8xyHtt9pDtJ3wvHEZ8Y/x",
"e0UT0oa8BOFK+82UvU/2b6",
"e7wu7ggnpObpJcyfHzwLYo",
"f9fY9cyhZCKbGFPr9RbI1+"
],
"0c204717b": [
"2dL3kvpAxJu6GJ7RdqJG5J",
"a2MjXRFdtLlYQ5ouAFv/+R"
]
},
md5AssetsMap: {},
orientation: "",
debug: true,
subpackages: {
GG1: {
name: "GG1",
path: "subpackages/GG1/",
uuids: [
"f10a80db-037d-40ea-8c56-0d00a1e2b26b"
]
},
GG2: {
name: "GG2",
path: "subpackages/GG2/",
uuids: [
"dabfbaf9-a14c-4803-a23c-3d7c4dc2bbc0"
]
},
GG3: {
name: "GG3",
path: "subpackages/GG3/",
uuids: [
"436035bd-de7d-476a-9a27-30a052766f49",
"0f1b5e19-1490-49fd-a204-1a727a0fbd16",
"2c4057b2-22f1-4267-95d2-b3df5f12b462",
"bfc64ae2-9fd1-4af6-838d-5e4916b49426"
]
}
}
};
// .4 实际使用 代码
// add assets
cc["AssetLibrary"].add({
libraryPath: 'res/import',
rawAssetsBase: 'res/raw-',
rawAssets: settings.rawAssets,
packedAssets: settings.packedAssets,
md5AssetsMap: settings.md5AssetsMap,
subpackages: settings.subpackages
});
Object.assign(cc.loader.downloader._subpackages, settings.subpackages);
let thiz = this;
cc.loader.downloader.loadSubpackage('GG1', function (err) {
if (err) {
console.log('||load subpackage GG1 fail.');
return console.error(JSON.stringify(err));
}
console.log('||load subpackage GG1 successfully.');
console.log("||start prefab")
cc.loader.loadRes('animation/flowers', cc.Prefab, function (err, prefab) {
if (err) {
console.log("||error prefab")
cc.error(err.message || err);
return;
}
cc.log('||Result should be a prefab: ' + (prefab instanceof cc.Prefab));
console.log("||success prefab")
let prefabNode = cc.instantiate(prefab);
prefabNode.parent = thiz.node;
});
console.log("||end prefab")
});
cc.loader.downloader.loadSubpackage('GG2', function (err) {
if (err) {
return console.error(err);
}
console.log('||load subpackage GG2 successfully.');
console.log("||start image")
cc.loader.loadRes('other/CloseNormal', cc.SpriteFrame, function (err, spriteFrame) {
if (err) {
console.log("||error image")
cc.error(err.message || err);
return;
}
thiz.image.spriteFrame = spriteFrame;
cc.log('||Result should be a sprite frame: ' + (spriteFrame instanceof cc.SpriteFrame));
console.log("||success image")
});
console.log("||end image")
});