1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . IO ;
4+ using System . Linq ;
5+ using UnityEditor ;
6+ using UnityEditor . Build . Reporting ;
7+
8+ namespace UnityBuilderAction
9+ {
10+ public static class BuildScript
11+ {
12+ private static readonly string Eol = Environment . NewLine ;
13+
14+ private static readonly string [ ] Secrets =
15+ { "androidKeystorePass" , "androidKeyaliasName" , "androidKeyaliasPass" , "test" } ;
16+
17+ public static void Build ( )
18+ {
19+ // Gather values from args
20+ Dictionary < string , string > options = GetValidatedOptions ( ) ;
21+
22+ if ( options . TryGetValue ( "test" , out string test ) )
23+ {
24+ Console . WriteLine ( $ "Test argument: { test } ") ;
25+ }
26+
27+ // Set version for this build
28+ if ( options . TryGetValue ( "buildVersion" , out string buildVersion ) && buildVersion != "none" )
29+ {
30+ PlayerSettings . bundleVersion = buildVersion ;
31+ PlayerSettings . macOS . buildNumber = buildVersion ;
32+ }
33+ if ( options . TryGetValue ( "androidVersionCode" , out string versionCode ) && versionCode != "0" )
34+ {
35+ PlayerSettings . Android . bundleVersionCode = int . Parse ( options [ "androidVersionCode" ] ) ;
36+ }
37+
38+ // Apply build target
39+ var buildTarget = ( BuildTarget ) Enum . Parse ( typeof ( BuildTarget ) , options [ "buildTarget" ] ) ;
40+ switch ( buildTarget )
41+ {
42+ case BuildTarget . Android :
43+ {
44+ EditorUserBuildSettings . buildAppBundle = options [ "customBuildPath" ] . EndsWith ( ".aab" ) ;
45+ if ( options . TryGetValue ( "androidKeystoreName" , out string keystoreName ) &&
46+ ! string . IsNullOrEmpty ( keystoreName ) )
47+ {
48+ PlayerSettings . Android . useCustomKeystore = true ;
49+ PlayerSettings . Android . keystoreName = keystoreName ;
50+ }
51+ if ( options . TryGetValue ( "androidKeystorePass" , out string keystorePass ) &&
52+ ! string . IsNullOrEmpty ( keystorePass ) )
53+ PlayerSettings . Android . keystorePass = keystorePass ;
54+ if ( options . TryGetValue ( "androidKeyaliasName" , out string keyaliasName ) &&
55+ ! string . IsNullOrEmpty ( keyaliasName ) )
56+ PlayerSettings . Android . keyaliasName = keyaliasName ;
57+ if ( options . TryGetValue ( "androidKeyaliasPass" , out string keyaliasPass ) &&
58+ ! string . IsNullOrEmpty ( keyaliasPass ) )
59+ PlayerSettings . Android . keyaliasPass = keyaliasPass ;
60+ if ( options . TryGetValue ( "androidTargetSdkVersion" , out string androidTargetSdkVersion ) &&
61+ ! string . IsNullOrEmpty ( androidTargetSdkVersion ) )
62+ {
63+ var targetSdkVersion = AndroidSdkVersions . AndroidApiLevelAuto ;
64+ try
65+ {
66+ targetSdkVersion =
67+ ( AndroidSdkVersions ) Enum . Parse ( typeof ( AndroidSdkVersions ) , androidTargetSdkVersion ) ;
68+ }
69+ catch
70+ {
71+ UnityEngine . Debug . Log ( "Failed to parse androidTargetSdkVersion! Fallback to AndroidApiLevelAuto" ) ;
72+ }
73+
74+ PlayerSettings . Android . targetSdkVersion = targetSdkVersion ;
75+ }
76+
77+ break ;
78+ }
79+ case BuildTarget . StandaloneOSX :
80+ PlayerSettings . SetScriptingBackend ( BuildTargetGroup . Standalone , ScriptingImplementation . Mono2x ) ;
81+ break ;
82+ }
83+
84+ // Determine subtarget
85+ int buildSubtarget = 0 ;
86+ #if UNITY_2021_2_OR_NEWER
87+ if ( ! options . TryGetValue ( "standaloneBuildSubtarget" , out var subtargetValue ) || ! Enum . TryParse ( subtargetValue , out StandaloneBuildSubtarget buildSubtargetValue ) ) {
88+ buildSubtargetValue = default ;
89+ }
90+ buildSubtarget = ( int ) buildSubtargetValue ;
91+ #endif
92+
93+ // Custom build
94+ Build ( buildTarget , buildSubtarget , options [ "customBuildPath" ] ) ;
95+ }
96+
97+ private static Dictionary < string , string > GetValidatedOptions ( )
98+ {
99+ ParseCommandLineArguments ( out Dictionary < string , string > validatedOptions ) ;
100+
101+ if ( ! validatedOptions . TryGetValue ( "projectPath" , out string _ ) )
102+ {
103+ Console . WriteLine ( "Missing argument -projectPath" ) ;
104+ EditorApplication . Exit ( 110 ) ;
105+ }
106+
107+ if ( ! validatedOptions . TryGetValue ( "buildTarget" , out string buildTarget ) )
108+ {
109+ Console . WriteLine ( "Missing argument -buildTarget" ) ;
110+ EditorApplication . Exit ( 120 ) ;
111+ }
112+
113+ if ( ! Enum . IsDefined ( typeof ( BuildTarget ) , buildTarget ?? string . Empty ) )
114+ {
115+ Console . WriteLine ( $ "{ buildTarget } is not a defined { nameof ( BuildTarget ) } ") ;
116+ EditorApplication . Exit ( 121 ) ;
117+ }
118+
119+ if ( ! validatedOptions . TryGetValue ( "customBuildPath" , out string _ ) )
120+ {
121+ Console . WriteLine ( "Missing argument -customBuildPath" ) ;
122+ EditorApplication . Exit ( 130 ) ;
123+ }
124+
125+ const string defaultCustomBuildName = "TestBuild" ;
126+ if ( ! validatedOptions . TryGetValue ( "customBuildName" , out string customBuildName ) )
127+ {
128+ Console . WriteLine ( $ "Missing argument -customBuildName, defaulting to { defaultCustomBuildName } .") ;
129+ validatedOptions . Add ( "customBuildName" , defaultCustomBuildName ) ;
130+ }
131+ else if ( customBuildName == "" )
132+ {
133+ Console . WriteLine ( $ "Invalid argument -customBuildName, defaulting to { defaultCustomBuildName } .") ;
134+ validatedOptions . Add ( "customBuildName" , defaultCustomBuildName ) ;
135+ }
136+
137+ return validatedOptions ;
138+ }
139+
140+ private static void ParseCommandLineArguments ( out Dictionary < string , string > providedArguments )
141+ {
142+ providedArguments = new Dictionary < string , string > ( ) ;
143+ string [ ] args = Environment . GetCommandLineArgs ( ) ;
144+
145+ Console . WriteLine (
146+ $ "{ Eol } " +
147+ $ "###########################{ Eol } " +
148+ $ "# Parsing settings #{ Eol } " +
149+ $ "###########################{ Eol } " +
150+ $ "{ Eol } "
151+ ) ;
152+
153+ // Extract flags with optional values
154+ for ( int current = 0 , next = 1 ; current < args . Length ; current ++ , next ++ )
155+ {
156+ // Parse flag
157+ bool isFlag = args [ current ] . StartsWith ( "-" ) ;
158+ if ( ! isFlag ) continue ;
159+ string flag = args [ current ] . TrimStart ( '-' ) ;
160+
161+ // Parse optional value
162+ bool flagHasValue = next < args . Length && ! args [ next ] . StartsWith ( "-" ) ;
163+ string value = flagHasValue ? args [ next ] . TrimStart ( '-' ) : "" ;
164+ bool secret = Secrets . Contains ( flag ) ;
165+ string displayValue = secret ? "*HIDDEN*" : "\" " + value + "\" " ;
166+
167+ // Assign
168+ Console . WriteLine ( $ "Found flag \" { flag } \" with value { displayValue } .") ;
169+ providedArguments . Add ( flag , value ) ;
170+ }
171+ }
172+
173+ private static void Build ( BuildTarget buildTarget , int buildSubtarget , string filePath )
174+ {
175+ string [ ] scenes = EditorBuildSettings . scenes . Where ( scene => scene . enabled ) . Select ( s => s . path ) . ToArray ( ) ;
176+ var buildPlayerOptions = new BuildPlayerOptions
177+ {
178+ scenes = scenes ,
179+ target = buildTarget ,
180+ // targetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget),
181+ locationPathName = filePath ,
182+ // options = UnityEditor.BuildOptions.Development
183+ #if UNITY_2021_2_OR_NEWER
184+ subtarget = buildSubtarget
185+ #endif
186+ } ;
187+
188+ BuildSummary buildSummary = BuildPipeline . BuildPlayer ( buildPlayerOptions ) . summary ;
189+ ReportSummary ( buildSummary ) ;
190+ ExitWithResult ( buildSummary . result ) ;
191+ }
192+
193+ private static void ReportSummary ( BuildSummary summary )
194+ {
195+ Console . WriteLine (
196+ $ "{ Eol } " +
197+ $ "###########################{ Eol } " +
198+ $ "# Build results #{ Eol } " +
199+ $ "###########################{ Eol } " +
200+ $ "{ Eol } " +
201+ $ "Duration: { summary . totalTime . ToString ( ) } { Eol } " +
202+ $ "Warnings: { summary . totalWarnings . ToString ( ) } { Eol } " +
203+ $ "Errors: { summary . totalErrors . ToString ( ) } { Eol } " +
204+ $ "Size: { summary . totalSize . ToString ( ) } bytes{ Eol } " +
205+ $ "{ Eol } "
206+ ) ;
207+ }
208+
209+ private static void ExitWithResult ( BuildResult result )
210+ {
211+ switch ( result )
212+ {
213+ case BuildResult . Succeeded :
214+ Console . WriteLine ( "Build succeeded!" ) ;
215+ EditorApplication . Exit ( 0 ) ;
216+ break ;
217+ case BuildResult . Failed :
218+ Console . WriteLine ( "Build failed!" ) ;
219+ EditorApplication . Exit ( 101 ) ;
220+ break ;
221+ case BuildResult . Cancelled :
222+ Console . WriteLine ( "Build cancelled!" ) ;
223+ EditorApplication . Exit ( 102 ) ;
224+ break ;
225+ case BuildResult . Unknown :
226+ default :
227+ Console . WriteLine ( "Build result is unknown!" ) ;
228+ EditorApplication . Exit ( 103 ) ;
229+ break ;
230+ }
231+ }
232+ }
233+ }
0 commit comments