build: document the poisoned build cache; compare like with like
An entire module was missing from the APK. The app died with ClassNotFoundException for app.echo_lot.protocol.EnrollmentLink while the build was green, the module's jar was correct, and :app:dependencies listed it on debugRuntimeClasspath — its code simply never reached AGP's intermediates. The cause was a poisoned Gradle build cache entry, which is why nothing obvious fixed it: clean, rm -rf */build and --rerun-tasks all leave the build cache alone. Only --no-build-cache did. Every app build made in this session shipped without core-protocol, so enrolment, sign-in and upload would all have crashed identically; several hours of "the tap does nothing" were this, misread as a UI problem. CLAUDE.md now carries the symptom, the fix, and the verification — grepping the dex for a string literal only that module defines, because grepping for a class *name* proves nothing: callers carry the name as a reference whether or not the class is packaged. That false check is what let me believe an earlier rebuild had fixed it. Also: the enrolment dialog compared the stored endpoint against the link's public URL, so re-enrolling with the same server announced itself as a move to a different one. Those are deliberately different strings now that discovery exists; the comparison uses the public name on both sides. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
bc384531e6
commit
f6e093944c
@@ -145,6 +145,17 @@ First build downloads AGP/Compose/Shizuku from Google Maven + Maven Central.
|
|||||||
Shizuku, **toggle Wireless debugging off/on** — Shizuku keeps running (separate process), a fresh
|
Shizuku, **toggle Wireless debugging off/on** — Shizuku keeps running (separate process), a fresh
|
||||||
port + mDNS record appear, and the beacon/connector recover. Plan the Shizuku-tier dev loop
|
port + mDNS record appear, and the beacon/connector recover. Plan the Shizuku-tier dev loop
|
||||||
around this (or USB, if ever available).
|
around this (or USB, if ever available).
|
||||||
|
- **A poisoned Gradle *build cache* entry can silently drop a whole module from the APK.**
|
||||||
|
Symptom: the app dies with `ClassNotFoundException` for a class that plainly exists, while the
|
||||||
|
build is green and `./gradlew :app:dependencies` lists the module on `debugRuntimeClasspath`.
|
||||||
|
The module's own jar is correct; its code simply never reaches AGP's intermediates. `clean`,
|
||||||
|
`rm -rf */build` and `--rerun-tasks` all fail to fix it, because **none of them touch the build
|
||||||
|
cache** — look for `compileKotlin FROM-CACHE` in the log. Fix: rebuild with `--no-build-cache`.
|
||||||
|
Verify by grepping the APK's dex for a string literal that only that module defines; grepping for
|
||||||
|
a *class name* proves nothing, because callers carry the name as a reference whether or not the
|
||||||
|
class is packaged:
|
||||||
|
`unzip -o -q app-debug.apk "classes*.dex" && grep -a "pin-sha256:" *.dex`
|
||||||
|
Suspect this whenever a runtime failure contradicts a successful build.
|
||||||
- **Empty-jar race with the IDE.** VSCodium's Java/Kotlin extension runs its own Gradle daemon on
|
- **Empty-jar race with the IDE.** VSCodium's Java/Kotlin extension runs its own Gradle daemon on
|
||||||
the same project; when it overlaps a CLI build, a module's `build/libs/*.jar` can end up
|
the same project; when it overlaps a CLI build, a module's `build/libs/*.jar` can end up
|
||||||
containing only a manifest, and Gradle then considers `jar` up-to-date. Dependent modules fail
|
containing only a manifest, and Gradle then considers `jar` up-to-date. Dependent modules fail
|
||||||
|
|||||||
@@ -285,7 +285,11 @@ class RunViewModel(app: Application) : AndroidViewModel(app) {
|
|||||||
state = state.copy(
|
state = state.copy(
|
||||||
pendingEnroll = PendingEnroll(
|
pendingEnroll = PendingEnroll(
|
||||||
link = link,
|
link = link,
|
||||||
currentServer = settings.serverUrl,
|
// Compared against the link's URL, which names the server publicly — so this
|
||||||
|
// has to be the public name too. Using the endpoint made re-enrolling with the
|
||||||
|
// same server look like a move to a different one, because the endpoint and
|
||||||
|
// the public name are deliberately different strings.
|
||||||
|
currentServer = settings.serverPublicUrl,
|
||||||
newServer = target,
|
newServer = target,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user