# How to Access Private Virtualization APIs Using Dynamic in vPhone-CLI

> Learn how to access private Virtualization APIs with vPhone-CLI and the Dynamic Swift package. Explore runtime reflection for Objective-C class manipulation in macOS.

- Repository: [Lakr/vphone-cli](https://github.com/Lakr233/vphone-cli)
- Tags: how-to-guide
- Published: 2026-09-09

---

**vPhone-CLI uses the Dynamic Swift package to instantiate and manipulate private Objective-C classes from Apple’s Virtualization.framework by leveraging runtime reflection via `NSClassFromString` and `performSelector:` bridges.**

The `vphone-cli` project demonstrates how to bypass the public Swift SDK and interact with undocumented Virtualization APIs on macOS. By integrating the third-party **Dynamic** library, the CLI tool unlocks hidden functionality—such as multi-touch input, synthetic key events, and hardware acceleration—that Apple does not expose in standard headers. This approach relies on a consistent three-step pattern to create objects, access properties, and invoke methods without compile-time bindings.

## Understanding the Dynamic Runtime Bridge

**Dynamic** is a Swift package that provides a thin runtime bridge for pure-Swift code to manipulate Objective-C classes and members unavailable in the public SDK. It operates by dynamically resolving class names at runtime using `NSClassFromString` and forwarding method calls through `performSelector:`. This mechanism allows developers to instantiate private Apple framework classes—such as those in Virtualization.framework and BiometricKit—without importing private headers or using Objective-C++ bridging.

The library exposes two core interfaces: factory methods prefixed with an underscore (e.g., `Dynamic._VZTouch`) to create instances, and wrapper initialization (`Dynamic(<obj>)`) to interact with existing objects. When wrapped, objects gain property accessors (`.asObject`, `.asUInt64`, `.asInt`) and method proxies that translate Swift types to Objective-C expectations automatically.

## The Three-Step Pattern for Private API Access

All private Virtualization API interactions in vPhone-CLI follow a predictable workflow. Mastering this pattern allows you to replicate the technique for other undocumented Apple frameworks.

### Step 1: Instantiate Private Classes

To create an instance of a private class, call the factory method named after the Objective-C class prefixed with an underscore. Dynamic uses `NSClassFromString` internally to locate the class and performs standard `alloc/init` sequences.

```swift
// Create a private VZTouch instance
let touch = Dynamic._VZTouch(
    locationX: x, locationY: y,
    pressure: pressure, phase: .began
)

// Create a private VZKeyEvent for keyboard simulation
let keyEvent = Dynamic._VZKeyEvent(type: 0, keyCode: UInt16(0x38))

```

### Step 2: Access Properties with Type Converters

After obtaining an object, wrap it with `Dynamic(<obj>)` to access properties that lack public getters or setters. The wrapper provides type-specific accessors that marshal values between Swift and Objective-C runtimes.

```swift
// Wrap an existing machine identifier to read a private property
if let ecid = Dynamic(machineIdentifier)._ECID.asUInt64 {
    print("ECID = \(ecid)")
}

// Access the BiometricKit manager delegate property
guard let mgr = Dynamic.BiometricKit.manager().asObject else { return }

```

### Step 3: Invoke Private Methods

Dynamic exposes Objective-C selectors as Swift methods on the wrapper object. These calls are forwarded using `performSelector:` under the hood, enabling invocation of private methods without static linking or header imports.

```swift
// Send touch events to a virtual device
let touchEvent = Dynamic._VZMultiTouchEvent(touches: [touchObj])
Dynamic(device).sendMultiTouchEvents([touchEvent] as NSArray)

// Send synthesized keystrokes to the virtual keyboard
Dynamic(keyboard).sendKeyEvents([keyEvent.asAnyObject] as NSArray)

```

## Real-World Implementation in vPhone-CLI

The vPhone-CLI source code demonstrates this pattern across multiple subsystems. Examining these concrete implementations reveals how to apply the technique consistently.

### Handling Touch Input in VPhoneVirtualMachineView.swift

In [`sources/vphone-cli/VPhoneVirtualMachineView.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneVirtualMachineView.swift) (lines 270–287), the CLI constructs multi-touch events for the virtual machine by instantiating private `VZTouch` and `VZMultiTouchEvent` classes, then dispatching them via the private `sendMultiTouchEvents:` selector.

```swift
let touch = Dynamic._VZTouch(
    locationX: x, locationY: y,
    pressure: pressure, phase: .began
)
let touchObj = touch.asObject
let eventObj = Dynamic._VZMultiTouchEvent(touches: [touchObj]).asObject
Dynamic(device).sendMultiTouchEvents([eventObj] as NSArray)

```

### Simulating Keyboard Events in VPhoneKeyHelper.swift

The [`sources/vphone-cli/VPhoneKeyHelper.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneKeyHelper.swift) file (lines 121–136) uses Dynamic to construct `VZKeyEvent` objects with arbitrary key codes, allowing the CLI to inject synthetic keystrokes—including modifier keys and power button events—into the guest OS.

```swift
if let obj = Dynamic._VZKeyEvent(type: 0, keyCode: UInt16(0x38)).asAnyObject {
    events.append(obj)
}
Dynamic(keyboard).sendKeyEvents(events as NSArray)

```

### Accessing BiometricKit in VPhoneTouchIDMonitor.swift

At lines 171–197 in [`sources/vphone-cli/VPhoneTouchIDMonitor.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneTouchIDMonitor.swift), the code accesses the private BiometricKit framework to monitor Touch ID state. It retrieves the framework’s singleton manager, sets a delegate, and enables background fingerprint detection using Dynamic’s property and method proxies.

```swift
guard let mgr = Dynamic.BiometricKit.manager().asObject else { return }
Dynamic(mgr).setDelegate(delegate)
Dynamic(mgr).enableBackgroundFdet(true)

```

### Configuring VM Accelerators in VPhoneVirtualMachine.swift

The [`sources/vphone-cli/VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneVirtualMachine.swift) file (lines 224–228) assembles hardware acceleration by initializing multiple private device configuration classes—`VZMacVideoToolboxDeviceConfiguration`, `VZMacNeuralEngineDeviceConfiguration`, and `VZMacScalerAcceleratorDeviceConfiguration`—then attaches them via the private `_setAcceleratorDevices:` method.

```swift
let obj1 = Dynamic._VZMacVideoToolboxDeviceConfiguration().asObject
let obj2 = Dynamic._VZMacNeuralEngineDeviceConfiguration().asObject
let obj3 = Dynamic._VZMacScalerAcceleratorDeviceConfiguration().asObject
Dynamic(config)._setAcceleratorDevices([obj1, obj2, obj3])

```

## Summary

Accessing private Virtualization APIs requires a systematic approach to runtime introspection. The vPhone-CLI implementation demonstrates that the Dynamic library provides a reliable bridge between Swift and undocumented Objective-C frameworks.

- **Dynamic** exposes private classes through underscore-prefixed factory methods that resolve via `NSClassFromString`.
- Property access requires wrapping objects with `Dynamic()` and using type-specific accessors like `.asObject` or `.asUInt64`.
- Method invocation relies on `performSelector:` forwarding, allowing calls to private selectors such as `sendMultiTouchEvents:` and `_setAcceleratorDevices:`.
- Key implementation files include [`VPhoneVirtualMachineView.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachineView.swift) for input handling, [`VPhoneKeyHelper.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneKeyHelper.swift) for keyboard injection, and [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift) for hardware configuration.

## Frequently Asked Questions

### What is the Dynamic Swift package and how does it work?

**Dynamic** is a third-party Swift package that creates a runtime bridge to Objective-C. It uses `NSClassFromString` to locate private classes by name and `performSelector:` to forward method calls, allowing Swift code to instantiate and manipulate Objective-C objects that are not linked at compile time.

### How do I handle type conversion when accessing private properties?

Use the wrapper’s convenience accessors provided by Dynamic. After wrapping an object with `Dynamic(<obj>)`, access properties using `.asObject`, `.asUInt64`, `.asInt`, or `.asAnyObject` depending on the expected Objective-C type. These accessors marshal the runtime value into the appropriate Swift type automatically.

### Can Dynamic be used with frameworks other than Virtualization?

Yes. The technique applies to any Objective-C framework, as demonstrated in [`VPhoneTouchIDMonitor.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneTouchIDMonitor.swift) where Dynamic accesses the private **BiometricKit** framework. The same pattern—factory methods for instantiation, property wrappers for fields, and method proxies for selectors—works across macOS and iOS private APIs.

### Is using private Virtualization APIs safe for production applications?

No. Private APIs are undocumented, unsupported, and subject to change or removal in future macOS updates. Apps using these techniques may break with system updates, fail App Store review, or cause instability. This approach is intended for research, debugging, and internal tooling only.