How loft runs on a phone, then Android TV / Google TV. Catalog: clients/Android/. Plan: clients/Android/PLAN.md. Engine: clients/mobile/. Protocol: protocol.md. Import URI: share.md. UX: clients/Android/design/DESIGN.md. Mock: clients/Android/design/index.html.
The adapter is Java. The session is Go.
apps
→ tun0 owned by VpnService
→ LoftVpnService (app.loft.android)
→ clients/mobile (gomobile AAR)
→ loft / SSTP / VLESS / Trojan
→ protect(fd) on front sockets
There is no loft-front. The service is the session.
make -C clients/mobile android writes clients/mobile/build/engine.aar (-androidapi 24, 16 KiB pages). The app depends on that file. NDK is required for the bind.
Java package app.loft.engine: Engine, Snapshot, PacketSink, SocketProtector, Mobile.parseShare.
VpnService.protect(fd) via Engine.SetProtector. Front IPs also excludeRoute on API 33+.
Path change: ConnectivityManager.NetworkCallback can call NotifyPathChange later; the thin adapter relies on Go reconnect after a dead socket for now.
| Engine AAR | API 24 |
| Phone app | API 26, target 36 |
| Language | Java 17 |
| Android TV / Google TV | same AAR; Leanback flavor later (PLAN phase 4) |