How to Install IPA Files Using vphone‑cli's Guest Daemon: Complete Protocol Guide

vphone-cli installs IPAs by uploading the file to the guest VM via vsock and sending an ipa_install protocol request to the vphoned daemon, which handles the actual installation inside the virtual iPhone.

The vphone-cli project by Lakr233 provides a macOS-native interface for running virtualized iOS devices. A core feature is its ability to install .ipa and .tipa application packages through a dedicated guest daemon (vphoned) running inside the VM. This article breaks down the complete installation flow, from capability negotiation to cleanup, based on the actual Swift implementation in the repository.

How the IPA Installation Protocol Works

The installation process relies on a three-phase protocol between the host application and the guest daemon. Understanding this flow helps diagnose failures and enables programmatic automation.

Phase 1: Capability Negotiation

When the virtual machine boots, the host queries the daemon for supported capabilities. The daemon advertises ipa_install if its version includes the installer functionality.

The host tracks this capability in VPhoneAppDelegate.swift:

// Capabilities are queried during VM connection
// mc?.updateInstallAvailability checks for "ipa_install"
// and disables the menu item when unavailable

If the daemon doesn't report ipa_install, the Install IPA/TIPA… menu item becomes disabled. This prevents user confusion when running an outdated guest image【/cache/repos/github.com/Lakr233/vphone-cli/main/sources/vphone-cli/VPhoneAppDelegate.swift#L170-L242】.

Phase 2: Initiating the Install Request

Users can trigger installation through two entry points:

Apps Menu (GUI) — VPhoneMenuApps.swift presents "Install IPA/TIPA…", opens an NSOpenPanel, and calls VPhoneControl.installIPA(localURL:)【/cache/repos/github.com/Lakr233/vphone-cli/main/sources/vphone-cli/VPhoneMenuApps.swift#L51-L71】

Command Line — The --install-ipa flag in VPhoneCLI.swift parses a URL and forwards it to the same method【/cache/repos/github.com/Lakr233/vphone-cli/main/sources/vphone-cli/VPhoneCLI.swift#L59-L73】

Phase 3: Host-Side Installer Execution

The VPhoneControl class in VPhoneControl.swift implements the core protocol logic. The installIPA(localURL:) method first validates daemon support, then delegates to installIPAWithBuiltInInstaller【/cache/repos/github.com/Lakr233/vphone-cli/main/sources/vphone-cli/VPhoneControl.swift#L54-L61】.

The built-in installer performs these steps:

  1. Create temporary directory — /var/mobile/Documents/vphone-installs on the guest
  2. Upload the IPA file — via uploadFile over the vsock channel
  3. Optionally upload signing certificate — for enterprise or ad-hoc signed apps
  4. Send JSON request — with "t": "ipa_install" and the remote file path
  5. Await daemon response — success message or error details
  6. Cleanup — defer block registers uploaded files for removal【/cache/repos/github.com/Lakr233/vphone-cli/main/sources/vphone-cli/VPhoneControl.swift#L64-L92】【/cache/repos/github.com/Lakr233/vphone-cli/main/sources/vphone-cli/VPhoneControl.swift#L76-L84】

The daemon processes the install request and returns a status. The host surfaces this directly to the caller, or a generic success string if empty【/cache/repos/github.com/Lakr233/vphone-cli/main/sources/vphone-cli/VPhoneControl.swift#L100-L106】.

Installing IPA Files: Practical Methods

Method 1: GUI Installation from the Apps Menu

Select Apps → Install IPA/TIPA… from the menu bar. This presents a file picker restricted to .ipa and .tipa extensions via VPhoneInstallPackage.allowedContentTypes.

// Implementation in VPhoneMenuApps.swift
@objc func installIPAFromDisk() {
    let panel = NSOpenPanel()
    panel.allowedContentTypes = VPhoneInstallPackage.allowedContentTypes
    if panel.runModal() == .OK, let url = panel.url {
        Task {
            let result = try await control.installIPA(localURL: url)
            print("[install] \(result)")
        }
    }
}

The result appears in a modal dialog after the async task completes【/cache/repos/github.com/Lakr233/vphone-cli/main/sources/vphone-cli/VPhoneMenuApps.swift#L72-L83】.

Method 2: Command-Line Installation

With the VM running and the guest daemon connected, use the --install-ipa flag:


# Basic installation

vphone-cli --install-ipa /path/to/MyApp.ipa

# Installation with spaces in path

vphone-cli --install-ipa "/Users/dev/Downloads/My App.tipa"

The CLI parses the URL in VPhoneCLI.swift and invokes the same installIPA method as the GUI【/cache/repos/github.com/Lakr233/vphone-cli/main/sources/vphone-cli/VPhoneCLI.swift#L59-L73】.

Method 3: Programmatic Installation in Swift

Integrate IPA installation into your own Swift tools using VPhoneControl:

import vphone_cli

let control = VPhoneControl(...)
let ipaURL = URL(fileURLWithPath: "/tmp/MyApp.ipa")

Task {
    do {
        let message = try await control.installIPA(localURL: ipaURL)
        print("Install succeeded:", message)
    } catch {
        print("Install failed:", error)
    }
}

This pattern appears in VPhoneVirtualMachineView.swift for automatic post-connection installs.

Error Handling and Troubleshooting

"unknown type: ipa_install"

If installIPA receives this daemon response, the method surfaces a clear error suggesting a VM reboot. This indicates the guest image lacks the installer component or the daemon failed to initialize properly【/cache/repos/github.com/Lakr233/vphone-cli/main/sources/vphone-cli/VPhoneControl.swift#L54-L61】.

Verify Capability Detection

Check that the guest daemon connected successfully. The Install IPA/TIPA… menu item disables automatically when ipa_install capability is absent.

Key Source Files Reference

File Role Critical Functions
sources/vphone-cli/VPhoneControl.swift Protocol implementation installIPA(localURL:), installIPAWithBuiltInInstaller
sources/vphone-cli/VPhoneMenuApps.swift GUI entry point installIPAFromDisk()
sources/vphone-cli/VPhoneCLI.swift CLI entry point --install-ipa flag parsing
sources/vphone-cli/VPhoneAppDelegate.swift Capability detection updateInstallAvailability
sources/vphone-cli/VPhoneVirtualMachineView.swift Auto-install example Post-connection install calls

Summary

  • Capability negotiation determines whether the guest daemon supports ipa_install before enabling UI options
  • Two entry points serve users: the Apps menu for GUI workflows and --install-ipa for automation
  • Protocol flow uploads the IPA to /var/mobile/Documents/vphone-installs, sends a JSON request with "t": "ipa_install", and cleans up afterward
  • Error handling provides actionable feedback when the daemon lacks installer support

Frequently Asked Questions

What file types does vphone-cli support for installation?

vphone-cli supports .ipa (standard iOS app packages) and .tipa (tweaked/modified IPAs). The file picker in VPhoneMenuApps.swift restricts selection to these types via VPhoneInstallPackage.allowedContentTypes, and the daemon handles both formats through the same ipa_install protocol.

Why is the "Install IPA/TIPA" menu item disabled?

The menu disables when the guest daemon doesn't advertise the ipa_install capability. This happens if the VM is still booting, the daemon crashed, or the guest image lacks the installer component. Restarting the VM typically resolves this by triggering fresh capability negotiation in VPhoneAppDelegate.swift.

Can I install IPAs automatically without user interaction?

Yes — use the CLI flag or programmatic API. The --install-ipa flag in VPhoneCLI.swift enables shell scripting, while VPhoneControl.installIPA(localURL:) allows Swift-based automation as demonstrated in VPhoneVirtualMachineView.swift for post-connection installs.

Where does the IPA get stored during installation?

The host uploads IPAs to /var/mobile/Documents/vphone-installs inside the guest VM. A defer block in installIPAWithBuiltInInstaller registers these files for cleanup after installation completes, preventing accumulation of temporary install packages.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →