Main changes: - go.mod: gioui.org v0.10.2, go 1.24, git.wow.st/gmp/ble e53c7be (commitNowAllowingStateLoss + BLUETOOTH_SCAN/CONNECT permission request from BlessedConnect.onAttach). - main.go: ported to the v0.10 API (app.Main + single-goroutine event loop, app.FrameEvent.Frame, material.* styles, op.Offset/ Affine, clip.Path for the circle). - On-demand rendering: no fixed 30 FPS ticker redraws. Frames are produced by Bluetooth events and input; 30 FPS only while the live stopwatch runs. The worker goroutine only polls the runtime permission (while a scan is pending) and starts the deferred scan. - widget.Clickable.Clicked must be called before Layout in v0.10: the Clickable consumes its click events during Layout. - circleClip: the clip.Path.Cube control points are relative to the pen; the second control point of each segment must be at (k-r), not (k). The old code drew a distorted, non-circular shape. - Android: perm_android.go pins a worker goroutine to one OS thread attached to the JVM for the life of the app (repeated attach/detach stack-overflows ART); the BLE view handle and scan permission state are shared with the render loop under bleMu. - os_android.go: AndroidViewEvent attach handling; os_others.go: no-op stubs for other platforms. New: - scripts/build.sh: gogio -> apktool decode -> inject BLUETOOTH_SCAN/BLUETOOTH_CONNECT into the manifest -> rebuild -> debug-sign -> install. Usage: ./scripts/build.sh [phone|emu] [--no-install]. - .gitignore: .DS_Store, *.idsig.
111 lines
4.4 KiB
Bash
Executable File
111 lines
4.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build (and optionally install) the HRM Android APK.
|
|
#
|
|
# Usage:
|
|
# ./scripts/build.sh [phone|emu] # build + install (default: phone)
|
|
# ./scripts/build.sh phone --no-install # build only
|
|
#
|
|
# Output: hrm/hrm.apk
|
|
#
|
|
# Prereqs on this workstation (the script checks each and explains what is
|
|
# missing):
|
|
# - JDK (java on PATH)
|
|
# - Go + gogio v0.10.0 (~/go/bin)
|
|
# - Android SDK at ~/android-sdk (platform-tools, build-tools 35.0.0,
|
|
# NDK for gogio)
|
|
# - 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 and only declare the pre-Android-12 BLUETOOTH/BLUETOOTH_ADMIN
|
|
# permissions. With targetSdk 31+ those are no-ops and BLE needs the
|
|
# runtime permissions BLUETOOTH_SCAN and BLUETOOTH_CONNECT declared in the
|
|
# manifest. So we decode the gogio APK, inject the two permissions into
|
|
# AndroidManifest.xml, rebuild, and re-sign with the debug key. (The
|
|
# runtime request and scan gating are implemented in Go: see
|
|
# hrm/perm_android.go.)
|
|
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 v0.10.0 in ~/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/hrm" && gogio -target android -targetsdk 34 -arch "$ARCH" -o "$WORK/hrm-raw.apk" .)
|
|
[ -f "$WORK/hrm-raw.apk" ] || die "gogio did not produce an APK"
|
|
|
|
echo "=== apktool decode + inject BLE permissions ==="
|
|
# gogio's manifest permissions come from a hardcoded table and only declare
|
|
# the pre-Android-12 permissions; the runtime permission logic itself lives
|
|
# in the Go code (hrm/perm_android.go).
|
|
java -jar "$APKTOOL" d "$WORK/hrm-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()
|
|
perms = [
|
|
'<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation"/>',
|
|
'<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>',
|
|
]
|
|
for perm in perms:
|
|
if perm not in t:
|
|
t = t.replace(" <application", " " + perm + "\n <application", 1)
|
|
if perm not in t:
|
|
sys.exit("ERROR: failed to inject " + perm)
|
|
p.write_text(t)
|
|
print("manifest: BLUETOOTH_SCAN + BLUETOOTH_CONNECT present")
|
|
PYEOF
|
|
|
|
echo "=== apktool rebuild ==="
|
|
java -jar "$APKTOOL" b "$WORK/decoded" -o "$WORK/hrm-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/hrm/hrm.apk" "$WORK/hrm-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 (start the emulator or plug in a phone; set ADB_SERIAL if several are attached)"
|
|
$ADB install -r "$REPO/hrm/hrm.apk"
|
|
fi
|
|
|
|
echo "=== DONE: $REPO/hrm/hrm.apk ==="
|