最近一个已上线项目需要开发新的东西,并且它是在多个平台上线的。那么在日常的迭代开发过程中,设计和测试定时的需要一个当前最新的版本来查看游戏目前的一个开发状态,如果他们每个人都跑来找程序手动的打新版本,那么程序一天啥也不干就光给设计和测试打版本了。。。
于是我就写了一个.bat批处理利用Unity的batchmode来实现每天定时打版本。废话不多说,直接上代码。
bat批处理脚本:
@echo off
cd>nul
REM GET THE COMMAND LINE ARGS
SET PLATFORM=%1
REM PLATFORM possible options are: Standalone, Win, Win64, OSXUniversal, Linux64, iOS, Android, WebGL, XboxOne, PS4, WindowsStoreApps, Switch, tvOS.
SET CONFIG=%2
SET OUTPUT=%3
SET PACKAGE=%4
SET BUILDNO=%5
SET UNITY_INSTALL_ROOT_KEY="HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Unity"
SET UNITY_ICON_KEY="DisplayIcon"
FOR /F "skip=2 tokens=1,2*" %%A IN ('REG QUERY "%UNITY_INSTALL_ROOT_KEY%" /v "%UNITY_ICON_KEY%" 2^>nul') DO (
SET ValueName=%%A
SET ValueType=%%B
SET ValueValue=%%C
)
if defined ValueValue (
ECHO Unity installation detected!
ECHO %ValueValue%
) else (
ECHO "%KEY_NAME%"\"%VALUE_NAME%" not be found.
EXIT
)
PUSHD %~dp0
SET UNITY=%ValueValue%
SET LOGFILE=%CD%\build_%PLATFORM%_%CONFIG%.log
IF NOT EXIST %OUTPUT% MKDIR %OUTPUT%
ECHO Build Command:
SET BUILDCMD="%UNITY%" -buildTarget "%PLATFORM%" -batchmode -quit -projectPath %CD% -logFile "%LOGFILE%" -executeMethod AutoBuildProcessor.Build
ECHO %BUILDCMD%
%BUILDCMD% -buildArgs:"platform=%PLATFORM%;config=%CONFIG%;output=%OUTPUT%;ispackage=%PACKAGE%;buildno=%BUILDNO%;scenes=MyScreen1&MyScreen2"
SET SHOWLOG=TYPE %LOGFILE%
%SHOWLOG%
POPD
@echo on
exit %ErrorLevel%
上面.bat批处理脚本完成了:
- 读取执行.bat脚本时传入的参数;
- 检查当前环境下是否安装有对应版本的Unity;
- 创建编译时输出的log文件;
- 执行Unity的batchmode下的相关命令;
- 最后执行项目工程里类AutoBuildProcessor的static函数Build完成编译打包。
AutoBuildProcessor.cs代码:
public class AutoBuildProcessor
{
public static void Build()
{
string buildPlatform = CommandLineParser.GetCustomArgument("platform");
string buildConfig = CommandLineParser.GetCustomArgument("config");
string buildOutput = CommandLineParser.GetCustomArgument("output");
string buildPackage = CommandLineParser.GetCustomArgument("ispackage");
string buildno = CommandLineParser.GetCustomArgument("buildno");
string scenesConfig = CommandLineParser.GetCustomArgument("scenes");
UnityEngine.Debug.Log("CustomArgs: buildPlatform=" + buildPlatform + " | buildConfig=" + buildConfig + " | buildOutput=" + buildOutput + " | buildNO=" + buildno + " | isBuildPackage=" + buildPackage);
string[] scenes = { };
if (scenesConfig.Length != 0)
{
string[] sceneList = scenesConfig.Split('&');
if (sceneList.Length != 0)
scenes = new string[sceneList.Length];
for (int i = 0; i < sceneList.Length; i++)
{
UnityEngine.Debug.Log("Build Scene: " + sceneList[i]);
scenes[i] = string.Format("Assets/Scenes/{0}.unity", sceneList[i]);
}
}
BuildTargetGroup group = BuildTargetGroup.Unknown;
BuildTarget target = BuildTarget.StandaloneWindows;
string ScriptingDefineSymbols = "";
buildPlatform = buildPlatform.ToUpper();
if (buildPlatform == "WIN32")
{
group = BuildTargetGroup.Standalone;
target = BuildTarget.StandaloneWindows;
ScriptingDefineSymbols = "MyWin32CustomDefineSymbols1; MyWin32CustomDefineSymbols2";
}
else if (buildPlatform == "WIN64")
{
group = BuildTargetGroup.Standalone;
target = BuildTarget.StandaloneWindows64;
ScriptingDefineSymbols = "MyWin64CustomDefineSymbols1; MyWin64CustomDefineSymbols2";
}
else if (buildPlatform == "IOS")
{
group = BuildTargetGroup.iOS;
target = BuildTarget.iOS
ScriptingDefineSymbols = "MyIOSCustomDefineSymbols1; MyIOSCustomDefineSymbols2";
}
else if (buildPlatform == "ANDROID")
{
group = BuildTargetGroup.Android;
target = BuildTarget.Android;
ScriptingDefineSymbols = "MyAndroidCustomDefineSymbols1; MyAndroidCustomDefineSymbols2";
}
//else if ()
//{
// You can add more platforms to build
//}
PlayerSettings.SetScriptingDefineSymbolsForGroup(group, ScriptingDefineSymbols);
//switch platform. NOTE: This method is not available when running the Editor in batch mode.
//EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Switch, target);
if (!System.IO.Directory.Exists(buildOutput))
System.IO.Directory.CreateDirectory(buildOutput);
EditorUserBuildSettings.explicitNullChecks = true;
BuildOptions option = BuildOptions.None;
if (buildConfig.ToUpper() == "DEBUG")
{
option = BuildOptions.AllowDebugging | BuildOptions.Development;
}
string executablePrefix = "MyGame";
string executableSuffix = ".exe"; //Need to change others based on different platforms
string outputPath = buildOutput + "/" + executablePrefix + executableSuffix;
BuildPipeline.BuildAssetBundles("Assets", BuildAssetBundleOptions.ForceRebuildAssetBundle | BuildAssetBundleOptions.DeterministicAssetBundle, target);
string buildResult = BuildPipeline.BuildPlayer(scenes, outputPath, target, option).ToString();
}
}
public class CommandLineParser
{
private const string kCustomArgPrefix = "-buildArgs:";
private const char kCustomArgSeparator = ';';
private static char[] kCustomArgStartEndMark = { '\"' };
private enum ECustomArgumentType { CustomArgumentKey, CustomArgumentValue, CustomArgumentSize };
private static Dictionary<string, string> sCustomArgsDict = null;
public static Dictionary<string, string> GetCustomArguments()
{
Dictionary<string, string> customArgsDict = new Dictionary<string, string>();
string[] commandLineArgs = Environment.GetCommandLineArgs();
string[] customArgs;
string[] customArgBuffer;
string customArgsStr = "";
try
{
customArgsStr = commandLineArgs.Where(row => row.Contains(kCustomArgPrefix)).Single();
}
catch (Exception e)
{
UnityEngine.Debug.LogError("GetCustomArguments: Can't retrieve any custom arguments in the command line [" + commandLineArgs + "]. Exception: " + e);
return customArgsDict;
}
customArgsStr = customArgsStr.Replace(kCustomArgPrefix, "");
customArgsStr = customArgsStr.Trim(kCustomArgStartEndMark);
customArgs = customArgsStr.Split(kCustomArgSeparator);
foreach (string customArg in customArgs)
{
customArgBuffer = customArg.Split('=');
if (customArgBuffer.Length == (int)ECustomArgumentType.CustomArgumentSize)
{
customArgsDict.Add(customArgBuffer[(int)ECustomArgumentType.CustomArgumentKey], customArgBuffer[(int)ECustomArgumentType.CustomArgumentValue]);
}
else
{
UnityEngine.Debug.LogWarning("GetCustomArguments: The custom argument [" + customArg + "] seem to be malformed.");
}
}
return customArgsDict;
}
public static string GetCustomArgument(string _argumentName, string fallback = "")
{
if (sCustomArgsDict == null)
sCustomArgsDict = GetCustomArguments();
if (sCustomArgsDict.ContainsKey(_argumentName))
{
return sCustomArgsDict[_argumentName];
}
else
{
UnityEngine.Debug.LogWarning("GetCustomArgument: Can't retrieve any custom argument named [" + _argumentName + "] in the command line [" + Environment.GetCommandLineArgs() + "].");
return fallback;
}
}
}
最后将.bat批处理脚本放到Unity工程根目录下执行它就可以完成自动编译打包(当然,是在你的游戏工程没有编译错误的前提下!)。
那么,又怎么让它每天定时的执行呢?在Windows环境下可以使用它自带的[任务计划程序]应用。
这个应用的具体使用方法可以自行网上搜索。
如果是Mac环境下的话可以使用Shell脚本和Jenkins来达到相同的目的。这个等我以后有时间了也去上手试一下再来分享。