291 lines
10 KiB
YAML
291 lines
10 KiB
YAML
|
|
version: '3'
|
||
|
|
|
||
|
|
includes:
|
||
|
|
common: ../Taskfile.yml
|
||
|
|
|
||
|
|
vars:
|
||
|
|
APP_ID: '{{.APP_ID | default "com.wails.app"}}'
|
||
|
|
MIN_SDK: '21'
|
||
|
|
TARGET_SDK: '34'
|
||
|
|
# The emulator runs the host architecture; physical devices are arm64
|
||
|
|
HOST_ARCH:
|
||
|
|
sh: '[ "$(uname -m)" = "x86_64" ] && echo "amd64" || echo "arm64"'
|
||
|
|
# System-image ABI for the host, used in the "create an AVD" hint below.
|
||
|
|
ANDROID_ABI:
|
||
|
|
sh: '[ "$(uname -m)" = "arm64" ] && echo "arm64-v8a" || echo "x86_64"'
|
||
|
|
# SDK location: $ANDROID_HOME / $ANDROID_SDK_ROOT, else the per-OS default
|
||
|
|
# (macOS: ~/Library/Android/sdk, Linux/other: ~/Android/Sdk)
|
||
|
|
SDK_ROOT:
|
||
|
|
sh: 'echo "${ANDROID_HOME:-${ANDROID_SDK_ROOT:-$([ -d "$HOME/Library/Android/sdk" ] && echo "$HOME/Library/Android/sdk" || echo "$HOME/Android/Sdk")}}"'
|
||
|
|
ADB:
|
||
|
|
sh: 'command -v adb || echo "${ANDROID_HOME:-${ANDROID_SDK_ROOT:-$([ -d "$HOME/Library/Android/sdk" ] && echo "$HOME/Library/Android/sdk" || echo "$HOME/Android/Sdk")}}/platform-tools/adb"'
|
||
|
|
EMULATOR:
|
||
|
|
sh: 'command -v emulator || echo "${ANDROID_HOME:-${ANDROID_SDK_ROOT:-$([ -d "$HOME/Library/Android/sdk" ] && echo "$HOME/Library/Android/sdk" || echo "$HOME/Android/Sdk")}}/emulator/emulator"'
|
||
|
|
|
||
|
|
tasks:
|
||
|
|
install:deps:
|
||
|
|
summary: Check and install Android development dependencies
|
||
|
|
cmds:
|
||
|
|
- go run build/android/scripts/deps/install_deps.go
|
||
|
|
env:
|
||
|
|
TASK_FORCE_YES: '{{if .YES}}true{{else}}false{{end}}'
|
||
|
|
prompt: This will check and install Android development dependencies. Continue?
|
||
|
|
|
||
|
|
build:
|
||
|
|
summary: Creates a debug build of the application for Android
|
||
|
|
deps:
|
||
|
|
- task: common:go:mod:tidy
|
||
|
|
- task: generate:android:overlay
|
||
|
|
- task: common:build:frontend
|
||
|
|
vars:
|
||
|
|
BUILD_FLAGS:
|
||
|
|
ref: .BUILD_FLAGS
|
||
|
|
PRODUCTION:
|
||
|
|
ref: .PRODUCTION
|
||
|
|
cmds:
|
||
|
|
- echo "Building Android app {{.APP_NAME}}..."
|
||
|
|
- task: compile:go:shared
|
||
|
|
vars:
|
||
|
|
ARCH: '{{.ARCH | default .HOST_ARCH}}'
|
||
|
|
vars:
|
||
|
|
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production,android -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-tags android,debug -buildvcs=false -gcflags=all="-l"{{end}}'
|
||
|
|
env:
|
||
|
|
PRODUCTION: '{{.PRODUCTION | default "false"}}'
|
||
|
|
|
||
|
|
compile:go:shared:
|
||
|
|
summary: Compile Go code to shared library (.so)
|
||
|
|
cmds:
|
||
|
|
- |
|
||
|
|
# Locate the NDK: $ANDROID_NDK_HOME, or the newest installed NDK
|
||
|
|
NDK_ROOT="$ANDROID_NDK_HOME"
|
||
|
|
if [ -z "$NDK_ROOT" ]; then
|
||
|
|
SDK_ROOT="{{.SDK_ROOT}}"
|
||
|
|
NDK_ROOT=$(ls -d "$SDK_ROOT"/ndk/* 2>/dev/null | sort -V | tail -1)
|
||
|
|
fi
|
||
|
|
if [ -z "$NDK_ROOT" ] || [ ! -d "$NDK_ROOT" ]; then
|
||
|
|
echo "Error: Android NDK not found"
|
||
|
|
echo "Install one with: sdkmanager 'ndk;26.3.11579264' (or set ANDROID_NDK_HOME)"
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Determine toolchain based on host OS
|
||
|
|
case "$(uname -s)" in
|
||
|
|
Darwin) HOST_TAG="darwin-x86_64" ;;
|
||
|
|
Linux) HOST_TAG="linux-x86_64" ;;
|
||
|
|
*) echo "Unsupported host OS"; exit 1 ;;
|
||
|
|
esac
|
||
|
|
|
||
|
|
TOOLCHAIN="$NDK_ROOT/toolchains/llvm/prebuilt/$HOST_TAG"
|
||
|
|
|
||
|
|
# Set compiler based on architecture
|
||
|
|
case "{{.ARCH}}" in
|
||
|
|
arm64)
|
||
|
|
export CC="$TOOLCHAIN/bin/aarch64-linux-android{{.MIN_SDK}}-clang"
|
||
|
|
export CXX="$TOOLCHAIN/bin/aarch64-linux-android{{.MIN_SDK}}-clang++"
|
||
|
|
export GOARCH=arm64
|
||
|
|
JNI_DIR="arm64-v8a"
|
||
|
|
;;
|
||
|
|
amd64|x86_64)
|
||
|
|
export CC="$TOOLCHAIN/bin/x86_64-linux-android{{.MIN_SDK}}-clang"
|
||
|
|
export CXX="$TOOLCHAIN/bin/x86_64-linux-android{{.MIN_SDK}}-clang++"
|
||
|
|
export GOARCH=amd64
|
||
|
|
JNI_DIR="x86_64"
|
||
|
|
;;
|
||
|
|
*)
|
||
|
|
echo "Unsupported architecture: {{.ARCH}}"
|
||
|
|
exit 1
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
|
||
|
|
export CGO_ENABLED=1
|
||
|
|
export GOOS=android
|
||
|
|
|
||
|
|
mkdir -p {{.BIN_DIR}}
|
||
|
|
mkdir -p build/android/app/src/main/jniLibs/$JNI_DIR
|
||
|
|
|
||
|
|
go build -buildmode=c-shared -overlay build/android/overlay.json {{.BUILD_FLAGS}} \
|
||
|
|
-o build/android/app/src/main/jniLibs/$JNI_DIR/libwails.so
|
||
|
|
vars:
|
||
|
|
BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production,android -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-tags android,debug -buildvcs=false -gcflags=all="-l"{{end}}'
|
||
|
|
|
||
|
|
compile:go:all-archs:
|
||
|
|
summary: Compile Go code for all Android architectures (fat APK)
|
||
|
|
cmds:
|
||
|
|
- task: compile:go:shared
|
||
|
|
vars:
|
||
|
|
ARCH: arm64
|
||
|
|
- task: compile:go:shared
|
||
|
|
vars:
|
||
|
|
ARCH: amd64
|
||
|
|
|
||
|
|
package:
|
||
|
|
summary: Packages a production build of the application into a signed release APK
|
||
|
|
deps:
|
||
|
|
- task: build
|
||
|
|
vars:
|
||
|
|
PRODUCTION: "true"
|
||
|
|
ARCH: '{{.ARCH | default .HOST_ARCH}}'
|
||
|
|
cmds:
|
||
|
|
- task: assemble:apk:release
|
||
|
|
|
||
|
|
package:fat:
|
||
|
|
summary: Packages a production build for all architectures (fat APK)
|
||
|
|
deps:
|
||
|
|
- task: build
|
||
|
|
vars:
|
||
|
|
PRODUCTION: "true"
|
||
|
|
ARCH: arm64
|
||
|
|
cmds:
|
||
|
|
- task: compile:go:shared
|
||
|
|
vars:
|
||
|
|
ARCH: amd64
|
||
|
|
PRODUCTION: "true"
|
||
|
|
- task: assemble:apk:release
|
||
|
|
|
||
|
|
assemble:apk:
|
||
|
|
summary: Assembles a debug APK using Gradle
|
||
|
|
preconditions:
|
||
|
|
- sh: 'command -v java >/dev/null || [ -n "$JAVA_HOME" ]'
|
||
|
|
msg: "Java not found. Install a JDK (e.g. brew install openjdk@21) and/or set JAVA_HOME"
|
||
|
|
cmds:
|
||
|
|
- |
|
||
|
|
cd build/android
|
||
|
|
# The exec bit is lost when gradlew is extracted from the embedded
|
||
|
|
# build assets, so restore it before invoking the wrapper.
|
||
|
|
chmod +x ./gradlew
|
||
|
|
./gradlew assembleDebug
|
||
|
|
cp app/build/outputs/apk/debug/app-debug.apk "../../{{.BIN_DIR}}/{{.APP_NAME}}.apk"
|
||
|
|
echo "APK created: {{.BIN_DIR}}/{{.APP_NAME}}.apk"
|
||
|
|
|
||
|
|
assemble:apk:release:
|
||
|
|
summary: Assembles a release APK using Gradle (signed with the debug keystore unless ANDROID_KEYSTORE_FILE is set)
|
||
|
|
preconditions:
|
||
|
|
- sh: 'command -v java >/dev/null || [ -n "$JAVA_HOME" ]'
|
||
|
|
msg: "Java not found. Install a JDK (e.g. brew install openjdk@21) and/or set JAVA_HOME"
|
||
|
|
cmds:
|
||
|
|
- |
|
||
|
|
cd build/android
|
||
|
|
# The exec bit is lost when gradlew is extracted from the embedded
|
||
|
|
# build assets, so restore it before invoking the wrapper.
|
||
|
|
chmod +x ./gradlew
|
||
|
|
./gradlew assembleRelease
|
||
|
|
cp app/build/outputs/apk/release/app-release.apk "../../{{.BIN_DIR}}/{{.APP_NAME}}.apk"
|
||
|
|
echo "Release APK created: {{.BIN_DIR}}/{{.APP_NAME}}.apk"
|
||
|
|
|
||
|
|
generate:android:overlay:
|
||
|
|
internal: true
|
||
|
|
summary: Generate Go build overlay that registers the Android main
|
||
|
|
sources:
|
||
|
|
- build/config.yml
|
||
|
|
generates:
|
||
|
|
- build/android/overlay.json
|
||
|
|
- build/android/gen/main_android.gen.go
|
||
|
|
cmds:
|
||
|
|
- wails3 android overlay:gen -out build/android/overlay.json -config build/config.yml
|
||
|
|
|
||
|
|
generate:android:bindings:
|
||
|
|
internal: true
|
||
|
|
summary: Generates bindings for Android
|
||
|
|
sources:
|
||
|
|
- "**/*.go"
|
||
|
|
- go.mod
|
||
|
|
- go.sum
|
||
|
|
generates:
|
||
|
|
- frontend/bindings/**/*
|
||
|
|
cmds:
|
||
|
|
# Bindings are generated from the Go AST; CGO is disabled so the NDK
|
||
|
|
# is not required for this step
|
||
|
|
- wails3 generate bindings -f '-tags android' -clean=true
|
||
|
|
env:
|
||
|
|
GOOS: android
|
||
|
|
CGO_ENABLED: 0
|
||
|
|
|
||
|
|
ensure-emulator:
|
||
|
|
internal: true
|
||
|
|
summary: Ensure Android Emulator is running
|
||
|
|
silent: true
|
||
|
|
cmds:
|
||
|
|
- |
|
||
|
|
# Check if an emulator is already running
|
||
|
|
if "{{.ADB}}" devices | grep -q "emulator"; then
|
||
|
|
echo "Emulator already running"
|
||
|
|
exit 0
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Get first available AVD
|
||
|
|
AVD_NAME=$("{{.EMULATOR}}" -list-avds | tail -1)
|
||
|
|
if [ -z "$AVD_NAME" ]; then
|
||
|
|
echo "No Android Virtual Devices found. Create one with:"
|
||
|
|
echo " avdmanager create avd --name wails --package 'system-images;android-34;google_apis;{{.ANDROID_ABI}}' --device pixel_7"
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
echo "Starting emulator: $AVD_NAME"
|
||
|
|
# Start the emulator daemonized so it outlives this task step. go-task's
|
||
|
|
# shell tracks background jobs by PID and reaps them when the command's
|
||
|
|
# interpreter finishes (which nohup/setsid alone don't prevent — the kill
|
||
|
|
# is direct), so a bare `emulator &` is gone before the later
|
||
|
|
# install/launch steps run. Launch it from a short-lived child shell that
|
||
|
|
# backgrounds the emulator and exits immediately: the emulator is then
|
||
|
|
# reparented to init/launchd and go-task's shell has no handle to reap it.
|
||
|
|
nohup sh -c "'{{.EMULATOR}}' -avd '$AVD_NAME' -no-snapshot-load </dev/null >/dev/null 2>&1 &" >/dev/null 2>&1
|
||
|
|
|
||
|
|
# Wait for emulator to boot (max 120 seconds)
|
||
|
|
echo "Waiting for emulator to boot..."
|
||
|
|
"{{.ADB}}" wait-for-device
|
||
|
|
|
||
|
|
for i in $(seq 1 120); do
|
||
|
|
BOOT_COMPLETED=$("{{.ADB}}" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')
|
||
|
|
if [ "$BOOT_COMPLETED" = "1" ]; then
|
||
|
|
echo "Emulator booted successfully"
|
||
|
|
exit 0
|
||
|
|
fi
|
||
|
|
sleep 1
|
||
|
|
done
|
||
|
|
|
||
|
|
echo "Emulator boot timeout"
|
||
|
|
exit 1
|
||
|
|
preconditions:
|
||
|
|
- sh: '[ -x "{{.ADB}}" ] || command -v adb'
|
||
|
|
msg: "adb not found. Install the Android SDK platform-tools (or set ANDROID_HOME)"
|
||
|
|
- sh: '[ -x "{{.EMULATOR}}" ] || command -v emulator'
|
||
|
|
msg: "emulator not found. Install the Android SDK emulator package (or set ANDROID_HOME)"
|
||
|
|
|
||
|
|
deploy-emulator:
|
||
|
|
summary: Deploy the packaged release APK to the Android Emulator
|
||
|
|
deps: [package]
|
||
|
|
cmds:
|
||
|
|
- task: ensure-emulator
|
||
|
|
- '"{{.ADB}}" uninstall {{.APP_ID}} 2>/dev/null || true'
|
||
|
|
- '"{{.ADB}}" install "{{.BIN_DIR}}/{{.APP_NAME}}.apk"'
|
||
|
|
- '"{{.ADB}}" shell am start -n {{.APP_ID}}/com.wails.app.MainActivity'
|
||
|
|
|
||
|
|
run:
|
||
|
|
summary: Build, install and launch a debug build in the Android Emulator
|
||
|
|
deps:
|
||
|
|
- task: ensure-emulator
|
||
|
|
- task: build
|
||
|
|
cmds:
|
||
|
|
- task: assemble:apk
|
||
|
|
- '"{{.ADB}}" uninstall {{.APP_ID}} 2>/dev/null || true'
|
||
|
|
- '"{{.ADB}}" install "{{.BIN_DIR}}/{{.APP_NAME}}.apk"'
|
||
|
|
- '"{{.ADB}}" shell am start -n {{.APP_ID}}/com.wails.app.MainActivity'
|
||
|
|
|
||
|
|
logs:
|
||
|
|
summary: Stream Android logcat filtered to this app
|
||
|
|
cmds:
|
||
|
|
- '"{{.ADB}}" logcat -v time | grep -E "(Wails|{{.APP_NAME}})" || true'
|
||
|
|
|
||
|
|
logs:all:
|
||
|
|
summary: Stream all Android logcat (verbose)
|
||
|
|
cmds:
|
||
|
|
- '"{{.ADB}}" logcat -v time'
|
||
|
|
|
||
|
|
clean:
|
||
|
|
summary: Clean build artifacts
|
||
|
|
cmds:
|
||
|
|
- rm -rf {{.BIN_DIR}}
|
||
|
|
- rm -rf build/android/app/build
|
||
|
|
- rm -rf build/android/app/src/main/jniLibs/*/libwails.so
|
||
|
|
- rm -rf build/android/.gradle
|