aboutsummaryrefslogtreecommitdiff
path: root/scripts/build-apk
diff options
context:
space:
mode:
authorLena <lena@omega>2026-01-01 00:00:00 +0000
committerLena <lena@omega>2026-06-24 22:14:50 +0300
commiteb0c8951196c637e44daf3c0617b131b997d5d2c (patch)
tree2f83b6a41cee745467e53fc401942b82cea286ea /scripts/build-apk
downloadscrcpy-android-eb0c8951196c637e44daf3c0617b131b997d5d2c.tar.gz
scrcpy-android: mirror an Android device over wireless ADB0.1
Native Java app for Android 12+ that mirrors another Android device over wireless ADB, forwarding video, audio, touch input, and clipboard. Bundles a pinned scrcpy-server.jar and the vendored libadb-android stack. Supports h264/h265/av1 video and raw/opus audio with in-app codec selection. No NDK, no Kotlin. Includes JVM unit tests and a Docker-based emulator e2e rig.
Diffstat (limited to 'scripts/build-apk')
-rwxr-xr-xscripts/build-apk83
1 files changed, 83 insertions, 0 deletions
diff --git a/scripts/build-apk b/scripts/build-apk
new file mode 100755
index 0000000..9fd1409
--- /dev/null
+++ b/scripts/build-apk
@@ -0,0 +1,83 @@
+#!/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)
+#
+# Optional:
+# ANDROID_SDK_ROOT if set, apksigner is located via this; otherwise
+# the script trusts gradle's output and skips the
+# post-build verification step.
+#
+# 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"
+JAR="$ROOT/app/src/main/assets/scrcpy-server.jar"
+
+require() {
+ name="$1"
+ eval "val=\${$name:-}"
+ 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
+require KEYSTORE_PASS
+require KEY_ALIAS
+require KEY_PASS
+
+if [ ! -f "$KEYSTORE_PATH" ]; then
+ echo "build-apk: keystore not found at $KEYSTORE_PATH" >&2
+ exit 1
+fi
+
+if [ ! -f "$JAR" ]; then
+ echo "build-apk: $JAR is missing" >&2
+ echo " run scripts/update-server first" >&2
+ exit 1
+fi
+
+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}')
+
+# Best-effort: if apksigner is reachable, confirm the signature.
+APKSIGNER=""
+if [ -n "${ANDROID_SDK_ROOT:-}" ]; then
+ APKSIGNER=$(ls "$ANDROID_SDK_ROOT"/build-tools/*/apksigner 2>/dev/null | sort | tail -n 1 || true)
+fi
+if [ -z "$APKSIGNER" ] && command -v apksigner >/dev/null 2>&1; then
+ APKSIGNER=$(command -v apksigner)
+fi
+if [ -n "$APKSIGNER" ]; then
+ echo "build-apk: apksigner verify"
+ "$APKSIGNER" verify --verbose "$APK" | sed 's/^/ /'
+fi
+
+echo "build-apk: $APK"
+echo "build-apk: sha256 $SUM"