How to Perform IPA Installation Within a vPhone-CLI VM: Complete Technical Guide

vPhone-CLI supports IPA installation through a vsock-based pipeline that uploads the package to the guest VM, optionally applies code signing certificates, and executes the installation via the ipa_install protocol message.

Installing iOS applications into a virtual iPhone requires coordinated communication between the host and guest systems. The Lakr233/vphone-cli project provides a complete end-to-end solution for IPA installation within a vphone-cli VM, handling file transfers, validation, and sandboxed deployment without manual SSH intervention.

Architecture Overview

The installation system comprises three coordinated components working across the host-guest boundary.

User Interface Layer

The interface initiates requests through menu items or command-line flags. In VPhoneMenuApps.swift, the buildAppsMenu() function adds the "Install IPA/TIPA…" menu item, while VPhoneCLI.swift exposes the --install-ipa flag for terminal-based workflows.

Host-Side Control Layer

VPhoneControl.swift manages the actual orchestration through the installIPA(localURL:) method. This component uploads the IPA to the guest filesystem, handles optional signing certificates, and communicates with the daemon via the vsock channel.

Guest Daemon (vphoned)

Running inside the VM, the guest daemon receives ipa_install requests, validates the uploaded package, performs code signing when certificates are provided, and installs the application into the guest's sandbox.

The IPA Installation Pipeline

The complete flow from file selection to app installation follows a strict protocol designed for reliability and security.

Initiating the Install Request

Users can trigger installation through two primary paths. The interactive menu path uses installIPAFromDisk() in VPhoneMenuApps.swift, which presents an NSOpenPanel restricted to file types defined in VPhoneInstallPackage.allowedContentTypes (.ipa and .tipa).

For automation, the CLI parses the --install-ipa argument in VPhoneCLI.swift, storing the file URL and executing the installation once the control channel connects.

File Validation and Upload Preparation

Before transmission, VPhoneInstallPackage.isSupportedFile(_:) verifies the file extension. The host then prepares the transfer through VPhoneControl.installIPAWithBuiltInInstaller(localURL:), which:

  • Reads the local IPA into a Data buffer
  • Creates the remote directory /var/mobile/Documents/vphone-installs
  • Generates a unique remote path using UUID prefixing to prevent filename collisions

Optional Code Signing Configuration

If a signing certificate is configured via Self.signCertURL(), the host uploads the certificate to the same remote directory and includes its path in the installation request under the cert_path key. This enables the guest daemon to re-sign the binary during installation.

Transmission and Guest Installation

The host transmits data through the vsock channel using createDirectory(path:) (sending file_mkdir) and uploadFile(path:data:). Once uploaded, the host constructs and sends the installation request:

var request: [String: Any] = [
    "t": "ipa_install",
    "path": remotePath,
    "registration": "User",
]
// cert_path appended if signing certificate provided

The guest daemon processes this request, validates the package integrity, applies code signing if specified, and installs the app into the guest sandbox.

Result Handling and Cleanup

After receiving the daemon's response, the host checks resp["msg"] for installation details. If the message is empty, it returns the default success string: "Installed <file>. through the built-in IPA installer."

A defer block ensures cleanup of temporary files (both IPA and certificate) from /var/mobile/Documents/vphone-installs, maintaining VM storage hygiene. If the daemon does not support ipa_install, the system throws ControlError.guestError with instructions to reconnect or reboot the VM.

Installation Methods

Interactive Menu Installation

For GUI users, the menu-driven approach provides file selection and status feedback:

@objc func installIPAFromDisk() {
    guard control.isConnected else {
        showAlert(title: "Install App Package",
                  message: "Guest is not connected.", style: .warning)
        return
    }
    let panel = NSOpenPanel()
    panel.allowedContentTypes = VPhoneInstallPackage.allowedContentTypes
    panel.message = "Choose an IPA or TIPA package to install in the guest."
    if panel.runModal() == .OK, let url = panel.url {
        Task {
            do {
                let result = try await control.installIPA(localURL: url)
                showAlert(title: "Install App Package",
                          message: VPhoneInstallPackage.successMessage(
                              for: url.lastPathComponent, detail: result),
                          style: .informational)
            } catch {
                showAlert(title: "Install App Package",
                          message: "\(error)", style: .warning)
            }
        }
    }
}

Command-Line Flag Installation

For scripting and automation, use the --install-ipa flag:

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

The CLI stores the URL and automatically triggers installIPA(localURL:) once the vsock channel establishes connectivity.

Programmatic API Usage

Developers integrating vPhone-CLI into larger workflows can invoke the control layer directly:

let control = VPhoneControl(connection: vsockConnection)
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)
    }
}

Key Source Files and Implementation Details

Understanding the source structure helps with debugging and extension:

  • VPhoneMenuApps.swift: Contains buildAppsMenu() and installIPAFromDisk(), handling the UI flow and validation before delegating to the control layer.

  • VPhoneControl.swift (lines 54-106): Implements the core installIPA(localURL:) and installIPAWithBuiltInInstaller methods, managing remote directory creation, certificate handling, and the ipa_install protocol request.

  • VPhoneInstallPackage.swift: Defines allowedContentTypes for .ipa and .tipa files, provides isSupportedFile(_:) validation, and formats success messages via successMessage(for:detail:).

  • VPhoneCLI.swift: Parses command-line arguments including --install-ipa, bridging CLI inputs to the control layer.

  • Guest Daemon: Receives the ipa_install message inside the VM (not included in the host repository) and performs the actual sandboxed installation.

Summary

  • vPhone-CLI provides three interfaces for IPA installation: interactive menu, CLI flag, and programmatic API.
  • The host control layer (VPhoneControl.swift) manages file uploads to /var/mobile/Documents/vphone-installs and vsock communication.
  • File validation ensures only .ipa and .tipa extensions are processed, with UUID-based naming to prevent collisions.
  • Optional code signing is supported by uploading certificates alongside the package and specifying cert_path in the installation request.
  • The guest daemon executes the actual installation via the ipa_install protocol message, returning status details to the host.
  • Automatic cleanup removes temporary files from the guest VM after installation completes.

Frequently Asked Questions

How do I install an IPA file when the guest daemon returns an unsupported error?

If you encounter ControlError.guestError indicating the ipa_install protocol is unsupported, the guest daemon (vphoned) requires an update. Reconnect to the VM or reboot it to ensure the daemon supports the installation protocol. The host will retry the request automatically once connectivity resumes.

Can I install unsigned IPAs using vPhone-CLI?

Yes, by providing a signing certificate through the configuration mechanism. If Self.signCertURL() returns a valid certificate path, the host uploads it to the guest and includes cert_path in the installation request. The guest daemon then re-signs the binary during installation. Without a certificate, only properly signed IPAs will install successfully.

What file formats does vPhone-CLI support for installation?

According to VPhoneInstallPackage.swift, the system supports .ipa (standard iOS App Store packages) and .tipa (testflight or development variants). The allowedContentTypes array restricts file selection dialogs to these extensions, and isSupportedFile(_:) validates the extension before upload begins.

Where does vPhone-CLI store temporary files during installation?

During the upload phase, files are stored in /var/mobile/Documents/vphone-installs inside the guest VM. The system generates unique filenames using UUID prefixes to avoid collisions. A defer block in installIPAWithBuiltInInstaller ensures these temporary files are deleted immediately after the installation completes, regardless of success or failure.

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 →