前言
我已经在mac上搭建了一套自动化打包流程,但是是用的sh,首先无法跨平台,其次成本比较高(穷~),借鉴python等工具,构思了一下从自己熟悉的js语言重构这套流程,目前已基本实现打包流程的自动化.
听闻官方也准备有个集成的热更方案,也许此教程不久就没什么价值了~
准备
-
操作系统
windows、mac
因为cocos官方没有支持linus构建,所以如果想用linux需要先在windows或mac上先构建,然后继续下面的步骤(为什么要多此一举,同时希望官方能尽快支持linux构建)
-
技术栈
nodejs – 必须
python – 非必须 如果需要使用到腾讯cos则需要会安装
jenkins – 如果想自动触发,则理论必须
构建原理
命令行构建
- CCC支持命令行构建
参考官方文档 命令行发布项目.
- AndroidStudio 提供了gradlew命令行构建脚本
构建步骤
如果只是构建web平台,那么看完文档安装好jenkins理论上整个流程就可以完成,我这边主要是原生工程的构建,主要是以下几个步骤:
- 构建项目
- 制作更新包
- 打包原生工程
能用node的原理
1.nodejs可以通过 require(“child_process”).exec 命令执行sh或cmd命令
2.cos支持cmd上传,SDK文档
主要流程
构建项目
我们在项目目录下,新建一个目录,自定义即可,主要是配置一些基础参数,为了保证windows和mac平台都可以使用,我这里用的是json配置,参考如下:
{
"clientVer": "1.0.0.0",
"debug": false,
"appVer": "1.0.0",
"appCode": 1,
"channel":["测试"],
"engineVer": "2.3.3",
"title": "PackTest",
"packageName": "com.xyzzlky.test.pack",
"apiLevel": 28,
"appABIs": ["armeabi-v7a"],
"xxteaKey": "318927a2-2183-4c",
"appName": "自动化打包测试",
"appId": "1",
"appKey": "1",
"buglyAppId": "1",
"buglyAppKey": "1",
"orientation":"portrait"
}
- clientVer 是配置当前构建的版本
- debug 是否是测试版本,如果是则不上传到cos
- appVer 安卓的versionName
- appCode 安卓的versionCode
- channel 打包的渠道
- engineVer 引擎版本
- title 构建的项目名 安卓打包的项目名
- packageName 安卓的包名
- apiLevel 安卓sdk版本
- appABIs 支持的cpu架构
- xxteaKey js加密密钥
- appName 安卓应用名称
- appId sdk的appid
- appKey sdk的appkey
- buglyAppId bugly的appId
- buglyAppKey bugly的appKey
- orientation 设备方向
据此,先写出构建的cmd命令
let cmd =
config.enginePath +
' --path ' + config.path +
' --build title=' + config.title +
';packageName=' + config.packageName +
';apiLevel=' + config.apiLevel +
';appABIs=' + appABIs +
';xxteaKey=' + config.xxteaKey +
';template=link;platform=android;debug=false;inlineSpriteFrame=false;mergeStartScene=false;optimizeHotUpdate=false;useDebugKeystore=true;md5Cache=false;encryptJs=true;zipCompressJs=true;'
- 最后一行的配置我是写死的,如果有需要,都可以放到配置中。
- 因为mac和windows路径是不同的,所以要区分下目录,比如
if (utils.isMac()) {
enginePath = '/Applications/CocosCreator/Creator/' + config.engineVer + '/CocosCreator.app/Contents/MacOS/CocosCreator';
} else {
enginePath = 'C:/CocosDashboard/resources/.editors/Creator/' + config.engineVer + '/CocosCreator.exe';
}
- 根据版本配置,也可以通过每次打包备份原版本,然后比较代码,判断是否进行构建,比如
if (utils.compareVersion(config.clientVer, backConfig.clientVer || '0')) {
console.log('Coocs开始构建');
config.path = projectPath;
ccc.pack(config).then(() => {
console.log('Cocos构建成功');
hotupdate();
}).catch(() => {
console.log('Cocos构建失败');
});
} else {
pack();
}
然后执行该命令,理论上包就打好了。
utils.runSh(cmd);
热更配置
官方文档也有相关的说明,这里我们根据自己的需求,做出一些修改,主要有以下几个方面的不同
- manifest 不纳入版本管理 所以我们项目中不能出现manifest后缀的文件(这里是为了方便大版本升级时,能判断热更版本号和包中版本号的大小关系,是否清空缓存)
- 考虑cdn缓存问题,我们热更每次的目录不同,所以链接是不同的(同时这样做,可以后台指定用户的热更版本,逻辑代码可以指定是否允许回退)
- 构建的代码需要打包,包里面的project需要保持最新,网上用的方法是二次打包机制,因为我们有第一步的保障,项目内只有一个manifest,可以一次打包,然后替换即可。
因为有目录关系,首先,我们根据版本创建目录,并把构建目录中的代码复制过来
// 复制文件到当前文件夹
const src = mfs.join(buildPath, 'src');
const res = mfs.join(buildPath, 'res');
const subpackages = mfs.join(buildPath, 'subpackages');
const dirPath = mfs.join(packPath, dirName);
mfs.cp(src, mfs.join(dirPath, 'src'));
mfs.cp(res, mfs.join(dirPath, 'res'));
mfs.cp(subpackages, mfs.join(dirPath, 'subpackages'));
注意,每个版本的目录形式不一致,需要自行做出一定的修改
之后我们就可以生成manifest文件,如下
let manifest = {};
const dirInfo = mfs.parse(config.dirPath);
manifest.packageUrl = url + '/' + dirInfo.base + '/';
manifest.remoteManifestUrl = manifest.packageUrl + 'project.manifest';
manifest.remoteVersionUrl = manifest.packageUrl + 'version.manifest';
manifest.version = config.version;
const destVersion = mfs.join(config.dirPath, 'version.manifest');
mfs.writeFile(destVersion, JSON.stringify(manifest, null, 4));// 写入基本信息到version.manifest
manifest.assets = {};
const paths = mfs.readDir(config.dirPath);
let manifestPath = '';
paths.forEach(filePath => {
const relative = encodeURI(mfs.relative(config.dirPath, filePath).replace(/\\/g, '/'));
if (mfs.extname(filePath) === '.manifest') { // manifest 不进行更新
manifestPath = relative;
return;
}
manifest.assets[relative] = {
size: mfs.size(filePath),
md5: utils.md5(mfs.readFile(filePath, 'binary'))
};
const compressed = mfs.extname(filePath).toLowerCase() === '.zip';
if (compressed) {
manifest.assets[relative].compressed = true;
}
});
const destManifest = mfs.join(config.dirPath, 'project.manifest');
mfs.writeFile(destManifest, JSON.stringify(manifest, null, 0));
return {
manifest: manifest,
path: manifestPath
}
本代码主要是生成md5以及找出manifest的目录,当manifest生成完毕后,我们就可以将该文件更新到build目录下面manifest, 并上传到cos
const destManifest = mfs.join(buildPath, info.path);
mfs.writeFile(destManifest, JSON.stringify(info.manifest, null, 0));
const cmd = 'coscmd upload -r ' + dirPath + ' ' + cosPath;
utils.runSh(cmd).then(() => {
console.log('上传成功');
backConfig.clientVer = config.clientVer;
pack();
}).catch(() => {
console.log('上传cos失败');
});
热更步骤,相对简单,如上就完成了热更打包,更新以及上传到cos。
完成以上工作后,我们将要编译一个安卓包出来,这样整个流程就完毕了。
安卓打包
任务列表
- [x] 打包构建
- [x] APK信息修改
- [ ] 修改icon
- [ ] sdk自动接入
安卓打包,说简单也简单——调用gradlew命令即可,说复杂也复杂,特别是我们如果接入了一些sdk的话,比如接入bugly就需要修改build.gradle,正则修改是一个方式,但太过于繁琐,所以——我直接重写了整个文件,文件过于冗杂,就不贴了,主要是修改一些参数,其中的运用了多渠道,各位可以下载我的工程查看。另外,示例工程中,我们的icon什么的都没有换,接入SDK还有一些文件需要替换,自己需要定义这一块内容,当然我完善后,也会同步更新到仓库中。
打包的话,直接调用gradlew即可(其实百度了好久,才知道方式)
请保证这个工程能正常运行,gradle版本什么已经下载下来了,不然这一步会卡到世界末日,你也看不到进度
utils.execFile('gradlew.bat', [':' + config.title + ':assembleRelease'], { cwd: config.androidPath }, (error, stdout, stderr) => {
if (error) {
console.log('error', error);
reject();
} else {
console.log('执行成功');
resolve();
}
});
- 如果发现该命令卡住,可以手动到android目录下执行gradlew命令查看原因,大部分情况是在下载gradle
执行
-
请确保已经安装jenkins(一步步next即可)
-
配置好git/svn/网址触发方式(请自行百度教程)
修改config的版本号,提交git或请求网址即可。
一些命令都被我封装了,包含但不仅仅包含:文件处理相关、执行cmd等,完整代码,请关注公众号【xyzzlky】回复AutoPack 获取。

咱们自己不是也有的咩