View in English

  • Apple Developer
    • Get Started

    Explore Get Started

    • Overview
    • Learn
    • Apple Developer Program

    Stay Updated

    • Latest News
    • Hello Developer
    • Platforms

    Explore Platforms

    • Apple Platforms
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    Featured

    • Design
    • Distribution
    • Games
    • Accessories
    • Web
    • Home
    • CarPlay
    • Technologies

    Explore Technologies

    • Overview
    • Xcode
    • Swift
    • SwiftUI

    Featured

    • Accessibility
    • App Intents
    • Apple Intelligence
    • Games
    • Machine Learning & AI
    • Security
    • Xcode Cloud
    • Community

    Explore Community

    • Overview
    • Meet with Apple events
    • Community-driven events
    • Developer Forums
    • Open Source

    Featured

    • WWDC
    • Swift Student Challenge
    • Developer Stories
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Centers
    • Documentation

    Explore Documentation

    • Documentation Library
    • Technology Overviews
    • Sample Code
    • Human Interface Guidelines
    • Videos

    Release Notes

    • Featured Updates
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • Downloads

    Explore Downloads

    • All Downloads
    • Operating Systems
    • Applications
    • Design Resources

    Featured

    • Xcode
    • TestFlight
    • Fonts
    • SF Symbols
    • Icon Composer
    • Support

    Explore Support

    • Overview
    • Help Guides
    • Developer Forums
    • Feedback Assistant
    • Contact Us

    Featured

    • Account Help
    • App Review Guidelines
    • App Store Connect Help
    • Upcoming Requirements
    • Agreements and Guidelines
    • System Status
  • Quick Links

    • Events
    • News
    • Forums
    • Sample Code
    • Videos
 

Videos

Open Menu Close Menu
  • Collections
  • All Videos
  • About

Back to WWDC26

  • About
  • Summary
  • Transcript
  • Code
  • 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.

    Chapters

    • 0:01 - Introduction
    • 1:04 - macOS guest provisioning
    • 4:34 - Accessory Access
    • 8:26 - Advanced network topologies
    • 11:35 - DiskImageKit
    • 15:57 - Custom Virtio

    Resources

    • DiskImageKit
    • Accessory Access
    • vmnet
    • Virtual I/O Device (VIRTIO) Version 1.4
    • Virtualization
      • HD Video
      • SD Video

    Related Videos

    WWDC26

    • Discover container machines
  • Search this video…

    Hello! I'm Ronnie Misra from the Virtualization team. In this session, I'll explore how you can add advanced capabilities to your Virtualization app. You can use the Virtualization framework to create apps that power full, desktop experiences or enable sophisticated developer workflows, like testing collaborative Mac apps, and networking between devices. You can also build command line tools and automation to enable consistent testing in controlled environments.

    Today, I'll take you through some new and existing APIs to make your Virtualization apps even more powerful. I'll cover: automating the setup of Virtual Macs, and attaching USB devices to virtual machines with the Accessory Access framework. I'll explore configuring advanced network topologies, and how to create high-performance, efficient disk images with the DiskImageKit framework. Finally, I'll cover creating custom, high-performance virtual devices with Virtio. First, I'll show you how Virtualization enables you to automate macOS guest provisioning. After you install macOS into a virtual Mac, you can set it up exactly the same way as you would set up a physical Mac. You use the same Setup Assistant you are already familiar with. This gives you an easy way to create a user account and configure common settings. For automation use cases, however, it would be convenient to be able to programmatically set up a virtual Mac.

    The Virtualization framework now lets your app specify provisioning options when a virtual Mac is started. You provide a full name, username, and password, and optionally enable auto-login or remote login via SSH.

    When the guest boots for the first time, these parameters are automatically passed to Setup Assistant. A user is created with the specified credentials, and auto-login and remote login are enabled if requested. To use the macOS guest provisioning API, you first create a VZMacGuestProvisioningOptions object with your desired settings. Here, I have created provisioningOptions that will create a user account, enable auto login, and also enable SSH. You then construct a VZMacOSVirtualMachineStartOptions object and set its guest provisioning to the provisioningOptions you just constructed. Finally, you start your virtual Mac using these startOptions. When the guest boots, these provisioning options will be used to automate provisioning of the virtual Mac. Now, I'll show you this in action. I've modified the macOS virtual machine sample app to make use of the macOS guest provisioning API. I have already installed macOS into a new virtual Mac, but I have not booted it yet. I'll double-click the app to boot the virtual Mac for the first time.

    The app prompts me for Provisioning Options. Because I have previously run this app, it remembers my preferred provisioning options to create a user for Jane Appleseed and enable automatic login and remote login. I'll now click OK to accept those settings.

    My app has now started the virtual Mac with those provisioning options. The Virtualization framework will pass those options into the guest, so I don't have to navigate through setup assistant manually. Setup assistant automatically creates a new user. Setup assistant has now created the new account. Because my provisioning options indicated that automatic login should be enabled, the guest has logged into the account. I'll now open a Finder window in my virtual Mac.

    The sidebar shows the username jappleseed, which matches the username I provided. Now, I'll open up System Settings and browse to the Remote Login sharing setting.

    System Settings confirms that Remote Login has been enabled. My virtual Mac is now ready to go! All I had to do was boot it. Note that these settings are only honored if the guest has not already been set up. If a user has already been created in the guest, provisioning options passed on subsequent boots will be ignored.

    When using these APIs, be thoughtful about how you handle passwords, and consider the security implications for your app. For example, instead of hardcoding a password in your code, you might want to read it from the Keychain, or a configuration file, or an environment variable. Next, I'll talk about attaching USB accessories using Accessory Access.

    Some virtual machine use cases require the ability to grant the guest access to a USB accessory connected to the host. For example, someone may want to make use of a USB drive from inside of a virtual machine. At the same time, people should remain in control of their devices. Accessory Access is a new framework designed to support making USB devices available to macOS and Linux virtual machines. A key principle of Accessory Access is that people should have explicit control of which devices are attached to which apps. People have visibility into what apps are using their devices, and can attach and detach devices at any time. Accessory Access supports device hot plugging. When someone grants an app access to a device, it can be attached to the virtual machine at runtime without changing the VM's static configuration.

    Before I dive into the details, here is Accessory Access in action. I'm running the macOS virtual machine sample app I showed you before. I'll now connect a USB drive to my Mac.

    The icon for my drive has appeared on the desktop. Also, because the virtual machine app is running and has indicated interest in storage devices, an accessory icon is now present in the menu bar. I'll now select my disk in the accessory menu and attach it to my app.

    Since I attached this drive to my virtual Mac, my host has unmounted the drive, and the guest has mounted it. Now I'll safely eject the drive from inside the virtual Mac.

    Then I'll use the accessory menu to release the drive back to my host.

    Now that I have released the drive to my host, the host has remounted the drive. This demonstrates how Accessory Access makes it easy to use your USB accessories from a virtual machine.

    To use Accessory Access, your app registers a listener with matching criteria describing the types of devices it is interested in. You can filter by device class and subclass, vendor ID and product ID, or other criteria.

    When a matching device is connected to the Mac, the Accessory Access menu extra appears. From here, someone can decide to attach the device to your app.

    If the device is attached to your app, your app's listener object will be notified of the newly attached device. To use Accessory Access, you start by creating an array of AAUSBAccessoryMatchingCriteria objects describing the types of devices you are interested in. You can use an empty array to express interest in all USB devices. Then use AAUSBAccessoryManager to register a listener. This listener should implement the AAUSBAccessoryListener protocol. registerListener will return any accessories that were previously attached to your application. When someone attaches a device to your app, your listener's usbAccessoryDidConnect function will be called. In this function, you can attach the device to your virtual machine. VZVirtualMachine requires modifications to happen on its own queue. On that queue, you can use the VZUSBPassthroughDeviceConfiguration class to create a VZUSBPassthroughDevice, and then attach this device to one of the virtualMachine's USB controllers.

    In order for your app to use Accessory Access, add the Claim USB Accessory capability to your Xcode target's capabilities. Remember that people can choose to attach or detach devices from your app at any time. Your app should handle these events gracefully. Consult the Accessory Access documentation for details on supported device types.

    In macOS 26 and later, your app can use the vmnet framework to configure virtual network interfaces. The Virtualization framework makes it easy to configure isolated virtual machines with basic NAT or bridge networking. For more advanced use cases, however, you may want to have more control of how VMs interact with each other or with the external network. For example, you may want to test connections to your server virtual machine from clients on either the same or a different network. The vmnet framework allows you to create custom network topologies to support these advanced use cases.

    Using the vmnet framework, you can create custom network topologies for your macOS and Linux VMs. vmnet allows you to control how your VMs can communicate with each other. vmnet also allows you to configure various parameters of those custom networks. For example, you can configure the DHCP settings for the network, or add rules to forward TCP or UDP host ports to specific virtual machines.

    To use vmnet with the Virtualization framework, you first create a vmnet network configuration object. You use that configuration to construct a vmnet network object. You can then use that network object to construct a network device attachment. This network device attachment is then attached to a network device configuration, which is in turn added to a virtual machine configuration. Finally, you use that virtual machine configuration to construct a virtual machine. If you want a second virtual machine to use the same vmnet network, you follow the same steps to configure that second virtual machine, making sure to use the same vmnet network object.

    Now I'll show you these steps in code. You first create a vmnet configuration object using vmnet_network_configuration_create. vmnet provides several functions to customize that network: for example, you can configure the network's DHCP settings, enable port forwarding, etc.

    Once you have a network configuration object, you can use vmnet_network_create to construct a vmnet network object. You then construct a VZVmnetNetworkDeviceAttachment to allow Virtualization to use the vmnet network you just created.

    Next, set the attachment on a VZVirtioNetworkDeviceConfiguration object. This networkDeviceConfiguration is added to the array of networkDevices on your VZVirtualMachineConfiguration object. And finally, this configuration will be used to construct your VZVirtualMachine. A vmnet network object is a reference counted Objective-C object. The network goes away when the last reference is released. This also implies that a vmnet network is not persisted when your app quits. If you want to create a consistent network configuration, your app must persist your vmnet settings itself.

    vmnet provides the vmnet_network_copy_serialization and vmnet_network_create_with_serialization APIs to allow you to transfer a vmnet network across an XPC connection from one process to another.

    This is useful if you would like to run multiple VMs in separate processes but connect them to the same network. Next, I'll show you how to use DiskImageKit to efficiently work with disk images. The Virtualization framework supports using standard raw disk image files to back virtual machine disks. This simple format maps disk blocks to file blocks one-to-one. This simplicity means that the format is widely supported by existing software. However, this simplicity comes with a cost. Raw disk images cannot inherently represent sparsity for example, a 100 gigabyte disk is represented by a 100 gigabyte file. This also makes snapshots expensive. Snapshotting a VM's disk requires making a copy of the entire disk.

    DiskImageKit is a new framework in macOS 27 that is designed to make disk image management more efficient. It supports the Apple Sparse Image Format or ASIF that was introduced in macOS 26. DiskImageKit allows you to construct a stack of images, allowing writes to go into an overlay layer while leaving the base layer unmodified. DiskImageKit also supports raw disk images. When constructing a stacked image, DiskImageKit supports a few different types of layers. The bottom layer of a stacked image is called the base layer. This layer can be of any format that is supported by DiskImageKit. Upper layers are always ASIF images. These layers can be either cache or overlay layers. A cache layer can be used to improve performance when underlying layers exist on slow storage like a remote network filesystem. When processing a read request, if the cache layer cannot satisfy the read, DiskImageKit will satisfy the read from lower layers, but store a copy of the data in the cache layer. Subsequent reads of the same data will then be read from the cache.

    Overlay layers can be used to implement copy-on-write semantics for snapshots. When writing to a layered image, if DiskImageKit encounters a writable overlay while traversing the stack, it will store the writes in that layer.

    DiskImageKit allows read-only layers to be shared by multiple concurrent stacks. This allows efficient reuse of shared content between multiple virtual machines while keeping their independent writes separate.

    ASIF images are sparse. This means that an ASIF image may logically represent more blocks than are actually stored in the image. When reading from an ASIF file, blocks that are not stored in the image are treated as if they were zero-filled.

    I'll walk through how DiskImageKit would process read and write requests for an example stack. In this example, the base layer has content for blocks 0, 1 and 4. The cache layer does not have content for any blocks. The overlay layer has updated content for block 4, and also has content for block 5. Note that a layer can have a different logical size than the layers above or below it.

    To satisfy a read of block 0, DiskImageKit will traverse the layers of the stacked image until it finds a layer that contains the content for this block. This read will be satisfied by the base layer. Because there was a cache layer, DiskImageKit will cache the contents of this block and then return the contents to the caller. Subsequent reads of this same block will be satisfied by the cache layer.

    When writing block 2, DiskImageKit will discover that the top layer is an overlay and store the content there.

    To use DiskImageKit images with Virtualization, you first start by creating a DiskImage object.

    If you'd like to use a layered image, you create multiple DiskImage objects and then append them in order.

    You can then construct a VZDiskImageStorageDeviceAttachment from your stackedImage. This can then be attached to a storageDeviceConfiguration, for example a VZVirtioBlockDeviceConfiguration.

    Add this storageDeviceConfiguration to your virtual machine configuration's storageDevices. Finally, create your VZVirtualMachine using this configuration.

    When using stacked images, it is worth noting that shallow stacks perform better. There is a performance cost to increasing the depth of a disk image stack. Keep in mind that a virtual machine is comprised of more than just disk images. For example, a virtual Mac has an auxiliary storage file, and a VM using the EFI boot loader has an EFI variable store file. If you want to clone a VM and use a shared base layer, remember that you must duplicate those other files. Finally, I'll show you how the custom Virtio APIs allow you to build custom communication channels between your app and your Linux virtual machines.

    Although the Virtualization framework already supports a wide range of standard device classes, some use cases may require something more specialized. Perhaps you want to implement a custom protocol for performance-critical communication between host and guest. Maybe you want to implement a coprocessor, such as a Virtio crypto device. You might want to provide efficient guest access to machine learning accelerators. That's where the custom Virtio device API comes in.

    Virtio is an industry standard for paravirtualized devices. It's the protocol used to implement many of the built in Virtualization devices. In macOS 27, the Virtualization framework allows you to implement your own Virtio devices, allowing custom communication between your host app and your Linux virtual machines. This is especially useful for performance-critical scenarios where you need low-latency, high-throughput communication.

    The Virtio protocol makes use of memory buffers shared between the guest and the host. These buffers are organized into Virtio queues. Virtio is designed to minimize the number of context switches between the guest and the host. The device driver in the guest notifies the device running on the host when data has been enqueued. Similarly, the host can use an interrupt to inform the guest driver about enqueued data.

    In macOS 27, the VZCustomVirtioDevice class can be used to implement your custom device. Your app sets a delegate on the device. This delegate will be notified when the guest enqueues data on its queue. You can also initiate activity in the guest by triggering an interrupt on the device.

    To use the custom Virtio device API, you start by creating a VZCustomVirtioDeviceConfiguration object. You configure this object with your device's Virtio device identity, its PCI class and subclass, and the number of Virtio queues your device uses.

    You also set a provider on the configuration. VZCustomVirtioDeviceDelegateProvider is used to configure a delegate that implements the VZCustomVirtioDevice- ConfigurationDelegate protocol.

    You then add this deviceConfiguration to your virtualMachineConfiguration's customVirtioDevices array, and create a VZVirtualMachine using that configuration.

    When the virtual machine is started, a VZCustomVirtioDevice object is created, and your configuration delegate's didCreateDevice function is called. In this function, you should set the device's delegate. This delegate should implement the VZCustomVirtioDeviceDelegate protocol. You can also hang onto the device itself so that your device can trigger guest interrupts.

    There are several functions in the VZCustomVirtioDeviceDelegate protocol that can be used to monitor the device's lifecycle and interact with the device. The didReceiveNotificationFor function is where you implement logic to dequeue elements from your device's queue, process those elements, and then return them to the queue.

    Remember that custom devices require custom drivers to allow the guest to use your device. Virtio queues are designed to provide efficient communication between the guest and the host. Make sure to follow best practices when designing your guest driver to make optimal use of Virtio queues. Before I wrap up, I want to briefly mention some other advancements to Virtualization that can really make your app shine.

    iCloud support is particularly valuable for desktop experiences, allowing people to access their iCloud data and services in the VM. EFI Secure Boot hardens Linux VMs with modern security features. macOS guests can take advantage of Metal features like argument buffers and indirect command buffers.

    You're now ready to add even more capabilities to your Virtualization app. Automate the setup of macOS user accounts by configuring them with provisioning options. Use the Accessory Access framework to attach USB devices to a VM.

    Customize networking for your VMs by building your own network topology and configuring port forwarding. Use the DiskImageKit framework to create efficient, sparse disk images. And for custom, high-performance device needs in Linux guests, consider creating custom devices with Virtio.

    Thanks for watching! Have a great WWDC.

    • 1:57 - 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)
    • 7:12 - 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.
      }
    • 7:39 - 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...
                  }
              }
          }
      }
    • 10:04 - 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)
    • 14:54 - 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)
    • 17:41 - 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)
    • 18:20 - 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
          }
      }
    • 18:42 - 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()
              }
          }
      }
    • 0:01 - Introduction
    • The advanced Virtualization capabilities ahead — automating Virtual Mac setup, attaching USB devices with the Accessory Access framework, configuring advanced networking, creating disk images with DiskImageKit, and building custom Virtio devices.

    • 1:04 - macOS guest provisioning
    • Automate the provisioning of user accounts in Setup Assistant for virtual Macs. Use the VZMacGuestProvisioningOptions API to set credentials and enable features like auto-login and SSH on first boot.

    • 4:34 - Accessory Access
    • Pass through USB accessories directly into virtual machines using the Accessory Access framework. This approach gives people explicit control over which physical devices, such as external drives, are passed through to the virtual machine.

    • 8:26 - Advanced network topologies
    • Configure complex network topologies by integrating the vmnet framework with Virtualization. You can create custom network architectures that define exactly how multiple virtual machines interact with each other and the host.

    • 11:35 - DiskImageKit
    • DiskImageKit is a new framework in macOS 27 designed for managing high-performance, space-efficient disk images. You can use layered disk images, including base layers, cache layers, and overlay layers, to share data efficiently across multiple virtual machines.

    • 15:57 - Custom Virtio
    • Define and implement custom paravirtualized devices using the industry-standard Virtio protocol. By using the VZCustomVirtioDevice API, you can enable specialized, high-performance communication between the host and custom drivers running in the virtual machine.

Developer Footer

  • Videos
  • WWDC26
  • Expand the capabilities of your Virtualization app
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • Apple Intelligence
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Downloads
    • Sample Code
    • Videos
    Open Menu Close Menu
    • Help Guides & Articles
    • Contact Us
    • Forums
    • Feedback & Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • Mini Apps Partner Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Read the latest news.
    Get the Apple Developer app.
    Copyright © 2026 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines