fix(android): keep the debug applicationId out of Tauri's reach

`bun run android:dev` produced an APK whose applicationId was plain
com.dtourolle.jellytau, so installing it over a real release build failed
with INSTALL_FAILED_UPDATE_INCOMPATIBLE -- the only obvious way out being to
uninstall the release app and lose its data.

`tauri android build` rewrites the getByName("debug") block in the generated
copy of build.gradle.kts to inject its jniLibs.keepDebugSymbols entries. The
damage is visible in the generated file, where `packaging {` ends up with the
first injected line welded onto it. That rewrite drops applicationIdSuffix
and nothing else -- versionNameSuffix and the manifest placeholders beside it
survive -- and it happens after sync-android-sources.sh has copied the
canonical file into place and before Gradle configures, so no amount of
syncing beats it. The sideBySideRelease suffix in the release build type is
untouched by the same rewrite, which is why `build-and-deploy.sh release
--debug` kept working while the plain debug path did not.

The suffix moves to a top-level statement after the android {} block, which
is not inside what the rewriter looks for and survives. build-android.sh then
asserts the applicationId the APK actually carries, read from AGP's
output-metadata.json, so a future CLI that reaches further fails the build
instead of shipping a colliding APK.

Verified: a debug build now reports com.dtourolle.jellytau.debug, and the
statement is still there in gen/ after the CLI has run.
This commit is contained in:
2026-08-25 23:48:24 +02:00
parent bbccc8567c
commit 1ba836928f
2 changed files with 65 additions and 1 deletions
+27 -1
View File
@@ -73,7 +73,9 @@ android {
// fully-qualified class names Rust looks up over JNI, the manifest
// <service> entry and the R8 keep rules are all unaffected. The
// FileProvider authority is already ${applicationId}-relative.
applicationIdSuffix = ".debug"
//
// The suffix itself is applied AFTER this block -- see the bottom of
// this file. It cannot live here.
versionNameSuffix = "-debug"
manifestPlaceholders["appLabel"] = "JellyTau Debug"
manifestPlaceholders["activityLabel"] = "JellyTau Debug"
@@ -127,6 +129,30 @@ android {
}
}
// The debug applicationId suffix, applied from OUTSIDE the `buildTypes` block.
//
// `tauri android build` rewrites the `getByName("debug")` block in the *generated*
// copy of this file (src-tauri/gen/android/app/build.gradle.kts) to inject its
// `jniLibs.keepDebugSymbols` entries -- you can see the damage in the generated
// file, where `packaging {` ends up with the first injected line welded onto it.
// That rewrite drops `applicationIdSuffix` and nothing else: `versionNameSuffix`
// and the manifest placeholders beside it survive. It happens after
// sync-android-sources.sh has copied this file into place and before Gradle
// configures, so no amount of syncing can beat it.
//
// The result was a debug APK whose applicationId was plain
// `com.dtourolle.jellytau`, colliding with a real release install:
// INSTALL_FAILED_UPDATE_INCOMPATIBLE, with the only obvious way out being to
// uninstall the release app and lose its data. The `sideBySideRelease` suffix in
// the *release* build type is untouched by the same rewrite, which is why that
// path kept working and this one did not.
//
// A top-level statement is not inside the block the rewriter looks for, so it
// survives. scripts/build-android.sh asserts the built applicationId afterwards,
// so a future CLI that reaches further fails the build instead of shipping a
// colliding APK.
android.buildTypes.getByName("debug").applicationIdSuffix = ".debug"
rust {
rootDirRel = "../../../"
}