项目中的全自动打包机制
大部分成熟的线上项目,在项目成形期都会有一套完整的自动打包流程,用于解放人力(不用让所有人都了解打包机制,使打包过程透明)。
实际上,先后经历了多个线上项目,每个项目的自动打包流程其实大同小异。本质上都是通过jenkins运行带参的bat或者shell脚本来完成自动化打包流程的。
商业项目还会分渠道打包,打出相应的渠道包。在Assets文件夹外部创建一个文件夹来放所有需要对接的平台相关资源,各个平台资源对应着不同的目录。
由此,抽象出了一整套自动化打包流程。
前期准备工作
1、各个渠道的sdk资源按渠道分类至各个渠道文件夹中,包括这个渠道打包所需要的【AndroidManife.xml、res、so、jar包、java代码】(Android)或【framework、.a文件、InfoPlisst、蕴含生命周期的UnityAppController.mm/AppDelegate.m文件】(ios)等资源文件。
2、一台单独打包机器(资金充足的话建议单独配打包机器),建议用MAC机,因为ios包只能用MAC机来打,而MAC机还能打安卓apk。
3、Jenkins,一个开源的可拓展的自动化服务器,关于Jenkins可以单独拿出来将一篇文章了,再此简单的说一下Jenkins的持续集成流程:提交代码–>拉取代码–>编译–>打包–>测试–>反馈问题–>开发处理–>提交代码,从这一流程就可以窥探到Jenkins的便利。
4、打包所用的脚本:build.bat或者build.sh脚本。
5、unity项目代码中可供打包脚本调用的打包相关静态方法。
具体流程
1、Jenkins中Build with Parameters里输入相应的打包参数,坐等打包完成,打包过程对你来说是透明的,完毕…哈哈,开个玩笑,接下用最通俗的语言带你揭秘打包流程。
2、全自动化打包流程最重要的在于打包脚本,接收到你的输入参数后开始工作,首先覆盖平台相关资源,其次拉取svn到指定版本,然后再将将指定平台写入代码中,最后关闭打包机上unity和资源管理器窗口。关闭unity尤为重要,不然unity会以进程被占用为由告诉你打包失败。
3、设置Unity宏定义,表明这个包是某个渠道的宏定义。
4、设置游戏版本号,便于后期维护发热更新。
5、构建游戏Aesstbundle资源:调用打包代码,构建资源输出到指定目录,将资源打成压缩包输出到resource目录下。
6、构建游戏安装包。
相关代码
build.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #!/bin/bash #define var
UnityCmd=/Applications/Unity/Unity.app/Contents/MacOS/Unity CurrentPath=$(cd `(dirname $0)`; pwd) PROJECTHOME=${CurrentPath}/../ FUNCTION_NAME="" BUILDHOME="" APP_NAME=""
cmdBuildAB="${UnityCmd} -quit -batchmode -projectPath ${PROJECTHOME} -executeMethod BuildEditor.BuildAndroidAB" $cmdBuildAB
cmd="${UnityCmd} -quit -batchmode -projectPath ${PROJECTHOME} -executeMethod AutoBuild.${FUNCTION_NAME} -outPath ${BUILDHOME}/${APP_NAME} -logFile" $cmd
|
C#静态方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
public static void BuildAssetBundle(int state) { DirectoryInfo direc = new DirectoryInfo(Application.streamingAssetsPath + "/AssetsBundle"); if (direc.Exists) { direc.Delete(true); }
m_abDataLs.list.Clear(); m_options = BuildAssetBundleOptions.CollectDependencies; if(state == 0 || state == 10) { m_options = BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.UncompressedAssetBundle; m_target = BuildTarget.Android; } else { m_options = BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.UncompressedAssetBundle; if(state == 1 || state == 3) { m_target = BuildTarget.iPhone; } else if(state == 2) { m_target = BuildTarget.StandaloneWindows; } } if (state == 0 || state == 1) { AutoBuild.RemoveRessToTmp(AutoBuild.SourcePrefabFileName, AutoBuild.DirecPrefabFileName); AutoBuild.MoveUIResToTemp(); }
if (state == 5) { AutoBuild.RemoveRessToTmp(AutoBuild.SourcePrefabFileNameObb, AutoBuild.DirecPrefabFileNameObb); }
if (state == 3 || state == 4) { AutoBuild.RemoveRessToTmp(AutoBuild.SourcePrefabFileName, AutoBuild.DirecPrefabFileName); }
BuildAB(state);
if (state != 3) { AssetBundleCompress(); } }
public static void Build_Apk(int XXqudao) { PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, "PLAT_SDK_XXqudao"); PlayerSettings.bundleIdentifier = "com.xxx.xxx.xxx"; BuildAndroid(XXqudao); }
static void BuildAndroid(int XXqudao) { MovePluginDir(XXqudao); ReplaceDll("Android", "DLL"); ReplaceLoadingImage(XXqudao); BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions(); buildPlayerOptions.scenes = new[] { "Assets/Scene1.unity", "Assets/Scene2.unity" }; buildPlayerOptions.locationPathName = m_outPath; buildPlayerOptions.target = BuildTarget.Android; buildPlayerOptions.options = BuildOptions.None;
BuildReport report = BuildPipeline.BuildPlayer(buildPlayerOptions); BuildSummary summary = report.summary;
if (summary.result == BuildResult.Succeeded) { Debug.Log("Build succeeded: " + summary.totalSize + " bytes"); }
if (summary.result == BuildResult.Failed) { Debug.Log("Build failed"); } RecoveryDll("DLL"); RecoveryPluginDir(); }
|
写在最后
这里只是提供一个大体的思路,实际上在自动化流程中还是有很多大大小小的坎坷的,比如一些已经成形的项目,其项目目录结构需要单独进行适配,一些渠道打包需要单独进行调整等,这些都是要考虑到的。
关于sdk:建议单独分出一个集成sdk的部门,用于将各个渠道的sdk集成到一个主的sdk上,游戏项目只需要接入一个sdk即可,使得sdk接入工作透明化,游戏开发人员专注于游戏业务逻辑的开发,更加高效。