aboutsummaryrefslogtreecommitdiff
path: root/README
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 /README
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 'README')
-rw-r--r--README147
1 files changed, 147 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..a58e244
--- /dev/null
+++ b/README
@@ -0,0 +1,147 @@
+scrcpy-android
+==============
+
+
+What it does
+------------
+Native Android app that mirrors a second Android device over Wireless ADB,
+the same way scrcpy(1) does. Source device runs this app; target is any
+Android 11+ device with Wireless Debugging enabled. Video, audio, touch,
+key, and clipboard are forwarded. No root required on either side.
+
+Java only, no Kotlin, no NDK. ADB stack vendored from
+MuntashirAkon/libadb-android. scrcpy-server.jar is a pinned upstream binary
+in `app/src/main/assets/`.
+
+
+How to run it
+-------------
+Prerequisites: Android Studio (Iguana or newer) or JDK 17 + Android SDK with
+platform-tools and platform 35.
+
+ ./scripts/fetch-vendor # pull libadb-android into vendor/
+ ./scripts/update-server # download + verify pinned scrcpy-server.jar
+ ./gradlew :app:assembleDebug # build debug APK
+ adb install app/build/outputs/apk/debug/app-debug.apk
+
+For a signed release APK, see "How to build a release APK" below.
+
+On the target device: Settings -> Developer options -> Wireless debugging ->
+Pair device with pairing code. Note the displayed ip:port and 6-digit code.
+
+In the app on the source device: enter ip:port and the pairing code, tap
+Pair. Then tap the saved device row to connect and mirror.
+
+
+How to test it
+--------------
+A `./test` entrypoint runs tests inside a project-local Docker image
+(JDK 17, Android cmdline-tools, platform 35, build-tools 35, x86_64
+emulator). The image is built on first run and cached.
+
+ ./test # JVM unit tests (Wire, Sync, ControlMessages,
+ # Devices, plus piped-stream parser tests for
+ # VideoStream, AudioStream, ControlStream).
+ # ~30 s on warm cache. No KVM needed.
+
+ ./test e2e # Single-emulator self-mirror end-to-end.
+ # Boots the API-35 AOSP emulator, roots it,
+ # installs the debug APK, drops the app's public
+ # key into /data/misc/adb/adb_keys, launches
+ # Mirror against 127.0.0.1:5555, then asserts
+ # 'video frame n=1' lands in logcat and the
+ # screencap is non-uniform. Then kills the server
+ # on the target and asserts the session detects the
+ # dropped link and auto-reconnects (a fresh
+ # 'video frame n=1'). Needs /dev/kvm readable by the
+ # invoking uid.
+
+ ./test all # unit tests followed by e2e. Fails fast: if the
+ # unit tier fails, the e2e tier is skipped.
+ # Same /dev/kvm requirement as `./test e2e`.
+
+ ./test record # Boots the emulator, runs a Mirror session, injects
+ # taps/keys, and stitches a screen recording into
+ # ./output.mp4. Needs /dev/kvm.
+
+ ./test apk # Smoke build: generates a throwaway PKCS12 keystore
+ # under .tools/, runs scripts/build-apk against it,
+ # verifies the resulting APK is signed. No KVM.
+
+If /dev/kvm is not rw for your uid the script prints the one-line fix
+and exits - it does not auto-chmod.
+
+
+How to build a release APK
+--------------------------
+Set four environment variables and run the release script:
+
+ export KEYSTORE_PATH=/abs/path/to/release.jks
+ export KEYSTORE_PASS=...
+ export KEY_ALIAS=...
+ export KEY_PASS=...
+ ./scripts/build-apk
+
+The signed APK lands at
+`app/build/outputs/apk/release/app-release.apk` and its sha256 is
+printed at the end. If `apksigner` is reachable (either on $PATH or
+under $ANDROID_SDK_ROOT/build-tools/) the script also runs a
+post-build `apksigner verify`.
+
+Generate a release keystore once with:
+
+ keytool -genkey -v -keystore release.jks -storetype PKCS12 \
+ -alias scrcpy-android -keyalg RSA -keysize 2048 -validity 10000
+
+Keep it OUTSIDE the repo. The .gitignore does not protect arbitrary
+filenames; the keystore is your secret.
+
+
+How to debug it
+---------------
+Everything is logged with tag `scrcpy-android`:
+
+ adb logcat -s scrcpy-android
+
+Expected log sequence on a successful connect (pair ok appears once,
+at pairing time):
+
+ pair ok host=... pair_port=...
+ adb connect ok
+ push /data/local/tmp/scrcpy-server.jar bytes=...
+ spawn server ver=<v> scid=<hex>
+ openAbstract scrcpy_<scid> ok (attempt <n>) (x3)
+ video meta codec=h264
+ audio meta codec=raw (or opus if selected in Settings)
+ video session meta <w>x<h> client_resize=false
+ video frame n=1
+
+Server stdout/stderr is pumped into the same log stream prefixed with
+`server: ` so target-side errors are visible without an extra adb shell.
+
+
+Layout
+------
+ app/ Android module (Java)
+ vendor/libadb-android/ vendored libadb module, pinned tag, plus licenses
+ scripts/ POSIX sh, set -eu
+ gradle/, gradlew* Gradle 8.9 wrapper
+ LICENSE Apache-2.0
+
+
+Constraints
+-----------
+- minSdk 31 (source device needs Android 12+); compileSdk = targetSdk =
+ 35 (built against and targeting Android 15)
+- Wireless ADB only; no USB-OTG host mode
+- Multi-touch, soft keys, clipboard sync, and hardware Back (long-press
+ the device Back key while Mirror is foreground) are forwarded.
+- Video codec (h264 / h265 / av1) and audio codec (raw / opus) are
+ selectable from the in-app Settings screen; defaults are h264 + raw.
+
+
+License
+-------
+Apache-2.0; see LICENSE. Bundles libadb-android (dual GPL-3.0-or-later OR
+Apache-2.0, used here under Apache-2.0) and a pinned, checksum-verified
+scrcpy-server.jar from Genymobile/scrcpy (Apache-2.0).