Complete Guide to vphone-cli Message Types for Guest Communication
vphone-cli communicates with the guest-side daemon over VSock using a length-prefixed JSON protocol supporting 30+ distinct message types for handshake, input injection, file transfer, app management, and system control.
The open-source tool vphone-cli (maintained in Lakr233/vphone-cli) implements a host-side Swift client that orchestrates virtualized iOS devices. Every message exchanged with the guest daemon vphoned follows a strict JSON envelope containing a protocol version ("v"), message type ("t"), and an optional request identifier ("id"). Understanding these supported message types is essential for extending the tool or debugging guest communication failures.
Protocol Structure and Conventions
All frames are length-prefixed JSON objects sent over a VSock connection on port 1337. The host (Swift) and guest (Objective-C) share an identical vocabulary. Message types determine the payload schema and expected directionality.
In sources/vphone-cli/VPhoneControl.swift, the sendCommand method serializes requests while the read loop dispatches responses based on the "t" field. Timeouts and error handling are managed per-type in this single source file.
Host-to-Guest Request Types
These message types originate from the host CLI and trigger actions inside the guest operating system.
System Handshake and Lifecycle
- hello – Sent during
performHandshake(lines 76-84) to announce the host identity and transmit an optional binary hash for version verification. - ping – Liveness check implemented in
sendPing(lines 36-37) expecting apongresponse. - version – Retrieves the guest build hash via
sendVersion(lines 40-42). - update – Pushes a raw binary payload to the guest when
pushUpdate(lines 50-53) detects a version mismatch. - devmode – Queries developer mode status through
sendDevModeStatus(lines 30-33). - low_power_mode – Toggles power state via
lowPowerMode(lines 87-92).
Input Injection
- hid – Transmits keyboard events through
sendHIDPressandsendHIDRelease(lines 86-95) using HID page and usage codes. - touch – Sends digitizer events via
sendTouch(lines 10-18) with phase values:0for down,1for move, and3for up.
File System Operations
The protocol supports full remote file management inside the guest sandbox:
- file_list – Directory enumeration from
listFiles(lines 81-84) returning metadata arrays. - file_get – Binary download initiated by
downloadFile(lines 90-94). - file_put – Upload via
uploadFile(lines 100-108) streaming raw bytes. - file_mkdir – Directory creation in
createDirectory(lines 42-44). - file_delete – Removal command from
deleteFile(lines 46-48). - file_rename – Move or rename operations via
renameFile(lines 50-52).
Application Management
- app_list – Enumerates installed applications through
appList(lines 22-27). - app_launch – Starts applications optionally with URL payloads via
appLaunch(lines 40-45). - app_terminate – Force-quits running apps using
appTerminate(lines 48-49). - app_foreground – Queries the currently focused application in
appForeground(lines 52-58). - ipa_install – Installs iOS packages through
installIPA(lines 64-67).
Security and Clipboard
- keychain_list – Retrieves stored credentials via
listKeychainItems(lines 16-20). - keychain_add – Inserts new keychain entries using
addKeychainItem(lines 27-33). - clipboard_get – Reads pasteboard contents (text and image) from
clipboardGet(lines 52-56). - clipboard_set – Writes text or binary image data via
clipboardSet(lines 63-71).
System Settings and URLs
- settings_get – Reads user defaults or system preferences in
settingsGet(lines 74-78). - settings_set – Writes configuration values through
settingsSet(lines 80-84). - open_url – Requests the guest open a specific URL scheme via
openURL(lines 62-66).
Advanced Diagnostics and Location
- accessibility_tree – Dumps the UIAccessibility hierarchy via
accessibilityTree(lines 97-102) for automation debugging. - location – Streams GPS coordinates, speed, and altitude updates from
sendLocation(lines 112-125). - location_stop – Terminates location updates using
sendLocationStop(lines 133-138).
Guest-to-Host Response Types
The guest daemon sends these types back to the host, typically as acknowledgments or data payloads.
- ok – Generic success response handled in the read loop default case (lines 44-48), optionally containing a message string.
- pong – Explicit response to
pingrequests (lines 49-51). - version – Returns the guest build hash (lines 52-55).
- err – Error indication carrying a
"msg"field, caught asControlError.guestErrorin the host (lines 56-58). - file_data – Inline binary payload for
file_getresponses (lines 95-110). - clipboard_get – Binary image data when clipboard contains non-text content (lines 15-21).
Bidirectional Common Types
Certain types appear in both directions with context-specific payloads:
- hello (guest side) – Response during handshake (lines 98-104) carrying guest name, capabilities, IP address, iOS version, and update requirements.
- need_update – Boolean flag inside the guest
hellopayload (line 104) triggering the host'supdatesequence.
Implementation in VPhoneControl.swift
The entire protocol implementation resides in sources/vphone-cli/VPhoneControl.swift. Key architectural details include:
- VSock connection establishment through
VPhoneVirtualMachine.swift(port 1337). - Request/response correlation using the
"id"field for async/await bridging. - Timeout handling per message category (file transfers allow longer durations than pings).
- Guest daemon scripts in
scripts/vphoned/*mirror this type vocabulary in Objective-C.
Practical Code Examples
Sending a HID keyboard shortcut to hide the current app:
let control = VPhoneControl(variant: .regular)
control.sendHIDPress(page: 0x07, usage: 0x0b) // Command + H
Requesting the UI accessibility tree for automation:
let tree = try await control.accessibilityTree(depth: 3)
print(tree)
Uploading and retrieving a file from the guest:
await control.uploadFile(path: "/tmp/example.txt",
data: Data("Hello".utf8))
let data = try await control.downloadFile(path: "/tmp/example.txt")
print(String(data: data, encoding: .utf8) ?? "-")
Handling guest-side errors explicitly:
do {
try await control.sendPing()
} catch VPhoneControl.ControlError.guestError(let msg) {
print("Guest reported error: \(msg)")
}
Summary
- vphone-cli uses a length-prefixed JSON protocol over VSock with mandatory
"v"(version) and"t"(type) fields. - Host-initiated types cover handshake (
hello), input (hid,touch), file operations (file_*), app lifecycle (app_*), and system control (settings_*,location). - Guest response types include status codes (
ok,err), data payloads (file_data,clipboard_get), and liveness checks (pong). - All message types are implemented in
VPhoneControl.swiftwith specific line-numbered handlers for serialization and parsing. - The protocol supports binary blob transfer for files, images, and clipboard contents alongside structured JSON metadata.
Frequently Asked Questions
What transport protocol does vphone-cli use for guest communication?
vphone-cli establishes a VSock (Virtio Socket) connection on port 1337 to the guest-side daemon. Messages are length-prefixed JSON objects, ensuring framing integrity when transmitting binary payloads like file contents or HID reports.
How does vphone-cli handle asynchronous responses from the guest?
The host correlates requests and responses using an optional "id" field in the JSON envelope. The Swift implementation in VPhoneControl.swift maintains an internal continuation map that resumes async/await calls when matching response types (like ok, file_data, or err) arrive with the corresponding identifier.
Can vphone-cli transfer binary files between host and guest?
Yes. The file_put and file_get message types support raw binary transmission. When uploading, the host sends the binary payload immediately after the JSON header. When downloading, the guest responds with a file_data frame containing the raw bytes, handled in VPhoneControl.swift lines 95-110.
What happens when the guest vphoned daemon needs an update?
During the initial hello handshake (lines 76-104), the guest sets a need_update boolean flag if its binary hash differs from the host's. The host then sends an update message type via pushUpdate (lines 50-53) containing the new daemon binary, which the guest replaces atomically before reconnecting.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →