【前言】
我们知道从源代码到可执行文件有四个步骤:预编译、编译、汇编、链接
- 预编译:处理源代码文件中的以"#"开始的各种预编译指令
- 编译:通过语法语义分析等将源代码文件转为中间语言文件并进行优化,再生成汇编代码文件
- 汇编:将汇编代码文件翻译成机器指令格式的二进制文件,即生成目标文件
- 链接:将多个目标文件链接起来生成可执行文件
Unity本身不会去构建出来一个可执行文件,最终的构建流程还是依托与不同平台的构建工具,Unity的构建相当于为平台构建工具提供数据,这些数据只要是三类:代码文件、资源文件、配置文件。例如,构建出Apk最终还是需要调用Android SDK和NDK,构建出IPA最终还是要在Xcode中进行的。
一般来说,构建会在软件上提供交互入口,点击后开始自动构建,这种方式用的是软件提供的自动构建流程。
我们会有自定义构建处理的需求,在整个构建流程中会提供Hook让我们在代码中去做自定义处理。一般有三种方式:
- 提前注册
- 继承接口
- 使用特性
【Unity构建流程】
构建流程为:准备构建->资源收集->脚本编译->Shader编译->配置文件生成->平台构建
1.发起构建:调用BuildPipeline.BuildPlayer(buildPlayerOptions)发起构建,buildPlayerOptions内容如下:
- string[] scenes 要构建的场景的路径
- string locationPathName 输出路径
- string assetBundleManifestPath
- BuildTargetGroup targetGroup
- BuildTarget target
- int subtarget
- BuildOptions options
- string[] extraScriptingDefines
2.平台切换:发出回调OnActiveBuildTargetChanged,继承自IActiveBuildTargetChanged。一般来说会事先切换好。
3.准备构建:引擎先调用PrepareForBuild,其继承自BuildPlayerProcessor
在这一步,我们需要事先把需要的资源文件和配置文件准备好。Unity构建时会从Plugins和StreamingAssets文件中收集资源,构建前先将需要放入初始包的资源放入这两个文件夹中。
由于Unity认为文件夹中的所有文件都是需要收集的,这里会存在两个问题:文件夹中的某些资源在打开时不需要,需要的一些资源不在文件夹中。
存在不需要的资源是因为项目管理没做好,需要事先规定并坚持执行:不进包的资源不能放在改文件夹中。否则,出现该问题会导致初始包包体增大。如果已经出现该问题,那么积重难返,需要在构建前删掉不需要的资源。
针对不在资源中的文件夹,需要从其他地方Copy过来,例如有些Bundle要进初始包,但打包出来的Bundle在其他路径,不在StreamingAssets文件夹中;有些插件不在事先放到Plugins文件夹中也要Copy过来。
4.资源收集
5.准备完成:引擎OnPreprocessBuild,继承自IPreprocessBuildWithReport
6.编译脚本:
C#脚本经过C#编译器生成Dll,引擎调用OnPostBuildPlayerScriptDLLs,其继承自IPostBuildPlayerScriptDLLs。一般来说承载游戏逻辑的C#脚本会被编译成Assembly.Csharp.dll,Plugins文件夹中的被编译成Assembly-CSharp-firstpass.dll。可以在编译完成后做自定义处理,但这会拖慢构建速度,一般不处理。
生成Dll后UnityLinker.exe会对代码进行裁剪,裁剪前发出GenerateAdditionalLinkXmlFile,其继承自 IUnityLinkerProcessor。生成自定义的Link.xml文件用于代码剥离,可以用来优化项目构建大小,减少不必要的代码和资源,提高项目的性能和加载速度
IL2CPP对剥离后的代码进行编译,生成二进制的代码文件。
7.编译Shader
编译某个Shader前,引擎调用OnProcessShader,其继承自IPreprocessShaders
编译某个ComputeShader 前,引擎调用OnProcessComputeShader,继承自IPreprocessComputeShaders
8.构建完成:调用OnPostprocessBuild,需要继承IPostprocessBuildWithReport。对应的特性为PostProcessBuildAttribute
如果是iOS平台,这时已经生成了XCode工程,通过BuildReport.Summary.OutputPath可以知道工程路径,可以将一些ios的库拷贝到xcode工程中。如果做自动化构建,需要在代码中修改xcode工程的属性和配置。
如果需要导出Android工程,在Android Gradle工程生成后,引擎会调用OnPostGenerateGradleAndroidProject,其继承自IPostGenerateGradleAndroidProject
9.平台构建
构建APK会调用Android SDK 和NDK自动构建
构建IPA需要在Xcode工程中构建