tmux-browser-android/README.md
Codex dd056c8027
All checks were successful
Gitea Smoke / smoke (push) Successful in 0s
Gitea Android APK / build (push) Successful in 12m19s
Add projects page and smooth terminal input
2026-07-06 18:49:28 +00:00

196 lines
7.7 KiB
Markdown

# tmux Android
Android API client for `tmux-ui` / `tmux-browser`.
The server project is expected to already be running on port 3000. This app does
not host or load the existing web UI. It calls the existing HTTP and WebSocket
APIs directly:
- server URL management for Tailscale `100.x.y.z:3000` APIs
- quick server selectors for `100.89.0.2`, `100.89.0.4`, `100.89.0.9`,
`100.89.0.11`, and `100.89.0.116`
- one-tap probe for the preset Tailscale APIs, showing health/version and
session counts
- native tmux session list
- Sessions page with current API/server and loaded session count
- native Projects page for kanban project grouping, project agents, project
messages, add/remove session, create, and delete actions
- create, rename, send command, split pane, select pane, kill pane, pin, mute,
and kill session through HTTP API
- open one live terminal viewer through `/ws/terminal`
- native `/ws/events` listener for session invalidation and hook notifications
- selectable GitHub or Gitea update manifest source
- native Tools page for health, server status, timeline, preferences, hook
events, image file/URL upload, image preview info, and native image preview
display
- mobile soft-key row for tmux-oriented input, including tmux prefix, detach,
new window, previous/next window, Ctrl keys, arrows, page keys, and paste
- automatic update checks against the selected release manifest
- one-download-per-version APK cache, SHA-256 verification, and installer
handoff
- native Update and About pages for version/build type, protocol, permission,
selected update source, and release information
## Server URL
Default:
```text
http://100.89.0.116:3000
```
On a physical Android device, `127.0.0.1` means the phone itself. The app
therefore defaults to Tailscale and includes quick selectors for:
```text
http://100.89.0.2:3000
http://100.89.0.4:3000
http://100.89.0.9:3000
http://100.89.0.11:3000
http://100.89.0.116:3000
```
The upstream server should stay bound to localhost or a private Tailscale IP.
Do not expose terminal control on `0.0.0.0` to the public internet.
## GitHub Actions Build
The workflow in `.github/workflows/android.yml` builds APKs online.
Required environment on Actions:
- `ubuntu-latest`
- JDK 17
- Android SDK platform 35 installed by `android-actions/setup-android`
- Gradle 8.10.2 installed by `gradle/actions/setup-gradle`
- Android Gradle Plugin 8.7.3 from Google Maven
For release builds that can update an already installed app, configure these
repository secrets:
```text
ANDROID_KEYSTORE_BASE64
ANDROID_KEYSTORE_PASSWORD
ANDROID_KEY_ALIAS
ANDROID_KEY_PASSWORD
```
Create the base64 value from your release keystore:
```bash
base64 -w 0 tmux-android-release.jks
```
Branch builds and manual workflow runs create Actions artifacts only. Use them
to verify grouped changes before publishing.
Publish a release build by pushing a `v*` tag. A tag should be reserved for a
coherent feature/test batch, not every small UI or text change. Tag publishing
creates a GitHub Release with:
```text
https://github.com/neatstudio/tmux-browser-android/releases/latest/download/tmux-android.apk
https://github.com/neatstudio/tmux-browser-android/releases/latest/download/latest.json
```
Those GitHub links are the primary public install/update channel. Gitea releases
are mirrored as a second public source. This Gitea instance does not support the
GitHub-style `/releases/latest/download/...` URL, so the app uses the Gitea
Release API as the stable Gitea update entrypoint.
Plain branch builds only create Actions artifacts; they are useful for CI
verification, but releases are the stable download/update channel.
Unsigned/debug workflow artifacts are useful only for smoke testing install and
launch. Automatic in-place updates require release APKs signed with the same
keystore every time; otherwise Android treats the APK as a different or
incompatible package.
## Current Terminal Scope
The terminal screen connects to `/ws/terminal` and sends the upstream protocol
messages unchanged: `attach`, `input`, `resize`, `scroll`, and `clear-history`.
The first Android UI renders terminal output as monospace text with basic ANSI
SGR color support. The terminal view stays bottom-aligned when output is short,
auto-scrolls as data arrives, and adjusts its bottom inset when the soft keyboard
opens. Rendering is throttled and the local terminal buffer is capped so opening
busy sessions does not block the UI thread. Input typed before the terminal
attach message is sent is queued and flushed after the WebSocket client is ready.
It is enough for shell-oriented remote testing, but it is not yet a complete
xterm-compatible renderer for full-screen TUIs such as `vim` or `top`.
The terminal toolbar and shortcut row include tmux prefix helpers. The app sends
the same control bytes a keyboard would send, for example `Ctrl+B`, `Ctrl+B d`,
`Ctrl+B c`, `Ctrl+B n`, and `Ctrl+B p`.
All app features are native Android controls. Complex server objects such as
preferences, timeline events, group messages, and image metadata currently use
native forms plus native JSON detail dialogs; kanban projects use a native
project/agent list; image preview uses a native `ImageView`. The app does not
load the browser UI.
## Permissions
The app needs network access and package install handoff for updates. Android
does not ask at runtime for normal internet access. Android 8+ requires the user
to allow this app to install unknown apps before automatic update installation
can continue. Android 13+ may ask for notification permission.
SMS permission is intentionally not requested because tmux-browser-android does
not read or send SMS.
## Auto Update
Normal Android apps cannot silently replace themselves. This app checks the
release manifest automatically, downloads the newer APK, verifies its SHA-256,
then opens Android's package installer. The user still has to approve the
install, and Android 8+ may require allowing this app to install unknown apps.
The default update manifest is:
```text
https://github.com/neatstudio/tmux-browser-android/releases/latest/download/latest.json
```
The public manual APK download is:
```text
https://github.com/neatstudio/tmux-browser-android/releases/latest/download/tmux-android.apk
```
The app checks only the selected update source. It does not probe GitHub and
Gitea during the same update check. Choose the source in the app's `Update`
page, or use a custom manifest/API URL.
The built-in Gitea API endpoint is:
```text
https://gitea.neatcn.com/api/v1/repos/tmux/tmux-browser-android/releases/latest
```
Gitea tag-specific assets are also public, for example:
```text
https://gitea.neatcn.com/tmux/tmux-browser-android/releases/download/v0.1.7/latest.json
https://gitea.neatcn.com/tmux/tmux-browser-android/releases/download/v0.1.7/tmux-android.apk
```
In the app:
- Open the `Update` page to check `latest.json`, download the APK, verify
SHA-256, and open Android's installer.
- If the same version APK was already downloaded and its SHA-256 still matches,
the app reuses that file instead of downloading it again.
- If Android sends you to the unknown-app install permission screen, return to
the app after allowing it; the app continues installing the already downloaded
APK without another update check or download.
- Open the `Update` page and tap `APK` to resolve the APK from the selected
update source and open it in a browser.
- Open the `Update` page and tap `Details` to see the installed version,
selected update source, APK/Release resolver behavior, install permission
state, and a `Check update` button.
- Open the `Update` page and tap `App settings` for Android's full per-app
permission/settings screen.
- Open the `About` page to see the app version/build type, package name,
API/protocol summary, selected update source, and update policy.