Skip to content

Repository files navigation

WatchPush

Build Release License Min SDK

Sideload an APK onto a Pixel Watch straight from your phone. No computer, no cable, no adb binary on your PATH — the app speaks the ADB wire protocol itself: mDNS discovery, Wireless-debugging pairing (SPAKE2), TLS transport, a sync: file push, then pm install on the watch.

Download the latest APK →

Requires Android 8.0+ on the phone and a Wear OS 3+ watch (Pixel Watch 1/2/3, Galaxy Watch 4+, and anything else with Wireless debugging).

Why Wi-Fi and not Bluetooth

Wear OS "debug over Bluetooth" is not a phone-to-watch feature. It's a tunnel the Wear OS companion app opens for a computer plugged into the phone over USB (adb forward tcp:4444 localabstract:/adb-hub). There is no supported way for a third-party phone app to drive that hub, and Android's SELinux policy blocks reaching another app's local socket anyway. Wireless debugging over Wi-Fi is what Google actually exposes, it's considerably faster, and it's what WatchPush uses.

Both devices need to be on the same Wi-Fi network and the same subnet — guest networks and AP-isolated networks won't work.

Using it

  1. On the watch — Settings → System → About → tap Build number seven times to unlock Developer options, then Settings → Developer options → Wireless debugging → on.
  2. Step 1: pick the .apk. WatchPush shows the parsed label, package name, version and size, and flags whether the APK declares android.hardware.type.watch.
  3. Step 2: pair — first time only. On the watch tap Pair new device; it shows an IP, a pairing port, and a six-digit code. In the app tap Scan network and tap the endpoint labelled pair (or tap Pair… and type it), enter the code, tap Pair.
  4. Step 2: connect. Back on the watch's Wireless debugging screen there's a different port next to the IP. Tap the connect endpoint from the scan, or type IP + port, then Connect. The banner turns green and names the watch.
  5. Step 3: Install on watch. Live progress bar during the transfer; the activity log records every step and reproduces any pm install error verbatim.

Pairing is one-time — the app keeps an RSA key pair in its private storage, exactly like ~/.android/adbkey on a desktop. Reconnecting after a watch reboot only needs step 4, but note the watch picks a new port every time Wireless debugging restarts.

Troubleshooting

Symptom Cause
Scan finds nothing Devices on different networks, or AP isolation on the router. Type the IP manually.
Connection refused Wireless debugging switched itself off, or the port changed after a reboot.
Connect hangs, then fails Not paired yet, or the pairing was dropped — pair again.
INSTALL_FAILED_* The watch rejected the APK (wrong ABI, signature clash with an installed copy, downgrade). The full pm output is in the log.

How it works

File Role
AdbKeys.kt Generates and persists the RSA-2048 key pair plus a self-signed X509 certificate (BouncyCastle).
WatchAdb.kt AbsAdbConnectionManager singleton holding the live connection.
AdbDiscovery.kt NsdManager mDNS scan for _adb-tls-pairing._tcp / _adb-tls-connect._tcp, filtering out this phone's own services.
AdbTransfer.kt ADB sync: SEND/DATA/DONE push in 64 KB chunks, and shell: command execution.
ApkStager.kt Copies the picked content:// APK into the cache and parses its manifest.
MainViewModel.kt State machine; all ADB work runs under runInterruptible(Dispatchers.IO) so it cancels cleanly.
ui/ Compose Material 3 — Material You dynamic colour on Android 12+, a Pixel-blue scheme below that, large corner radii, pill buttons, themed monochrome launcher icon.

The install path is push-then-install (/data/local/tmp/…pm install -r -t -drm) rather than a streamed cmd package install -S, because it yields an accurate byte-level progress bar.

Building

./gradlew :app:assembleRelease

JDK 17 and an Android SDK with platform 35 are required; point local.properties at your SDK (sdk.dir=...).

Release signing is opt-in. Without a keystore the release build falls back to the debug key so a fresh clone still builds. To sign with your own key, create keystore.properties in the repo root:

storeFile=keystore/my-release.jks
storePassword=…
keyAlias=…
keyPassword=…

Both that file and keystore/ are gitignored. Published releases are signed with a key that is not in this repository — a self-built APK will therefore not upgrade an installed release build; uninstall first.

Security

WatchPush holds an ADB key that a watch has authorised, which is a lot of power over that device. It only ever opens two services — sync: to write the APK and shell: to run pm install — and it never phones home; there is no analytics, no network access beyond the local ADB socket. Keep Wireless debugging switched off on the watch when you're not using it.

Licence

GPL-3.0-or-later — see LICENSE.

The app links spake2-java (LGPL-3.0) via libadb-android (GPL-3.0-or-later OR Apache-2.0), which makes GPL-3.0 the compatible choice for the whole work. Also uses Conscrypt (Apache-2.0) for the bundled TLSv1.3 provider — required to reach a remote adbd without hidden-API access — and Bouncy Castle (MIT) for certificate generation.

Known limits

  • Single APKs only. Split APKs, .apkm and .xapk bundles would need install-create plus multiple install-write sessions.
  • The install runs in the ViewModel rather than a foreground service, so backgrounding the app mid-transfer can let the system kill the job. Fine for the tens of seconds a watch APK takes.
  • Untested against physical hardware by the author at time of first release — the protocol work is built to spec, but please open an issue if your watch disagrees.

About

Sideload APKs onto a Pixel Watch straight from your phone - an in-app ADB client over Wireless debugging. No computer required.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages