wails3 task android:run:device uninstalls the released app (and the user's library) to install a differently-id'd build #159

Closed
opened 2026-08-20 16:59:43 +00:00 by logan · 1 comment
Collaborator

wails3 task android:run:device uninstalls the released app — and
its library — to install a build with a different id.

Found while setting up the device run for #52, before running it. I did
not execute the task; this is read from the Taskfile and confirmed
against the two ids on a real device.

build/android/Taskfile.yml line 18:

APP_ID: '{{.APP_ID | default "app.yellowjacket"}}'

run:device (line 395) builds the debug variant and then:

"{{.ADB}}" -s "$DEVICE" uninstall {{.APP_ID}} 2>/dev/null || true
"{{.ADB}}" -s "$DEVICE" install ".../yellowjacket.apk"
"{{.ADB}}" -s "$DEVICE" shell am start -n {{.APP_ID}}/com.wails.app.MainActivity

But assemble:apk runs assembleDebug, and app/build.gradle's debug
buildType carries applicationIdSuffix ".dev". So the id it
uninstalls is app.yellowjacket and the id it installs is
app.yellowjacket.dev. Measured on the device:

package: name='app.yellowjacket.dev' ...   # what run:device builds
package:app.yellowjacket                   # what run:device uninstalls

Three consequences, worst first:

  1. It deletes the user's library. The release app's data goes with
    the uninstall, and there is no undo. On the device I was handed, that
    was the published v0.3.1 with a real library on it.
  2. It then fails to launch, because am start names the package it
    just removed — a class-not-found that reads like a broken build, so
    the natural next move is to run it again.
  3. deploy-device (line 426) has the same two lines. There it is at
    least consistentpackage builds the release id — so the
    uninstall is "only" the certificate-change remedy that
    android-tier.md says never to perform. It is still an uninstall
    nobody asked for, and install -r is what it wants.

The skill reference currently recommends this task, which is how it
would have been reached: android-tier.md's "The scaffold's own tasks"
lists android:run:device as "debug build + install + launch on the
first connected physical device". That sentence is accurate about the
intent and omits the uninstall.

Suggested fix. The two ids must be derived from one statement, not
declared twice — android-tier.md already flags exactly this
("The identity is declared twice ... Nothing enforces that they
agree
") and this is that hazard cashing out. Concretely:

  • drop the uninstall from both tasks and use adb install -r;
  • give the debug-flavoured tasks APP_ID + .dev, or read the id back
    from the built APK (aapt dump badging) rather than from a default;
  • a check that fails if the APK's package name is not the one the task
    is about to launch would have caught this statically.

Until then the safe manual sequence, which is what I used for #52:

wails3 task android:build ARCH=arm64 && wails3 task android:assemble:apk
adb install -r bin/yellowjacket.apk          # never uninstall
adb shell am start -n app.yellowjacket.dev/com.wails.app.MainActivity
**`wails3 task android:run:device` uninstalls the *released* app — and its library — to install a build with a different id.** Found while setting up the device run for #52, before running it. I did not execute the task; this is read from the Taskfile and confirmed against the two ids on a real device. `build/android/Taskfile.yml` line 18: ```yaml APP_ID: '{{.APP_ID | default "app.yellowjacket"}}' ``` `run:device` (line 395) builds the **debug** variant and then: ```sh "{{.ADB}}" -s "$DEVICE" uninstall {{.APP_ID}} 2>/dev/null || true "{{.ADB}}" -s "$DEVICE" install ".../yellowjacket.apk" "{{.ADB}}" -s "$DEVICE" shell am start -n {{.APP_ID}}/com.wails.app.MainActivity ``` But `assemble:apk` runs `assembleDebug`, and `app/build.gradle`'s debug buildType carries `applicationIdSuffix ".dev"`. So the id it **uninstalls** is `app.yellowjacket` and the id it **installs** is `app.yellowjacket.dev`. Measured on the device: ``` package: name='app.yellowjacket.dev' ... # what run:device builds package:app.yellowjacket # what run:device uninstalls ``` Three consequences, worst first: 1. **It deletes the user's library.** The release app's data goes with the uninstall, and there is no undo. On the device I was handed, that was the published `v0.3.1` with a real library on it. 2. It then **fails to launch**, because `am start` names the package it just removed — a class-not-found that reads like a broken build, so the natural next move is to run it again. 3. `deploy-device` (line 426) has the same two lines. There it is at least *consistent* — `package` builds the release id — so the uninstall is "only" the certificate-change remedy that `android-tier.md` says never to perform. It is still an uninstall nobody asked for, and `install -r` is what it wants. **The skill reference currently recommends this task**, which is how it would have been reached: `android-tier.md`'s "The scaffold's own tasks" lists `android:run:device` as "debug build + install + launch on the first connected physical device". That sentence is accurate about the intent and omits the uninstall. **Suggested fix.** The two ids must be derived from one statement, not declared twice — `android-tier.md` already flags exactly this ("The identity is declared twice ... **Nothing enforces that they agree**") and this is that hazard cashing out. Concretely: - drop the `uninstall` from both tasks and use `adb install -r`; - give the debug-flavoured tasks `APP_ID` + `.dev`, or read the id back from the built APK (`aapt dump badging`) rather than from a default; - a check that fails if the APK's package name is not the one the task is about to launch would have caught this statically. Until then the safe manual sequence, which is what I used for #52: ```sh wails3 task android:build ARCH=arm64 && wails3 task android:assemble:apk adb install -r bin/yellowjacket.apk # never uninstall adb shell am start -n app.yellowjacket.dev/com.wails.app.MainActivity ```
logan self-assigned this 2026-08-20 18:06:25 +00:00
logan added the
Status
In Progress
label 2026-08-20 18:06:25 +00:00
Author
Collaborator

Taking this on fix/159-android-task-app-id.

Approach, against the issue's three suggestions:

  • Derive the id from the built APK, not from a default. aapt dump badging on the artifact each task is about to install is the one
    statement both halves already agree with by construction, which is
    what the .dev suffix defeats. The cheaper fix — APP_ID + .dev
    on the debug-flavoured tasks — leaves the class of bug alive, and
    android-tier.md has flagged it for five phases.
  • Replace the uninstall with install -r, and where that fails on
    INSTALL_FAILED_UPDATE_INCOMPATIBLE, print the remedy rather than
    performing it. A signing-certificate change is the one case an
    uninstall is right for, and it is exactly the case where it costs
    the user their library — so it is the user's call, not the task's.
  • A guard, so this is safe by construction rather than by reading
    the Taskfile first: refuse to act on a package the APK does not
    declare.

Device attached, so nothing will be run against it: app.yellowjacket
v0.3.1 (firstInstallTime 2026-08-17 23:35:56) stays untouched, and the
real run is against the emulator.

Taking this on `fix/159-android-task-app-id`. Approach, against the issue's three suggestions: - **Derive the id from the built APK**, not from a default. `aapt dump badging` on the artifact each task is about to install is the one statement both halves already agree with by construction, which is what the `.dev` suffix defeats. The cheaper fix — `APP_ID` + `.dev` on the debug-flavoured tasks — leaves the class of bug alive, and `android-tier.md` has flagged it for five phases. - **Replace the uninstall with `install -r`**, and where that fails on `INSTALL_FAILED_UPDATE_INCOMPATIBLE`, print the remedy rather than performing it. A signing-certificate change is the one case an uninstall is right for, and it is exactly the case where it costs the user their library — so it is the user's call, not the task's. - **A guard**, so this is safe by construction rather than by reading the Taskfile first: refuse to act on a package the APK does not declare. Device attached, so nothing will be run against it: `app.yellowjacket` v0.3.1 (firstInstallTime 2026-08-17 23:35:56) stays untouched, and the real run is against the emulator.
logan closed this issue 2026-08-20 19:46:36 +00:00
gitea-actions bot removed the
Status
In Progress
label 2026-08-20 19:46:46 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: yonlu/yellowjacket#159