2026 System Services
WWDC26 · 20 min · System Services
Expand the capabilities of your Virtualization app
Bring powerful new capabilities in macOS 27 to your Virtualization app. Discover how to automate the setup of macOS guests through user account setup on first boot. We’ll explore advanced workflows that involve passthrough of USB accessories to virtual machines, as well as custom network topologies and port forwarding. You’ll also learn about recent improvements that can enrich the experience of running your app’s virtual machines.
Watch at developer.apple.com ↗Chapters
Code shown on screen · 8 snippets
Provision a macOS guest
import Virtualization
let provisioningOptions = VZMacGuestProvisioningOptions()
provisioningOptions.fullName = fullName
provisioningOptions.username = username
provisioningOptions.password = password
provisioningOptions.logsInAutomatically = true
provisioningOptions.enablesRemoteLogin = true
let startOptions = VZMacOSVirtualMachineStartOptions()
try startOptions.setGuestProvisioning(provisioningOptions)
try await virtualMachine.start(options: startOptions) Register an Accessory Access listener
import AccessoryAccess
let criteria: [AAUSBAccessoryMatchingCriteria] = []
let accessories = try await AAUSBAccessoryManager.shared.registerListener(self, matchingCriteria: criteria)
for accessory in accessories {
// Handle previously attached accessories.
} Respond to USB accessory connection
import AccessoryAccess
import Virtualization
class AccessoryListener: NSObject, AAUSBAccessoryListener {
func usbAccessoryDidConnect(_ usbAccessory: AAUSBAccessory) {
virtualMachine.queue.async {
do {
let configuration = VZUSBPassthroughDeviceConfiguration(device: usbAccessory)
let device = try VZUSBPassthroughDevice(configuration: configuration)
self.virtualMachine.usbControllers.first?.attach(device: device) { error in
// Handle error if necessary...
}
} catch {
// Handle error...
}
}
}
} Create a custom vmnet network
import Virtualization
import vmnet
var status: vmnet_return_t = .VMNET_FAILURE
guard let networkConfiguration =
vmnet_network_configuration_create(.VMNET_SHARED_MODE, &status) else { ... }
guard let network =
vmnet_network_create(networkConfiguration, &status) else { ... }
let attachment = VZVmnetNetworkDeviceAttachment(network: network)
let networkDeviceConfiguration = VZVirtioNetworkDeviceConfiguration()
networkDeviceConfiguration.attachment = attachment
virtualMachineConfiguration.networkDevices = [networkDeviceConfiguration]
let virtualMachine = VZVirtualMachine(configuration: virtualMachineConfiguration) Use DiskImageKit with Virtualization
import DiskImageKit
import Virtualization
let baseImage = try DiskImage(opening: .open(url: baseLayerURL, mode: .readOnly))
let cacheImage = try baseImage.appending(.asifLayer(url: cacheLayerURL, type: .cache))
let overlayImage = try DiskImage(opening: .open(url: overlayLayerURL))
let stackedImage = try cacheImage.appending(overlayImage)
let storageDeviceAttachment = try VZDiskImageStorageDeviceAttachment(diskImage: stackedImage)
let storageDeviceConfiguration =
VZVirtioBlockDeviceConfiguration(attachment: storageDeviceAttachment)
virtualMachineConfiguration.storageDevices = [storageDeviceConfiguration]
let virtualMachine = VZVirtualMachine(configuration: virtualMachineConfiguration) Configure a custom Virtio device
import Virtualization
let deviceConfiguration = VZCustomVirtioDeviceConfiguration()
// Virtio entropy device.
deviceConfiguration.deviceID = 4
// PCI class for crypto devices.
deviceConfiguration.pciClassID = 0x10
// PCI subclass for network and computing encryption controllers.
deviceConfiguration.pciSubclassID = 0x00
// An entropy device uses a single Virtio queue.
deviceConfiguration.virtioQueueCount = 1
deviceConfiguration.provider =
VZCustomVirtioDeviceDelegateProvider(deviceQueue: deviceQueue, delegate: provider)
virtualMachineConfiguration.customVirtioDevices = [deviceConfiguration]
let virtualMachine = VZVirtualMachine(configuration: virtualMachineConfiguration) Attach a delegate to a VZCustomVirtioDevice
import Virtualization
class DeviceConfigurationDelegate: NSObject, VZCustomVirtioDeviceConfigurationDelegate {
func customVirtioConfiguration(_ deviceConfiguration: VZCustomVirtioDeviceConfiguration,
didCreateDevice device: VZCustomVirtioDevice) {
device.delegate = deviceDelegate
self.device = device
}
} Process Virtio queue elements
import Virtualization
class DeviceDelegate: NSObject, VZCustomVirtioDeviceDelegate {
func customVirtioDevice(_ device: VZCustomVirtioDevice,
didReceiveNotificationFor queue: VZVirtioQueue) {
while let element = queue.nextElement() {
// Process element...
element.returnToQueue()
}
}
} Resources
Related sessions
-
11 min