diff --git a/.gitea/workflows/build-release.yml b/.gitea/workflows/build-release.yml index 768735f..2fb34df 100644 --- a/.gitea/workflows/build-release.yml +++ b/.gitea/workflows/build-release.yml @@ -196,13 +196,17 @@ jobs: - name: Set app version from tag run: ./scripts/ci-set-version.sh + # Before init, and before the build: this edits tauri.conf.json, which is + # the input both of them read. `gen/android/app/tauri.properties` is an + # output of `android build` — it does not exist yet, and anything written + # there would be overwritten by the build anyway. + - name: Pin a monotonic Android versionCode + run: ./scripts/ci-android-version-code.sh + - name: Initialise the Android project working-directory: src-tauri run: cargo tauri android init - - name: Pin a monotonic Android versionCode - run: ./scripts/ci-android-version-code.sh - # Manifest, MainActivity, gradle config, and btleplug's Java backend. # `tauri android init` above regenerated gen/android and knows about none # of it — without this step the APK builds and then finds no trainer. diff --git a/scripts/ci-android-version-code.sh b/scripts/ci-android-version-code.sh index c359e68..51b760a 100755 --- a/scripts/ci-android-version-code.sh +++ b/scripts/ci-android-version-code.sh @@ -1,10 +1,15 @@ #!/usr/bin/env sh # Pin an explicit, monotonic Android versionCode. # -# `tauri android init` derives one from the semver in a way that is not -# monotonic across a version series: 0.1.0 and 0.0.10 can collide, and Android -# refuses to install an APK whose versionCode is not greater than the installed -# one. A rider who cannot update is a rider who stops updating. +# Tauri derives one from the semver as +# +# major * 1000000 + minor * 1000 + patch +# +# which is monotonic but leaves the pre-1.0 series crowded down at the bottom of +# the range: 0.1.0 is versionCode 1000. Android refuses to install an APK whose +# versionCode is not greater than the installed one, and a rider who cannot +# update is a rider who stops updating, so this pins the number rather than +# leaving it to a default that a Tauri upgrade could change under us: # # code = 1000 + major * 10000 + minor * 100 + patch # @@ -12,20 +17,23 @@ # semver order for any minor/patch below 100, which is well past where this # project will ever get. # -# The 1000 floor is not decoration: `tauri android init` writes versionCode=1000 -# for 0.1.0 today, so anyone carrying a locally-built APK already has that +# The 1000 floor is not decoration: Tauri's default gives 0.1.0 versionCode +# 1000, so anyone carrying an APK from before this script already has that # number installed. A bare major/minor/patch code would be 100 — a *downgrade*, # which Android refuses outright. # +# This writes bundle.android.versionCode in tauri.conf.json, NOT +# gen/android/app/tauri.properties. tauri.properties is generated by +# `cargo tauri android build`, not by `android init` — it does not exist at init +# time, and the build overwrites it from the config on every run, so an edit +# there is either a crash or a no-op. The config is the only durable input. +# # POSIX sh: the runner's /bin/sh is dash. No here-strings, no \s in sed. set -e ROOT="$(cd "$(dirname "$0")/.." && pwd)" -PROPS="$ROOT/src-tauri/gen/android/app/tauri.properties" CONF="$ROOT/src-tauri/tauri.conf.json" -[ -f "$PROPS" ] || { echo "❌ $PROPS not found — run 'cargo tauri android init' first" >&2; exit 1; } - VERSION=$(grep '"version"' "$CONF" | head -1 | sed -E 's/.*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/') MAJ=$(echo "$VERSION" | cut -d. -f1) MIN=$(echo "$VERSION" | cut -d. -f2) @@ -36,9 +44,18 @@ PAT=$(echo "$VERSION" | cut -d. -f3) CODE=$(( 1000 + MAJ * 10000 + MIN * 100 + PAT )) echo "version=$VERSION -> versionCode=$CODE" -if grep -q '^tauri.android.versionCode=' "$PROPS"; then - sed -i "s/^tauri.android.versionCode=.*/tauri.android.versionCode=$CODE/" "$PROPS" -else - echo "tauri.android.versionCode=$CODE" >> "$PROPS" -fi -cat "$PROPS" + +# The key is committed to tauri.conf.json, so a missing one means the config was +# restructured and this sed would otherwise silently do nothing — shipping an +# APK with a stale versionCode that no device would accept as an update. +grep -q '"versionCode"' "$CONF" || { + echo "❌ no \"versionCode\" key in $CONF — add bundle.android.versionCode back" >&2 + exit 1 +} +sed -i "s/\"versionCode\"[[:space:]]*:[[:space:]]*[0-9]*/\"versionCode\": $CODE/" "$CONF" + +grep -q "\"versionCode\": $CODE" "$CONF" || { + echo "❌ failed to set versionCode to $CODE in $CONF" >&2 + exit 1 +} +grep -A2 '"android"' "$CONF" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 123fcf0..e5a891a 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -42,6 +42,9 @@ "icons/icon.png" ], "category": "Utility", + "android": { + "versionCode": 1100 + }, "shortDescription": "Indoor cycling trainer control", "longDescription": "Control a smart trainer over BLE, ride gradient profiles and synthetic waveforms, and record the result." }