@@ -92,6 +92,49 @@ function runPathmodePatch({ allowMissing }) {
9292 return patchResult . status === 0 ;
9393}
9494
95+ function spawnTauriCommand ( tauriArgs , envOverrides ) {
96+ const isWindows = process . platform === 'win32' ;
97+ const execCommand = isWindows ? 'cmd.exe' : 'npx' ;
98+ const execArgs = isWindows ? [ '/d' , '/s' , '/c' , 'npx' , ...tauriArgs ] : tauriArgs ;
99+
100+ return spawnSync ( execCommand , execArgs , {
101+ stdio : 'inherit' ,
102+ env : envOverrides
103+ } ) ;
104+ }
105+
106+ function ensureAndroidProjectScaffold ( envOverrides ) {
107+ const androidAppDir = path . resolve ( __dirname , '..' , 'src-tauri' , 'gen' , 'android' , 'app' ) ;
108+ if ( existsDir ( androidAppDir ) ) {
109+ return true ;
110+ }
111+
112+ console . log ( '[Tauri Android Runner] Android scaffold is missing. Bootstrapping with: npx tauri android init --ci' ) ;
113+ const initResult = spawnTauriCommand ( [ 'tauri' , 'android' , 'init' , '--ci' ] , envOverrides ) ;
114+
115+ if ( initResult . error ) {
116+ console . error ( `[Tauri Android Runner] Failed to start android init: ${ initResult . error . message } ` ) ;
117+ return false ;
118+ }
119+ if ( initResult . signal ) {
120+ console . error ( `[Tauri Android Runner] Android init terminated by signal: ${ initResult . signal } ` ) ;
121+ return false ;
122+ }
123+
124+ const initStatus = initResult . status === null ? 1 : initResult . status ;
125+ if ( initStatus !== 0 ) {
126+ console . error ( `[Tauri Android Runner] Android init failed with status ${ initStatus } .` ) ;
127+ return false ;
128+ }
129+
130+ if ( ! existsDir ( androidAppDir ) ) {
131+ console . error ( `[Tauri Android Runner] Android init completed but scaffold is still missing: ${ androidAppDir } ` ) ;
132+ return false ;
133+ }
134+
135+ return true ;
136+ }
137+
95138function main ( ) {
96139 const mode = process . argv [ 2 ] ;
97140 const cliTarget = process . argv [ 3 ] ;
@@ -117,10 +160,6 @@ function main() {
117160 if ( target ) {
118161 tauriArgs . push ( '--target' , target ) ;
119162 }
120-
121- const isWindows = process . platform === 'win32' ;
122- const execCommand = isWindows ? 'cmd.exe' : 'npx' ;
123- const execArgs = isWindows ? [ '/d' , '/s' , '/c' , 'npx' , ...tauriArgs ] : tauriArgs ;
124163 const cargoBuildJobs = String ( parsePositiveInt ( process . env . CARGO_BUILD_JOBS , 1 ) ) ;
125164 const cargoReleaseOptLevel = String ( process . env . CARGO_PROFILE_RELEASE_OPT_LEVEL || '0' ) ;
126165 const cargoReleaseCodegenUnits = String (
@@ -131,9 +170,29 @@ function main() {
131170 const cargoReleasePanic = String ( process . env . CARGO_PROFILE_RELEASE_PANIC || 'abort' ) ;
132171 const cargoIncremental = String ( process . env . CARGO_INCREMENTAL || '0' ) ;
133172 const rustflags = appendRustflag ( process . env . RUSTFLAGS , '-C debuginfo=0' ) ;
134-
135- // For dev/build, Android project should already exist and must be patched before compile.
173+ const tauriEnv = {
174+ ...process . env ,
175+ ANDROID_HOME : sdkRoot ,
176+ ANDROID_SDK_ROOT : sdkRoot ,
177+ NDK_HOME : ndkHome ,
178+ ANDROID_NDK_HOME : ndkHome ,
179+ CARGO_BUILD_JOBS : cargoBuildJobs ,
180+ CARGO_PROFILE_RELEASE_OPT_LEVEL : cargoReleaseOptLevel ,
181+ CARGO_PROFILE_RELEASE_CODEGEN_UNITS : cargoReleaseCodegenUnits ,
182+ CARGO_PROFILE_RELEASE_DEBUG : cargoReleaseDebug ,
183+ CARGO_PROFILE_RELEASE_LTO : cargoReleaseLto ,
184+ CARGO_PROFILE_RELEASE_PANIC : cargoReleasePanic ,
185+ CARGO_INCREMENTAL : cargoIncremental ,
186+ RUSTFLAGS : rustflags
187+ } ;
188+
189+ // Dev/build commands require the generated Android project before patching.
136190 if ( mode === 'dev' || mode === 'build' ) {
191+ if ( ! ensureAndroidProjectScaffold ( tauriEnv ) ) {
192+ console . error ( '[Tauri Android Runner] Failed to prepare Android scaffold before build/dev.' ) ;
193+ process . exit ( 1 ) ;
194+ }
195+
137196 if ( ! runPathmodePatch ( { allowMissing : false } ) ) {
138197 console . error ( '[Tauri Android Runner] Failed to apply Android Pathmode patch before build/dev.' ) ;
139198 process . exit ( 1 ) ;
@@ -160,24 +219,7 @@ function main() {
160219 }
161220 console . log ( `[Tauri Android Runner] Executing: npx ${ tauriArgs . join ( ' ' ) } ` ) ;
162221
163- const result = spawnSync ( execCommand , execArgs , {
164- stdio : 'inherit' ,
165- env : {
166- ...process . env ,
167- ANDROID_HOME : sdkRoot ,
168- ANDROID_SDK_ROOT : sdkRoot ,
169- NDK_HOME : ndkHome ,
170- ANDROID_NDK_HOME : ndkHome ,
171- CARGO_BUILD_JOBS : cargoBuildJobs ,
172- CARGO_PROFILE_RELEASE_OPT_LEVEL : cargoReleaseOptLevel ,
173- CARGO_PROFILE_RELEASE_CODEGEN_UNITS : cargoReleaseCodegenUnits ,
174- CARGO_PROFILE_RELEASE_DEBUG : cargoReleaseDebug ,
175- CARGO_PROFILE_RELEASE_LTO : cargoReleaseLto ,
176- CARGO_PROFILE_RELEASE_PANIC : cargoReleasePanic ,
177- CARGO_INCREMENTAL : cargoIncremental ,
178- RUSTFLAGS : rustflags
179- }
180- } ) ;
222+ const result = spawnTauriCommand ( tauriArgs , tauriEnv ) ;
181223
182224 if ( result . error ) {
183225 console . error ( `[Tauri Android Runner] Failed to start command: ${ result . error . message } ` ) ;
0 commit comments