iOS Simulator Driver

jumpstarter-driver-iossimulator manages a simulator on a local macOS exporter. It provides a power child for lifecycle control and an ios child for the shared iOS client, backed by an operator-installed idb_companion.

Installation

$ pip3 install --extra-index-url https://pkg.jumpstarter.dev/simple jumpstarter-driver-iossimulator

The exporter requires a logged-in macOS session, the full Xcode app selected as the active developer directory (sudo xcode-select -s /Applications/Xcode.app; the standalone command-line tools lack simctl), an iOS 17.4+ simulator runtime, and idb_companion. Install an idb client on each macOS or Linux client. External tools are installed separately under their respective licenses; the driver does not bundle or download them.

For Xcode 27, use a companion containing the upstream display-activity fallback; released companion 1.6.2 cannot capture screenshots on that runtime. Keep the companion executable with its distribution’s adjacent frameworks and resource bundles, and set idb_companion to its absolute path when needed.

Configuration

export:
  simulator:
    type: jumpstarter_driver_iossimulator.driver.IosSimulator
    config:
      device_type: com.apple.CoreSimulator.SimDeviceType.iPhone-18-Pro
      runtime: com.apple.CoreSimulator.SimRuntime.iOS-27-0

Find available identifiers with xcrun simctl list devicetypes and xcrun simctl list runtimes. Configure either a new simulator or a golden source:

Parameter

Description

device_type, runtime

Device type and iOS runtime for a new simulator

golden_device_set, golden_udid

Dedicated device set and simulator UUID to clone instead

A golden source must remain shutdown and unchanged while cloning. The driver leaves it intact and rejects the user’s default CoreSimulator device set as a source.

Optional parameter

Default

Description

device_name

Jumpstarter iOS Simulator

Simulator name

state_dir

/private/tmp

Existing writable directory for private state; use a short path for Unix sockets

xcrun

xcrun

Xcode tool executable

idb_companion

idb_companion

Companion executable

command_timeout

30

Metadata and creation timeout in seconds

boot_timeout

180

Boot and readiness timeout in seconds

companion_timeout

30

Companion readiness timeout in seconds

shutdown_timeout

30

Shutdown, deletion and process-stop timeout in seconds

http_service

Unconfigured

HTTPS provider class and options from trusted exporter configuration

Usage

Inside a local or leased Jumpstarter shell:

j simulator power on
j simulator ios info
j simulator ios -- idb describe --json
j simulator ios -- idb install /path/to/YourApp.app
j simulator power off

Use j simulator ios serve to keep a local companion endpoint open for an external idb process, or j simulator ios connect to register it with idb.

The Python API supports the same transport context managers as physical devices:

from jumpstarter.common.utils import serve
from jumpstarter_driver_iossimulator.driver import IosSimulator

driver = IosSimulator(
    device_type="com.apple.CoreSimulator.SimDeviceType.iPhone-18-Pro",
    runtime="com.apple.CoreSimulator.SimRuntime.iOS-27-0",
)
with serve(driver) as simulator:
    simulator.power.on()
    with simulator.ios.serve() as endpoint:
        print(endpoint)  # Pass to idb's --companion option.
    simulator.power.off(destroy=True)

power.on() is idempotent. power.off() stops the companion and simulator while preserving the lease’s data; another on() reuses it. A failed first on() removes the partially created simulator; a failed restart only stops it, keeping the lease’s data for a retry. off(destroy=True), reset and session close delete the owned device set. power.read() is unsupported.

Optional HTTPS service

A trusted exporter configuration can add an HTTPS service for the lease’s simulator by naming an HttpServiceProvider class and its options in the simulator’s config:

http_service:
  provider: your_package.services.YourProvider
  options: {}

Clients use the generic ios.https() context manager or j simulator ios https -- COMMAND; they cannot select the provider, its executable, host address or options. The service starts when HTTPS metadata is requested after power.on().

with simulator.ios.https() as endpoint:
    url = endpoint.url
    context = endpoint.ssl_context()
    metadata = endpoint.metadata

The endpoint exposes its URL, public CA file and the provider’s metadata. Keep certificate and hostname verification enabled. The CLI passes JUMPSTARTER_IOS_HTTPS_URL, JUMPSTARTER_IOS_HTTPS_CA_FILE and JUMPSTARTER_IOS_HTTPS_METADATA to the command. The client API is shared with the iOS device driver.

Security and limitations

Each lease owns a private device set and companion Unix socket. Lifecycle commands explicitly select that set; failures retain ownership when cleanup must be retried. Core lifecycle uses simctl without launching Simulator.app or Device Hub. Only local macOS execution is supported.

The owning exporter holds a lock on its lease directory. If an exporter exits without cleanup, for example after a crash, the next lease or session reset in the same state_dir shuts down and deletes that lease’s simulators, stops processes still using its directory, such as its companion and HTTP service, and removes it. Live leases and directories without a lease lock are never touched.

Simulators share the Mac’s network namespace, so arbitrary TCP forwarding is unavailable. A configured HTTP provider is trusted exporter code and must restrict access to its simulator. Its constructor must clean partial resources on failure; its idempotent close() must revoke streams and remove owned state.

API Reference

class jumpstarter_driver_iossimulator.driver.IosSimulator

Manage a local macOS simulator in a private device set.

Configure device_type and runtime to create a simulator, or golden_device_set and golden_udid to clone a shutdown source. Power off preserves lease data; destroy, reset and close remove it. Xcode and idb_companion must be installed on the exporter.

class jumpstarter_driver_iosdevice.client.IosDeviceClient
connect(protocol: str | None = None, *, port: int = 0, usbfluxctl: str = 'usbfluxctl', idb: str = 'idb', timeout: float = 60.0) → Generator[str, None, None]

Attach with the user’s usbfluxctl or idb and detach on exit.

The user installs and runs usbfluxd before attaching a usbmux endpoint. Cleanup also covers a timed out or failed attach, and stays bounded.

https(*, port: int = 0) → Generator[HttpsEndpoint, None, None]

Expose the configured HTTPS service with its public CA and metadata.

The client does not interpret provider metadata or configure tools. Closing the context removes its listener and CA files. The exporter owns service resources until lease teardown or reset.

serve(protocol: str | None = None, *, port: int = 0) → Generator[str, None, None]

Serve a protocol on IPv4 loopback without invoking device tools.

The native protocol is the first one advertised by the target. port=0 selects an unused local port. The yielded endpoint is 127.0.0.1:port.

class jumpstarter_driver_iossimulator.http_service.HttpServiceProvider

An HTTPS service scoped to one simulator lease.

Constructors must remove partial resources before raising. close must be idempotent and revoke existing streams as well as prevent new ones. A close failure leaves the provider and device set owned for a cleanup retry. Providers must not discover, stop or mutate resources outside their context.

abstractmethod close() → None

Revoke streams, stop owned processes and remove private state.

abstractmethod connect()

Return an async context manager yielding the encrypted byte stream.

abstractmethod metadata() → dict

Return public ca_certificate PEM and a JSON metadata object.