From b2c9dd40dcdc823b8564f6267fa24a83ce8743a3 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Wed, 4 Feb 2026 14:43:56 +0000 Subject: [PATCH] Chore: Fixed Android release script --- packages/app-mobile/tools/clean.js | 50 +++++++++++++++++++++++++-- packages/tools/cspell/dictionary4.txt | 1 + packages/tools/release-android.ts | 10 +++++- 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/packages/app-mobile/tools/clean.js b/packages/app-mobile/tools/clean.js index 0773a7a1c0..f24ad0f4b1 100644 --- a/packages/app-mobile/tools/clean.js +++ b/packages/app-mobile/tools/clean.js @@ -3,13 +3,59 @@ const fs = require('fs'); +function deleteMatchingDirs(rootDir, predicate) { + let entries; + try { + entries = fs.readdirSync(rootDir, { withFileTypes: true }); + } catch { + return; + } + + for (const entry of entries) { + if (!entry.isDirectory()) continue; + + const fullPath = `${rootDir}/${entry.name}`; + + if (predicate(fullPath)) { + fs.rmSync(fullPath, { recursive: true, force: true }); + } else { + deleteMatchingDirs(fullPath, predicate); + } + } +} + function main() { const mobileDir = `${__dirname}/..`; + + // Standard Android / iOS build artefacts fs.rmSync(`${mobileDir}/android/.gradle`, { recursive: true, force: true }); - fs.rmSync(`${mobileDir}/android/app/build`, { recursive: true, force: true }); fs.rmSync(`${mobileDir}/android/build`, { recursive: true, force: true }); + fs.rmSync(`${mobileDir}/android/app/build`, { recursive: true, force: true }); + fs.rmSync(`${mobileDir}/android/.cxx`, { recursive: true, force: true }); + fs.rmSync(`${mobileDir}/android/app/.cxx`, { recursive: true, force: true }); + + // React Native generated files that frequently break CMake/autolinking + fs.rmSync(`${mobileDir}/android/app/build/generated/autolinking`, { recursive: true, force: true }); + fs.rmSync(`${mobileDir}/android/app/build/generated/source/codegen`, { recursive: true, force: true }); + + // iOS fs.rmSync(`${mobileDir}/ios/Pods`, { recursive: true, force: true }); - console.info('To clean the Android build, in some rare cases you might also need to clear the cache in ~/.android and ~/.gradle'); + + // Delete all native module Android build artefacts + // Equivalent to: + // find . -path "*/node_modules/*/android/build" -type d -exec rm -rf {} + || true + // find . -path "*/node_modules/*/android/.cxx" -type d -exec rm -rf {} + || true + deleteMatchingDirs(mobileDir, p => + p.includes('/node_modules/') && ( + p.endsWith('/android/build') || + p.endsWith('/android/.cxx') + ), + ); + + console.info( + 'Mobile app build artefacts cleaned.\n' + + 'If you still see build issues, you may also need to clear ~/.gradle/caches and ~/.android.', + ); } try { diff --git a/packages/tools/cspell/dictionary4.txt b/packages/tools/cspell/dictionary4.txt index 63cdd11b18..cd07756c7e 100644 --- a/packages/tools/cspell/dictionary4.txt +++ b/packages/tools/cspell/dictionary4.txt @@ -247,3 +247,4 @@ youtu nocookie fgag mrjo +codegen diff --git a/packages/tools/release-android.ts b/packages/tools/release-android.ts index 83735ebc7b..14f7e75925 100644 --- a/packages/tools/release-android.ts +++ b/packages/tools/release-android.ts @@ -148,7 +148,15 @@ async function createRelease(projectName: string, releaseConfig: ReleaseConfig, } else { process.chdir(`${rnDir}/android`); apkBuildCmd = './gradlew'; - apkCleanBuild = `./gradlew clean -PbuildDir=${buildDirName}`; + + // Note: We intentionally do NOT run `./gradlew clean`. On React Native 0.8x+, `clean` is + // broken because it triggers CMake regeneration via externalNativeBuild, which re-evaluates + // autolinking and codegen and fails if generated JNI/CMake directories are missing (and for + // some reason they usually are). Manually deleting build artefacts is safer and + // deterministic. + + // apkCleanBuild = `./gradlew clean -PbuildDir=${buildDirName}`; + apkCleanBuild = 'yarn clean'; restoreDir = rootDir; }