From 6b8107504ea872bcbd51b730fcddcceff918b19f Mon Sep 17 00:00:00 2001 From: Siavash Sameni Date: Thu, 9 Apr 2026 12:02:01 +0400 Subject: [PATCH] fix(desktop): tauri capability for android event listeners + persistent debug keystore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two related Android-only papercuts found while testing build #4 on a Pixel 6: 1. Frontend was crashing in the WebView with: Tauri/Console: Uncaught (in promise) event.listen not allowed. Permissions associated with this command: core:event:allow-listen, core:event:default The desktop build worked fine because Tauri's default capability set covers the desktop side. On Android (and iOS) Tauri 2.x is much stricter about ACL — without an explicit capabilities/default.json that lists "android" in its platforms, the WebView gets zero permissions. Add a default capability granting core:default + the event listener perms across all five platforms (linux/macOS/windows/android/iOS). 2. Every fresh docker run produced a new ~/.android/debug.keystore, so `adb install -r` of a freshly built APK over an already-installed one failed with INSTALL_FAILED_UPDATE_INCOMPATIBLE. Mount a persistent host volume at /home/builder/.android in build-tauri-android.sh so the same debug keystore is reused across builds and `install -r` keeps working. Co-Authored-By: Claude Opus 4.6 (1M context) --- desktop/src-tauri/capabilities/default.json | 26 +++++++++++++++++++++ scripts/build-tauri-android.sh | 20 ++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 desktop/src-tauri/capabilities/default.json diff --git a/desktop/src-tauri/capabilities/default.json b/desktop/src-tauri/capabilities/default.json new file mode 100644 index 0000000..c08af6f --- /dev/null +++ b/desktop/src-tauri/capabilities/default.json @@ -0,0 +1,26 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "Default capability — grants core APIs (events, path, window, app, clipboard) to the main window on every platform we ship to.", + "windows": ["main"], + "platforms": [ + "linux", + "macOS", + "windows", + "android", + "iOS" + ], + "permissions": [ + "core:default", + "core:event:default", + "core:event:allow-listen", + "core:event:allow-unlisten", + "core:event:allow-emit", + "core:event:allow-emit-to", + "core:path:default", + "core:window:default", + "core:app:default", + "core:webview:default", + "shell:default" + ] +} diff --git a/scripts/build-tauri-android.sh b/scripts/build-tauri-android.sh index 362e021..a54960f 100755 --- a/scripts/build-tauri-android.sh +++ b/scripts/build-tauri-android.sh @@ -109,7 +109,10 @@ if [ "$DO_PULL" = "1" ]; then echo ">>> git fetch + reset $BRANCH" cd "$BASE_DIR/data/source" git reset --hard HEAD 2>/dev/null || true - git clean -fd 2>/dev/null || true + # NOTE: deliberately do NOT run `git clean -fd` here. It would wipe the + # tauri-generated `desktop/src-tauri/gen/android/` scaffold (gradlew, + # settings.gradle, etc.) which is expensive to recreate and breaks + # subsequent builds with "gradlew not found". git gc --prune=now 2>/dev/null || true git fetch origin "$BRANCH" 2>&1 | tail -3 git checkout "$BRANCH" 2>/dev/null || git checkout -b "$BRANCH" "origin/$BRANCH" @@ -139,6 +142,13 @@ fi PROFILE_FLAG="--debug" [ "$BUILD_RELEASE" = "1" ] && PROFILE_FLAG="" +# Persist ~/.android (where the auto-generated debug.keystore lives) so every +# build is signed with the SAME key. Without this, every fresh container gets +# a new debug keystore and `adb install -r` fails with INSTALL_FAILED_UPDATE_ +# INCOMPATIBLE because the signature changed. +mkdir -p "$BASE_DIR/data/cache/android-home" +chown 1000:1000 "$BASE_DIR/data/cache/android-home" 2>/dev/null || true + docker run --rm \ --user 1000:1000 \ -e DO_INIT="$DO_INIT" \ @@ -148,6 +158,7 @@ docker run --rm \ -v "$BASE_DIR/data/cache/cargo-git:/home/builder/.cargo/git" \ -v "$BASE_DIR/data/cache/target:/build/source/target" \ -v "$BASE_DIR/data/cache/gradle:/home/builder/.gradle" \ + -v "$BASE_DIR/data/cache/android-home:/home/builder/.android" \ wzp-android-builder \ bash -c ' set -euo pipefail @@ -158,7 +169,12 @@ npm install --silent 2>&1 | tail -5 || npm install 2>&1 | tail -20 cd src-tauri -if [ "${DO_INIT}" = "1" ] || [ ! -d gen/android ]; then +# Run init if forced, OR if the gradle wrapper is missing. Just checking +# for `gen/android` is not enough — Tauri creates a few subdirectories +# during build (app/, buildSrc/, .gradle/) that survive a partial wipe and +# would make a naive `[ ! -d gen/android ]` check return false even though +# the build wrapper itself is gone. +if [ "${DO_INIT}" = "1" ] || [ ! -x gen/android/gradlew ]; then echo ">>> cargo tauri android init" cargo tauri android init 2>&1 | tail -20 fi