scripts/build.sh (documented in README) builds, manifest-patches ( MANAGE_EXTERNAL_STORAGE ), signs and installs the APK in one go. Without the permission the system 'All files access' toggle is grayed out on Android 11+. GUI fix: the event loop only checks the 'updated' channel when it is not blocked in w.Event(), and gioui only emits frames on invalidation or user input, so the initial list load was never drawn until a tap. The updater now signals non-blocking and invalidates the window itself; the animation ticker gets the same wake-up treatment.
100 lines
3.9 KiB
Bash
Executable File
100 lines
3.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build (and optionally install) the passgo-gui Android APK.
|
|
#
|
|
# Usage:
|
|
# ./scripts/build.sh [phone|emu] # build + install (default: phone)
|
|
# ./scripts/build.sh phone --no-install # build only
|
|
#
|
|
# Output: cmd/passgo-gui/passgo-gui.apk
|
|
#
|
|
# Prereqs on this workstation:
|
|
# - JDK (java on PATH)
|
|
# - Go + gogio (~/go/bin)
|
|
# - Android SDK at ~/android-sdk (platform-tools, build-tools 35.0.0)
|
|
# - debug keystore at ~/.android/debug.keystore
|
|
# apktool is not a prerequisite: if it is missing, the script downloads
|
|
# v3.0.3 to the stable location ~/android-sdk/tools/apktool.jar.
|
|
#
|
|
# Why the apktool detour: gogio's manifest permissions come from a hardcoded
|
|
# table (only the legacy READ/WRITE_EXTERNAL_STORAGE). On Android 11+ the
|
|
# "All files access" settings toggle is grayed out unless the app declares
|
|
# MANAGE_EXTERNAL_STORAGE, which Permissions.java opens at startup. So we
|
|
# decode the gogio APK, inject the permission, rebuild, and re-sign with
|
|
# the debug key.
|
|
set -euo pipefail
|
|
|
|
REPO=$(cd "$(dirname "$0")/.." && pwd)
|
|
export ANDROID_HOME=${ANDROID_HOME:-$HOME/android-sdk}
|
|
export PATH=$PATH:$ANDROID_HOME/platform-tools:$ANDROID_HOME/build-tools/35.0.0:$HOME/go/bin
|
|
|
|
MODE=${1:-phone}
|
|
INSTALL=1
|
|
[ "${2:-}" = "--no-install" ] && INSTALL=0
|
|
case "$MODE" in
|
|
phone) ARCH="arm64,arm";;
|
|
emu) ARCH="amd64";;
|
|
*) echo "usage: $0 [phone|emu] [--no-install]" >&2; exit 1;;
|
|
esac
|
|
|
|
die() { echo "ERROR: $*" >&2; exit 1; }
|
|
|
|
command -v java >/dev/null 2>&1 || die "java not found"
|
|
command -v gogio >/dev/null 2>&1 || die "gogio not found (need ~/go/bin)"
|
|
command -v apksigner >/dev/null 2>&1 || die "apksigner not found (need $ANDROID_HOME/build-tools/35.0.0)"
|
|
command -v adb >/dev/null 2>&1 || die "adb not found (need $ANDROID_HOME/platform-tools)"
|
|
[ -f "$HOME/.android/debug.keystore" ] || die "debug keystore missing: $HOME/.android/debug.keystore"
|
|
|
|
# apktool: auto-download to a stable location if missing.
|
|
APKTOOL="$ANDROID_HOME/tools/apktool.jar"
|
|
if [ ! -f "$APKTOOL" ]; then
|
|
echo "=== apktool missing; downloading v3.0.3 to $APKTOOL ==="
|
|
mkdir -p "$ANDROID_HOME/tools"
|
|
curl -fsSL -o "$APKTOOL" \
|
|
https://github.com/iBotPeaches/Apktool/releases/download/v3.0.3/apktool_3.0.3.jar \
|
|
|| die "apktool download failed"
|
|
fi
|
|
|
|
WORK=$(mktemp -d)
|
|
trap 'rm -rf "$WORK"' EXIT
|
|
|
|
echo "=== gogio (Go -> APK) ==="
|
|
# targetSdk 34: targeting 35 makes Android 15 force edge-to-edge, which the
|
|
# app does not handle.
|
|
(cd "$REPO/cmd/passgo-gui" && gogio -target android -targetsdk 34 -arch "$ARCH" -o "$WORK/passgo-raw.apk" .)
|
|
[ -f "$WORK/passgo-raw.apk" ] || die "gogio did not produce an APK"
|
|
|
|
echo "=== apktool decode + inject MANAGE_EXTERNAL_STORAGE ==="
|
|
java -jar "$APKTOOL" d "$WORK/passgo-raw.apk" -o "$WORK/decoded" -f >/dev/null
|
|
python3 - "$WORK/decoded/AndroidManifest.xml" << 'PYEOF'
|
|
import sys, pathlib
|
|
p = pathlib.Path(sys.argv[1])
|
|
t = p.read_text()
|
|
perm = '<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>'
|
|
if perm not in t:
|
|
t = t.replace(" <application", " " + perm + "\n <application", 1)
|
|
if perm not in t:
|
|
sys.exit("ERROR: failed to inject MANAGE_EXTERNAL_STORAGE")
|
|
p.write_text(t)
|
|
print("manifest: MANAGE_EXTERNAL_STORAGE present")
|
|
PYEOF
|
|
|
|
echo "=== apktool rebuild ==="
|
|
java -jar "$APKTOOL" b "$WORK/decoded" -o "$WORK/passgo-unsigned.apk" >/dev/null
|
|
|
|
echo "=== sign ==="
|
|
apksigner sign \
|
|
--ks "$HOME/.android/debug.keystore" --ks-pass pass:android \
|
|
--key-pass pass:android --ks-key-alias androiddebugkey \
|
|
--out "$REPO/cmd/passgo-gui/passgo-gui.apk" "$WORK/passgo-unsigned.apk"
|
|
|
|
# ADB_SERIAL selects the device when several are attached (adb devices).
|
|
ADB="adb${ADB_SERIAL:+ -s $ADB_SERIAL}"
|
|
|
|
if [ "$INSTALL" = "1" ]; then
|
|
echo "=== install ==="
|
|
$ADB get-state >/dev/null 2>&1 || die "no adb device (connect the phone; set ADB_SERIAL if several are attached)"
|
|
$ADB install -r "$REPO/cmd/passgo-gui/passgo-gui.apk"
|
|
fi
|
|
|
|
echo "=== DONE: $REPO/cmd/passgo-gui/passgo-gui.apk ==="
|