Skip to content

Install on Android

APX Android is not on Google Play or the App Store. It is distributed the same way APX itself is: as a file you can inspect, from the repository that built it.

Download:

https://github.com/agentprojectcontext/apx/releases/download/android-latest/apx.apk

That link never moves. It always points at the newest signed build, so it is safe to bookmark, print in a QR code, or send to someone else.

Two ways. They end in the same place — pick whichever matches what you have in your hands.

No cable, no computer.

  1. Open the download link above in the phone’s browser.
  2. Tap the downloaded file. Android will say it cannot install from this source.
  3. Allow it: Settings → Install unknown apps → <your browser> → Allow. This permission is per-app — you are trusting your browser, not every app.
  4. Tap Install, then Open.
  5. Pair it: see Connect it below.

Every release publishes the APK’s checksum beside it:

Terminal window
curl -sL https://github.com/agentprojectcontext/apx/releases/download/android-latest/apx.apk.sha256
shasum -a 256 apx.apk

The two lines should show the same hash.

This is the part that decides how the app behaves, and it is worth understanding before pairing rather than after. The app asks for one address — your daemon’s — and there are three kinds. They are not interchangeable.

http://127.0.0.1:7430, made real by adb reverse. apx android install sets this up for you; by hand it is:

Terminal window
adb reverse tcp:7430 tcp:7430

The daemon stays on loopback and nothing is exposed to any network. It dies when the cable is unplugged. Perfect for the first install and for development; not an address a phone can keep.

Terminal window
apx panel share
apx restart

The daemon binds a local IP, and the phone reaches it at http://192.168.x.x:7430 as long as both are on the same WiFi. Fast and private — nothing leaves the house — and gone the moment the phone does.

It is http://, which the native app is fine with but a browser is not: no installing the panel as a web app, no microphone, no clipboard. Those three need a secure context, and that is a browser rule, not an APX decision.

Turn it off with apx panel unshare.

Terminal window
apx panel tailscale on

This gives the daemon a stable name with a real HTTPS certificate, reachable from any device signed into the same tailnet. It is tailscale serve, not funnel: nothing is published to the public internet.

This is the only option that works away from home, and the only one that gives a browser a secure context. If the phone is meant to stay connected, this is the address to pair with.

The app needs the daemon’s address and a one-time code. apx android install does this over the cable. By hand:

  1. Run apx pair web on the daemon machine — it prints a code and a QR.
  2. Open APX on the phone, enter the daemon URL and the code, tap Vincular y abrir.
  3. The device appears under Settings → Devices in the panel, with its own token, revocable on its own.

A phone gets its own kind: android token. Installing the app does not disturb a browser that was already paired on the same phone — Android isolates each app’s storage, so they are two clients.

Android will not let an app grant itself the permissions that matter. Each is a deliberate one-time switch:

What you wantWhere it is
NotificationsAccept the prompt on first launch
The floating mascotDisplay over other apps
Trip detectionAPX menu → Enable trip detection → notification access
Driving alerts through Do Not DisturbAPX menu → Allow driving alerts
Alerts arriving on time from a pocketAPX menu → Remove battery restriction

The Android app page explains what each one buys.

The car half has two levels, and a sideloaded APK only gets one of them for free:

  • Message cards on the head unit work as soon as the app is installed.
  • APX’s own screen in the car — the one that offers the four answers to a proximity alert — does not appear until Android Auto’s developer settings have Unknown sources enabled. Android Auto reserves that surface for apps installed from Google Play, and it fails silently: no chip, no error.

To enable it: open Android Auto’s settings (Settings → Connected devices → Connection preferences → Android Auto), tap Version ten times, then in the developer menu tick Unknown sources.

From the app. APX’s menu → Buscar actualizaciones. If there is a newer version it offers it, downloads it, checks it against the published sha256 and hands it to Android’s installer. The app also looks on its own every time you open it, and speaks only when there is something to install.

The first time, Android asks for permission to let APX install apps. It is a per-app switch, granted once, and there is no way around it outside Play — nor should there be: an app that can replace itself without anyone being asked can replace itself with anything.

Without the app. Install the new APK over the old one — apx android install again, or download it and tap it. Your pairing, settings and permissions survive.

The app is in the repository, and the release is built from it by .github/workflows/android.yml.

Terminal window
cd src/interfaces/android
./gradlew testDebugUnitTest assembleDebug
adb install -r app/build/outputs/apk/debug/app-debug.apk

That needs a JDK 17 and the Android SDK. A release build additionally needs a keystore, supplied through the environment (APX_KEYSTORE, APX_KEYSTORE_PASSWORD, APX_KEY_ALIAS, APX_KEY_PASSWORD); without one, assembleRelease produces an unsigned APK that Android will not install.

apx android install installs the PUBLISHED APK even inside a checkout that has a build of its own — a local build is signed with the debug key, and the first real release cannot update over it. Pass --local when you do want yours.