Files
Patrick Ecord d3dd785921 core: file/image transfer over the RTC data channel (chunked, P2P)
Add Engine.send_file(name, mime, data) and MessageHandler.on_file. Files stream
over each open RTC data channel as binary frames — M<json meta> · C<16-byte
id><16KB chunk>… · E<id> — and reassemble on the receiver in arrival order
(the channel is reliable+ordered). The data channel now distinguishes string
(clipboard) from binary (file) messages. Files are direct-only — never relayed,
matching prefer-direct.

Transport trait gains start(...files) + a default-noop send_file (only RTC
implements it). The agent saves received files to ~/Downloads; the apps stub
on_file (receive UI is a follow-up). All MessageHandler impls updated.

Proven by examples/file_demo.rs: A sends a 50KB blob (4 chunks), B reassembles
it to identical bytes over RTC.

Follow-ups: file transfer over LAN (same-network without RTC); attach/preview UI;
progress + size cap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 11:54:29 -05:00
..

tether — Android client

Compose UI over the shared tethercore Rust engine (SSE + RTC) via UniFFI Kotlin bindings. Same engine as the iOS/macOS apps and the desktop agent; only the UI and the binding language differ.

Build (requires the Android NDK)

This machine had no Android toolchain when the app was scaffolded, so the native .so and Kotlin bindings are not committed — they're generated:

  1. Install the toolchain:
    • Android Studio (SDK + NDK), or sdkmanager "ndk;26.x"
    • cargo install cargo-ndk
    • rustup target add aarch64-linux-android x86_64-linux-android
    • export ANDROID_NDK_HOME=/path/to/ndk
  2. Generate native libs + bindings:
    ../core/build-android.sh
    
    This places libtethercore.so under app/src/main/jniLibs/<abi>/ and the Kotlin binding under app/src/main/java/uniffi/tethercore/.
  3. Build/run the app: open android/ in Android Studio (it generates the Gradle wrapper on first sync), then Run. From the CLI, generate the wrapper once with gradle wrapper, then ./gradlew :app:assembleDebug.

Notes

  • Default server is http://10.0.2.2:8765 — the emulator's alias for the host machine's localhost. On a physical device use the relay's LAN address.
  • Android (unlike iOS) lets a foreground app observe clipboard changes, so the app auto-sends via OnPrimaryClipChangedListener. A foreground Service would extend that to the background (future work).
  • The room id is a per-install UUID (RoomIdentity); account-derived shared rooms are future work, matching the iOS plan.