← All posts

Android

Wireless debugging - the key to closing the Android dev loop

Build and install an Android app from your phone with the dev machine anywhere. Wireless ADB over Tailscale, plus an agent in tmux, so there's no cable and no desk in the loop.

AndroidWorkflowsAgents

I build TermRover on Android, and for a long time the development loop tied me to a desk. Write code on the laptop, plug the phone in with a USB cable, hit run, watch it install, pick up the phone to test. Every step assumed I was sitting in front of the machine with the phone within cable’s reach. I’d accepted that as simply how Android development worked.

Then, far later than I’d like to admit, I found out that Android has had wireless debugging built in for years. I had no idea it existed. The whole time, I’d been reaching for a USB cable when the phone could have just connected over the network. Discovering that genuinely changed how I work and where I can work from. It’s one of those small features that quietly rearranges everything around it.

Because once the cable is gone, the loop opens right up. I can write a feature, build it, and have it land on the phone in my hand while the build machine sits at home and I’m on the couch, or out, or anywhere. The phone is both the thing I’m developing on and the thing I’m developing for. This post is how that loop closes, and how you can set it up too.

The two halves of the loop

There are two connections to set up, and they point in opposite directions:

  1. Phone to build machine, so I can drive the build. This is an SSH session: TermRover on the phone connects to the machine where the code lives.
  2. Build machine to phone, so the freshly built APK can install. This is wireless ADB: the build machine pushes the app to the phone over the network.

Get both running and the cable disappears. The phone talks to the machine, the machine talks back to the phone, and I never touch a USB port.

Reaching the build machine from the phone

This is the Tailscale setup I covered earlier. My desktop is on my tailnet, my phone is on my tailnet, so TermRover connects to the desktop by its 100.x.y.z address from anywhere, with nothing exposed to the internet. If you haven’t set that up yet, start there, because everything below assumes the phone can already SSH to the build machine.

Once I’m in, I start an agent in tmux and leave it running:

tmux new -s android
claude            # or whichever agent you drive

tmux matters here for the usual reason: the build outlives my connection. A Gradle build can take minutes, my phone will lock or switch networks in that time, and I want the build to keep going regardless. I attach when I want to look and detach when I don’t.

Wireless ADB, the other direction

Now the interesting half. Android has shipped wireless debugging since Android 11, and it’s the key to installing without a cable.

On the phone, enable it once:

  1. Open Settings → Developer options → Wireless debugging and turn it on.
  2. Tap Pair device with pairing code. The phone shows an IP, a port, and a six-digit code.

On the build machine, pair and then connect:

adb pair 100.x.y.z:37000      # pairing IP:port, then enter the code
adb connect 100.x.y.z:43000   # connect IP:port (a different port)

Here’s the trick that makes it work from anywhere: put the phone on Tailscale too. Then the address the phone reports for wireless debugging is reachable from the build machine over the tailnet, not just on the local Wi-Fi. The machine can push to the phone whether they’re in the same room or different countries.

Tip: the pairing port and the connect port are not the same. Pairing is a one-time step; after that you only need adb connect on the connect port. If adb connect starts failing, toggle Wireless debugging off and on. The port usually changes when you do.

With the device connected, confirm it:

adb devices
# List of devices attached
# 100.x.y.z:43000   device

Closing the loop

Both directions are live now, so the agent can run the whole cycle. I tell it what I want, it edits the code, and it runs:

./gradlew installDebug

Gradle builds the APK and adb installs it straight onto the phone in my hand. The app updates, I open it, I test the change. If it’s wrong, I tell the agent what I saw, and it edits and reinstalls. Write, build, install, test, repeat, with the machine somewhere else entirely.

A few things make this comfortable rather than fiddly from a phone:

  • I keep the agent in one tmux session and a plain shell for adb and logcat in another, then flip between them with the session picker.
  • When something looks wrong on screen, I screenshot it and send the image to the agent instead of trying to describe a layout bug in words.
  • Reading a stack trace out of adb logcat is exactly what mouse-mode scrollback is for.

Why this changes things

The cable was never just a cable. It was a tether to a place. Closing the loop wirelessly means the development work and wherever I happen to be stop being the same question. I can ship a fix to the app on my own phone from a train, see how it feels, and move on.

It also fits naturally with how I work with agents in general, which is a whole workflow of its own. The Android loop is just one machine in that picture, but it used to be the one that felt most stubbornly desk-bound, and now it isn’t.