| 简体中文 | English |
A native Android client for ZCode remote control. Built by reverse-engineering the communication protocol of the official web remote-control page, it lets you view and control desktop ZCode sessions from your phone — no browser needed.
Written in Kotlin with Jetpack Compose (Material 3). All code is an independent implementation.
📱 Live preview: damianjiang.github.io/ZCode-Android
sid / hash in a remote-control URL are device credentials. Never share them.
If leaked, regenerate the QR code on the desktop to invalidate them.permission_request / elicitation_request,
approve file access or commands directly from your phoneRequires JDK 17 and Android SDK 35.
git clone https://github.com/Damianjiang/ZCode-Android.git
cd ZCode-Android
./gradlew assembleRelease # gradlew.bat on Windows
The APK is written to app/build/outputs/apk/release/. Release builds use R8 and
resource shrinking, signed with the debug key so they install directly. Use
assembleDebug for development.
Requires Android 12+ (minSdk 28), arm64-v8a only.
app/src/main/java/app/zemote/
├── MainActivity.kt # App entry point
├── ZemoteApp.kt # Application class
├── crash/
│ └── CrashHandler.kt # Crash capture and restart
├── protocol/ # Protocol stack (fully independent implementation)
│ ├── ConnectionParams.kt # URL parsing (sid/hash/t)
│ ├── Proof.kt # HMAC-SHA256 pairing proof
│ ├── IpcCodec.kt # 7-bit varint codec
│ ├── RpcFrameTransport.kt # rpc-frame fragmentation / CRC32 / reassembly
│ ├── ChannelClient.kt # Channel RPC and event subscriptions
│ ├── RelayClient.kt # WebSocket connection, heartbeat, reconnect
│ ├── ZemoteClient.kt # bootstrap, bridge open and recovery
│ ├── BridgeSession.kt # workspace bridge session
│ └── ConversationV4.kt # Conversation protocol: subscriptions, streaming,
│ # queue, attachments, permission handling
├── service/
│ └── KeepAliveService.kt # Foreground keep-alive notification
├── state/ # State layer
│ ├── AccountStore.kt # Persisted device list
│ ├── AppSessionViewModel.kt # Connection and conversation-repo management
│ ├── AppSettings.kt # App settings (message count limit, etc.)
│ ├── CredentialCipher.kt # Keystore AES/GCM encryption
│ └── LanguagePrefs.kt # Language preference
└── ui/ # Compose UI
├── theme/ # M3 theme, palettes, typography
├── component/ # Shared components
├── components/ # Markdown rendering
├── logger/
│ └── ZemoteLogger.kt # Protocol-level debug logging
├── navigation/
│ └── ZemoteNavHost.kt # Navigation routes
└── screens/ # Individual screens
├── AccountsScreen.kt # Device list
├── ChatAndTasksScreen.kt # Chat page + task panel
├── ChangelogScreen.kt # In-app changelog
├── CrashScreen.kt # Crash report viewer
├── DeviceSwitchSheet.kt # Device switch dialog
├── LogScreen.kt # Debug log viewer
├── MainScreen.kt # Bottom navigation shell
├── MainShellScreen.kt # Post-login main page
├── PersonalizeScreen.kt # Theme personalization
├── QrScanScreen.kt # QR code pairing scanner
└── SettingsScreen.kt # Settings page
The stack mirrors the official web client’s behavior; the implementation is entirely independent:
| Layer | Notes |
|---|---|
| Relay | wss connection, 10s heartbeat, exponential-backoff reconnect |
| Pairing | HMAC-SHA256(nonce ‖ role ‖ deviceSid, passHash) |
| IPC | 7-bit varint, type tags (String / Int / JSON / Bytes / Array) |
| RpcFrame | 512KB fragments, CRC32 verification, acks, retransmit on fault |
| Channel RPC | request/response promise + event subscriptions |
| Conversation V4 | snapshot + delta subscriptions, wire-frame reassembly, session queue, attachment upload, permission handling |
Implementation details of the conversation protocol cross-reference the original Flutter version of this project (same wire behavior).
MIT. The ZCode name and related trademarks belong to their respective owners; this project has no affiliation with them.