1. 项目背景与需求解析
在游戏开发团队协作中,我们经常遇到这样的场景:主程完成功能开发后需要将Unity工程打包成可执行文件,然后手动复制到共享目录,最后还要记得提交到SVN版本库。这套流程看似简单,但实际开发中常常出现以下问题:
- 开发者忘记执行某个步骤(特别是深夜加班时)
- 不同成员打包输出的目录结构不一致
- SVN提交时漏掉关键文件
- 手动操作耗时且容易出错
我在参与某MMO手游项目时,就曾因为打包流程不规范导致测试团队拿到了错误的版本,造成整整半天的测试资源浪费。痛定思痛后,我设计了这个自动化方案,现在分享给各位游戏开发者。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 整体方案设计
2.1 技术选型考量
实现自动化打包后处理,主要有三个技术关键点:
- 打包钩子(PostProcessBuild):Unity在2017版本后提供了完善的构建后处理接口
- 文件操作(System.IO):需要处理跨平台路径问题
- SVN命令行工具:大多数版本控制系统都提供命令行接口
为什么不使用CI/CD工具?对于中小团队来说,搭建Jenkins等持续集成系统学习成本较高,而本文方案只需在Unity工程中添加一个脚本即可实现基础自动化。
2.2 架构流程图
plaintext复制Unity打包完成
→ 触发PostProcessBuild脚本
→ 校验输出目录
→ 复制到指定位置
→ 调用svn.exe提交
→ 生成操作日志
3. 核心实现细节
3.1 构建后处理脚本
在Editor文件夹下创建PostBuildProcessor.cs:
csharp复制using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using System.IO;
using System.Diagnostics;
public class PostBuildProcessor : IPostprocessBuildWithReport
{
public int callbackOrder => 0;
public void OnPostprocessBuild(BuildReport report)
{
string buildPath = report.summary.outputPath;
string targetPath = @"\\192.168.1.100\Builds\Latest";
// 复制文件
if(Directory.Exists(targetPath))
{
Directory.Delete(targetPath, true);
}
Directory.CreateDirectory(targetPath);
CopyFilesRecursively(buildPath, targetPath);
// SVN提交
SVNCommit(targetPath);
}
private void CopyFilesRecursively(string source, string target)
{
// 递归复制实现...
}
private void SVNCommit(string path)
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = @"C:\Program Files\TortoiseSVN\bin\svn.exe";
psi.Arguments = $"commit \"{path}\" -m \"Auto commit after build\"";
psi.UseShellExecute = false;
Process.Start(psi)?.WaitForExit();
}
}
3.2 关键参数说明
- outputPath:Unity构建报告的原始输出路径
- targetPath:建议使用网络共享路径(需确保有写入权限)
- svn.exe路径:根据实际安装位置调整
- WaitForExit:确保提交完成后再继续
注意:如果使用Git替代SVN,只需修改提交命令为git push即可
4. 进阶优化方案
4.1 多平台适配
不同平台的构建后处理需要特殊处理:
csharp复制switch(report.summary.platform)
{
case BuildTarget.Android:
// 处理APK重命名
break;
case BuildTarget.iOS:
// 处理Xcode工程
break;
case BuildTarget.StandaloneWindows:
// 处理exe文件
break;
}
4.2 版本号自动管理
建议在复制前自动更新版本号:
csharp复制string version = PlayerSettings.bundleVersion;
targetPath = Path.Combine(targetPath, version);
4.3 邮件通知
构建完成后发送通知邮件:
csharp复制using System.Net.Mail;
void SendNotification(string version)
{
MailMessage mail = new MailMessage();
mail.Subject = $"新版本构建完成: {version}";
// 配置SMTP...
}
5. 常见问题排查
5.1 权限问题
症状:复制到网络共享失败
解决方案:
- 使用UNC路径而非映射驱动器
- 在代码中显式指定凭据:
csharp复制using (new NetworkConnection(@"\\server\share", new NetworkCredential("user","pass")))
{
// 文件操作...
}
5.2 SVN提交失败
典型错误:
- 工作副本已过期
- 存在冲突文件
处理策略:
csharp复制private void SVNCommit(string path)
{
// 先更新
RunSVNCommand("update", path);
// 解决冲突
if(CheckConflicts(path))
{
RunSVNCommand("resolve", path);
}
// 再提交
RunSVNCommand("commit", path);
}
5.3 路径长度限制
Windows系统默认路径长度限制为260字符,解决方法:
- 启用长路径支持(需修改注册表)
- 使用相对路径
- 缩短中间目录名
6. 性能优化建议
- 增量复制:比较文件哈希,只复制修改过的文件
- 并行处理:对大量小文件使用多线程复制
- 压缩传输:特别适合远程服务器场景
- 日志优化:记录详细的构建时间统计
csharp复制Stopwatch sw = Stopwatch.StartNew();
// 复制操作...
sw.Stop();
Debug.Log($"文件复制耗时: {sw.ElapsedMilliseconds}ms");
7. 安全注意事项
- 凭据存储:不要将SVN密码硬编码在脚本中
- 访问控制:网络共享目录应设置适当权限
- 输入验证:检查路径合法性防止注入攻击
- 异常处理:确保临时文件能被正确清理
重要:建议在PlayerSettings中设置AllowDebugging=false发布正式版本
8. 实际应用案例
在某卡牌游戏项目中,我们扩展了这个方案:
- 自动生成版本说明(从Jira提取最近完成的工单)
- 构建完成后自动上传到测试分发平台
- 通过企业微信机器人通知测试团队
- 与Jenkins集成实现双重保障
实施后构建部署时间从原来的15分钟缩短到2分钟,且实现了100%的操作准确率。
9. 扩展思路
这个基础方案可以进一步扩展:
- 自动化测试:构建后立即运行冒烟测试
- 多语言打包:根据配置生成不同语言版本
- 资源差分更新:生成与上一版本的差异包
- 构建质量分析:检查纹理压缩设置等
对于大型团队,建议结合Jenkins等CI工具实现更完整的流水线,但本文方案已经能解决80%的中小团队需求。
10. 调试技巧
当脚本不工作时,按以下步骤排查:
- 检查Unity Editor日志(Window > Analysis > Editor Log)
- 手动运行svn命令看是否正常
- 在关键节点添加Debug.Log输出
- 使用try-catch捕获异常详情
一个实用的调试代码片段:
csharp复制try {
// 你的代码...
}
catch(Exception e) {
Debug.LogError($"构建后处理失败: {e.ToString()}");
EditorUtility.DisplayDialog("错误", e.Message, "确定");
}
这个方案在我们团队已经稳定运行3年,处理了超过2000次构建任务。最大的收获不是节省了多少时间,而是彻底消除了人为失误导致的版本问题。建议每个Unity团队都尽早实施类似的自动化流程,你会惊讶于它带来的改变。
