#!/bin/sh
# Build a signed release APK.
#
# Required environment:
#   KEYSTORE_PATH   absolute path to a JKS / PKCS12 keystore
#   KEYSTORE_PASS   password for the keystore
#   KEY_ALIAS       alias of the signing key inside the keystore
#   KEY_PASS        password for that key (often the same as KEYSTORE_PASS)
#
# Required tooling:
#   Android build-tools 35.0.0 under ANDROID_SDK_ROOT or on PATH.
#
# Usage:
#   scripts/build-apk
#
# Output: prints the absolute path of the signed APK and its sha256.
# The signed APK lives at app/build/outputs/apk/release/app-release.apk.
#
# This script does NOT generate a keystore. Generate one once with:
#   keytool -genkey -v -keystore release.jks -alias scrcpy-android \
#       -keyalg RSA -keysize 2048 -validity 10000
# and keep it outside the repo (it must never be committed).

set -eu

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
APK="$ROOT/app/build/outputs/apk/release/app-release.apk"

require() {
    name="$1"
    val="$2"
    if [ -z "$val" ]; then
        echo "build-apk: \$$name is not set" >&2
        echo "  see the header of $0 for the required environment" >&2
        exit 1
    fi
}

require KEYSTORE_PATH "${KEYSTORE_PATH:-}"
require KEYSTORE_PASS "${KEYSTORE_PASS:-}"
require KEY_ALIAS "${KEY_ALIAS:-}"
require KEY_PASS "${KEY_PASS:-}"

if [ ! -f "$KEYSTORE_PATH" ]; then
    echo "build-apk: keystore not found at $KEYSTORE_PATH" >&2
    exit 1
fi

"$ROOT/scripts/check-wrapper"
"$ROOT/scripts/check-server"

echo "build-apk: gradle :app:assembleRelease"
cd "$ROOT"
./gradlew --no-daemon :app:assembleRelease

if [ ! -f "$APK" ]; then
    echo "build-apk: gradle finished but $APK does not exist" >&2
    exit 1
fi

SUM=$(sha256sum "$APK" | awk '{print $1}')

APKSIGNER=""
AAPT2=""
ZIPALIGN=""
SDK_ROOT="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}"
if [ -n "$SDK_ROOT" ]; then
    APKSIGNER="$SDK_ROOT/build-tools/35.0.0/apksigner"
    AAPT2="$SDK_ROOT/build-tools/35.0.0/aapt2"
    ZIPALIGN="$SDK_ROOT/build-tools/35.0.0/zipalign"
    [ -x "$APKSIGNER" ] || APKSIGNER=""
    [ -x "$AAPT2" ] || AAPT2=""
    [ -x "$ZIPALIGN" ] || ZIPALIGN=""
fi
if [ -z "$APKSIGNER" ] && command -v apksigner >/dev/null 2>&1; then
    APKSIGNER=$(command -v apksigner)
fi
if [ -z "$AAPT2" ] && command -v aapt2 >/dev/null 2>&1; then
    AAPT2=$(command -v aapt2)
fi
if [ -z "$ZIPALIGN" ] && command -v zipalign >/dev/null 2>&1; then
    ZIPALIGN=$(command -v zipalign)
fi
if [ -z "$APKSIGNER" ] || [ -z "$AAPT2" ] || [ -z "$ZIPALIGN" ]; then
    echo "build-apk: build-tools 35.0.0 are required" >&2
    echo "  set ANDROID_SDK_ROOT or put apksigner, aapt2, and zipalign on PATH" >&2
    exit 1
fi

# Capture rather than pipe: POSIX sh has no pipefail, so
# `apksigner verify | sed` reports sed's status and a rejected APK would
# sail past set -e and be announced below as if it were signed.
echo "build-apk: apksigner verify"
if ! verify_out=$("$APKSIGNER" verify --verbose --print-certs "$APK" 2>&1); then
    printf '%s\n' "$verify_out" >&2
    echo "build-apk: apksigner rejected $APK" >&2
    exit 1
fi
printf '%s\n' "$verify_out" | sed 's/^/  /'

"$ZIPALIGN" -c -P 16 4 "$APK"

expected_permissions=$(cat <<EOF
package: invalid.lena.scrcpy
uses-permission: name='android.permission.INTERNET'
uses-permission: name='android.permission.FOREGROUND_SERVICE'
uses-permission: name='android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK'
uses-permission: name='android.permission.POST_NOTIFICATIONS'
EOF
)
actual_permissions=$("$AAPT2" dump permissions "$APK")
if [ "$actual_permissions" != "$expected_permissions" ]; then
    echo "build-apk: unexpected release permissions:" >&2
    printf '%s\n' "$actual_permissions" >&2
    exit 1
fi

expected_sdk=$(cat <<EOF
minSdkVersion:'31'
targetSdkVersion:'36'
EOF
)
actual_sdk=$("$AAPT2" dump badging "$APK" \
    | sed -n '/^minSdkVersion:/p; /^targetSdkVersion:/p')
if [ "$actual_sdk" != "$expected_sdk" ]; then
    echo "build-apk: unexpected release SDK levels:" >&2
    printf '%s\n' "$actual_sdk" >&2
    exit 1
fi

expected_abis="native-code: 'arm64-v8a' 'x86_64'"
actual_abis=$("$AAPT2" dump badging "$APK" | sed -n '/^native-code:/p')
if [ "$actual_abis" != "$expected_abis" ]; then
    echo "build-apk: unexpected release ABIs: $actual_abis" >&2
    exit 1
fi

echo "build-apk: $APK"
echo "build-apk: sha256 $SUM"
