pub struct SimctlClient {}Expand description
Stateless wrapper around xcrun simctl. Methods are free functions
in spirit (no instance state beyond optionally-cached xcrun path);
kept as a struct for API ergonomics + future caching.
Implementations§
Source§impl SimctlClient
impl SimctlClient
Sourcepub async fn list_runtimes(&self) -> Result<Vec<SimctlRuntime>, SimctlError>
pub async fn list_runtimes(&self) -> Result<Vec<SimctlRuntime>, SimctlError>
xcrun simctl list runtimes -j → Vec<SimctlRuntime>.
Sourcepub async fn list_devices(&self) -> Result<Vec<SimctlDevice>, SimctlError>
pub async fn list_devices(&self) -> Result<Vec<SimctlDevice>, SimctlError>
xcrun simctl list devices -j → flattened Vec<SimctlDevice>.
Sourcepub async fn boot(&self, udid: &str) -> Result<(), SimctlError>
pub async fn boot(&self, udid: &str) -> Result<(), SimctlError>
xcrun simctl boot <udid> — fire-and-forget boot request.
Sourcepub async fn shutdown(&self, udid: &str) -> Result<(), SimctlError>
pub async fn shutdown(&self, udid: &str) -> Result<(), SimctlError>
xcrun simctl shutdown <udid>.
Sourcepub async fn current_locale(
&self,
udid: &str,
) -> Result<Option<String>, SimctlError>
pub async fn current_locale( &self, udid: &str, ) -> Result<Option<String>, SimctlError>
v6.10 c2 — read the sim’s current BCP-47 locale (first entry of
NSGlobalDomain AppleLanguages). Returns Ok(None) when the
preference is unset (defaults read exits non-zero) or unparseable.
Wire format: simctl spawn <udid> defaults read -g AppleLanguages
stdout looks like "(\n \"en-US\"\n)\n"; we extract the first
quoted token.
Sourcepub async fn set_locale(
&self,
udid: &str,
locale: &str,
) -> Result<(), SimctlError>
pub async fn set_locale( &self, udid: &str, locale: &str, ) -> Result<(), SimctlError>
v6.10 c2 — write AppleLanguages (array) + AppleLocale (scalar)
to the sim’s NSGlobalDomain so SpringBoard + apps re-localize on
next launch. AppleLocale is BCP-47 with hyphen replaced by
underscore (en_US); AppleLanguages is the BCP-47 tag verbatim.
The caller must shutdown + reboot the sim for the change to
take effect — running apps cache the locale at process start.
Insight gol-611 §3 capability.
Sourcepub async fn boot_and_wait(
&self,
udid: &str,
timeout: Duration,
) -> Result<(), SimctlError>
pub async fn boot_and_wait( &self, udid: &str, timeout: Duration, ) -> Result<(), SimctlError>
Boot + poll device state == “Booted” within timeout. Tries every
500 ms until success or timeout_ms elapses. Idempotent on
already-booted devices (xcrun simctl boot 已 booted 返非零, swallow).
Sourcepub async fn erase(&self, udid: &str) -> Result<(), SimctlError>
pub async fn erase(&self, udid: &str) -> Result<(), SimctlError>
xcrun simctl erase <udid> — wipe device contents.
Sourcepub async fn install(
&self,
udid: &str,
app_path: &str,
) -> Result<(), SimctlError>
pub async fn install( &self, udid: &str, app_path: &str, ) -> Result<(), SimctlError>
xcrun simctl install <udid> <app-path> — install a .app bundle.
Sourcepub async fn uninstall(
&self,
udid: &str,
bundle_id: &str,
) -> Result<(), SimctlError>
pub async fn uninstall( &self, udid: &str, bundle_id: &str, ) -> Result<(), SimctlError>
xcrun simctl uninstall <udid> <bundle-id>.
Sourcepub async fn terminate(
&self,
udid: &str,
bundle_id: &str,
) -> Result<(), SimctlError>
pub async fn terminate( &self, udid: &str, bundle_id: &str, ) -> Result<(), SimctlError>
xcrun simctl terminate <udid> <bundle-id> — kill a running app.
Sourcepub async fn launch(
&self,
udid: &str,
bundle_id: &str,
) -> Result<LaunchResult, SimctlError>
pub async fn launch( &self, udid: &str, bundle_id: &str, ) -> Result<LaunchResult, SimctlError>
xcrun simctl launch <udid> <bundleId> → parse "<bundle>: <pid>".
Sourcepub async fn launch_with_args(
&self,
udid: &str,
bundle_id: &str,
args: &[String],
) -> Result<LaunchResult, SimctlError>
pub async fn launch_with_args( &self, udid: &str, bundle_id: &str, args: &[String], ) -> Result<LaunchResult, SimctlError>
xcrun simctl launch <udid> <bundleId> -- <arg>... — launch with a
process-level argument vector. Empty args is equivalent to
Self::launch. v5.2 c2 — maestro yaml launchApp.arguments 同源.
Sourcepub async fn launch_with_args_and_env(
&self,
udid: &str,
bundle_id: &str,
args: &[String],
child_env: &[(&str, &str)],
) -> Result<LaunchResult, SimctlError>
pub async fn launch_with_args_and_env( &self, udid: &str, bundle_id: &str, args: &[String], child_env: &[(&str, &str)], ) -> Result<LaunchResult, SimctlError>
v6.8 c2 — like Self::launch_with_args but also sets
SIMCTL_CHILD_* envp on the simctl process so the launched app
can read deploy-time vars via ProcessInfo().environment["KEY"].
child_env keys without the SIMCTL_CHILD_ prefix get it added
automatically (per compose_child_env semantics). Insight
gol-611 §4 — used to prelaunch an app before any openLink so
iOS treats the subsequent URL handoff as in-app routing instead
of cross-app, side-stepping the SpringBoard “Open in ‘
Sourcepub async fn open_url(&self, udid: &str, url: &str) -> Result<(), SimctlError>
pub async fn open_url(&self, udid: &str, url: &str) -> Result<(), SimctlError>
xcrun simctl openurl <udid> <url> — open a URL on the device.
Sourcepub async fn send_push(
&self,
udid: &str,
bundle_id: &str,
apns_json_path: &str,
) -> Result<(), SimctlError>
pub async fn send_push( &self, udid: &str, bundle_id: &str, apns_json_path: &str, ) -> Result<(), SimctlError>
v5.7 c3 — xcrun simctl push <udid> <bundle-id> <apns-json-path>.
Deliver an APNS payload to a sim-installed app. The payload file is
a JSON document whose top-level dictionary mirrors what an APNS
provider would send; aps.alert.body / aps.alert.title surface
as banner content and reach the app’s
UNUserNotificationCenterDelegate.
Sourcepub async fn set_appearance(
&self,
udid: &str,
mode: Appearance,
) -> Result<(), SimctlError>
pub async fn set_appearance( &self, udid: &str, mode: Appearance, ) -> Result<(), SimctlError>
xcrun simctl ui <udid> appearance <light|dark> — set UI appearance.
Sourcepub async fn grant_permission(
&self,
udid: &str,
permission: SimctlPermission,
bundle_id: &str,
) -> Result<(), SimctlError>
pub async fn grant_permission( &self, udid: &str, permission: SimctlPermission, bundle_id: &str, ) -> Result<(), SimctlError>
xcrun simctl privacy <udid> grant <perm> <bundle-id>.
Sourcepub async fn revoke_permission(
&self,
udid: &str,
permission: SimctlPermission,
bundle_id: &str,
) -> Result<(), SimctlError>
pub async fn revoke_permission( &self, udid: &str, permission: SimctlPermission, bundle_id: &str, ) -> Result<(), SimctlError>
xcrun simctl privacy <udid> revoke <perm> <bundle-id> — explicitly
deny the permission. v5.2 c2 — maestro yaml permissions: { x: deny }
同源(grant 反向). 不同于 reset(那是回到 “not determined”).
Sourcepub async fn location_set(
&self,
udid: &str,
latitude: f64,
longitude: f64,
) -> Result<(), SimctlError>
pub async fn location_set( &self, udid: &str, latitude: f64, longitude: f64, ) -> Result<(), SimctlError>
v5.2 c5 — xcrun simctl location <udid> set <lat>,<lng> — set sim
location to a fixed point. maestro setLocation 同源.
Sourcepub async fn location_start(
&self,
udid: &str,
points: &[(f64, f64)],
speed_mps: Option<f64>,
) -> Result<(), SimctlError>
pub async fn location_start( &self, udid: &str, points: &[(f64, f64)], speed_mps: Option<f64>, ) -> Result<(), SimctlError>
v5.2 c5 — xcrun simctl location <udid> start [--speed=<m/s>] <waypoints>
— interpolate sim location along waypoints. Fire-and-return: simctl
injects scenario and returns; sim continues interpolation in background.
maestro travel 同源.
Sourcepub async fn location_clear(&self, udid: &str) -> Result<(), SimctlError>
pub async fn location_clear(&self, udid: &str) -> Result<(), SimctlError>
v5.2 c5 — xcrun simctl location <udid> clear — reset active
location scenario.
Sourcepub async fn add_media(
&self,
udid: &str,
paths: &[String],
) -> Result<(), SimctlError>
pub async fn add_media( &self, udid: &str, paths: &[String], ) -> Result<(), SimctlError>
v5.2 c5 — xcrun simctl addmedia <udid> <path>... — add photos /
videos / contacts to sim library. maestro addMedia 同源 (scalar or
array form already flattened on adapter side).
Sourcepub async fn record_video_start(
&self,
udid: &str,
path: &str,
) -> Result<RecordingHandle, SimctlError>
pub async fn record_video_start( &self, udid: &str, path: &str, ) -> Result<RecordingHandle, SimctlError>
v5.2 c5 — start recording sim display to path. Spawns
xcrun simctl io <udid> recordVideo <path> as a long-running child;
returns handle immediately. Caller must pair with
Self::record_video_stop for clean SIGINT-and-wait shutdown —
dropping the handle would SIGKILL via tokio + lose mp4 trailer.
Sourcepub async fn record_video_stop(
&self,
handle: RecordingHandle,
) -> Result<(), SimctlError>
pub async fn record_video_stop( &self, handle: RecordingHandle, ) -> Result<(), SimctlError>
v5.2 c5 — stop a recording via SIGINT + wait (≤10s). SIGINT lets simctl trap and flush the mp4 trailer; SIGKILL would corrupt output. Timeout escalates to SIGKILL with explicit error mentioning truncation.
Sourcepub async fn reset_permission(
&self,
udid: &str,
permission: SimctlPermission,
bundle_id: &str,
) -> Result<(), SimctlError>
pub async fn reset_permission( &self, udid: &str, permission: SimctlPermission, bundle_id: &str, ) -> Result<(), SimctlError>
xcrun simctl privacy <udid> reset <perm> <bundle-id> — return the
permission to “not determined” so the next request re-prompts.
May terminate a running instance of the target app (Apple
behavior) — call before launch, not mid-flow.
Sourcepub async fn keychain_reset(&self, udid: &str) -> Result<(), SimctlError>
pub async fn keychain_reset(&self, udid: &str) -> Result<(), SimctlError>
xcrun simctl keychain <udid> reset — clear all keychain entries.
Sourcepub async fn pasteboard_get(&self, udid: &str) -> Result<String, SimctlError>
pub async fn pasteboard_get(&self, udid: &str) -> Result<String, SimctlError>
xcrun simctl pbpaste <udid> — read clipboard contents.
Sourcepub async fn pasteboard_set(
&self,
udid: &str,
text: &str,
) -> Result<(), SimctlError>
pub async fn pasteboard_set( &self, udid: &str, text: &str, ) -> Result<(), SimctlError>
xcrun simctl pbcopy <udid> — write clipboard contents (via piped stdin).
Sourcepub async fn set_reduce_motion(
&self,
udid: &str,
enabled: bool,
) -> Result<(), SimctlError>
pub async fn set_reduce_motion( &self, udid: &str, enabled: bool, ) -> Result<(), SimctlError>
Toggle “Reduce Motion” accessibility setting via defaults write.
Sourcepub async fn screenshot(&self, udid: &str) -> Result<Vec<u8>, SimctlError>
pub async fn screenshot(&self, udid: &str) -> Result<Vec<u8>, SimctlError>
xcrun simctl io <udid> screenshot <tmpfile> → raw PNG bytes.
Goes through a temp file: current Xcode’s screenshot - does not
treat - as stdout — it writes a literal file named - in cwd
and emits nothing on stdout (observed on Xcode/iOS 26.5).
Sourcepub async fn create_device(
&self,
name: &str,
device_type: &str,
runtime_id: &str,
) -> Result<String, SimctlError>
pub async fn create_device( &self, name: &str, device_type: &str, runtime_id: &str, ) -> Result<String, SimctlError>
xcrun simctl create <name> <device-type-id> <runtime-id> → udid.
Sourcepub async fn delete_device(&self, udid: &str) -> Result<(), SimctlError>
pub async fn delete_device(&self, udid: &str) -> Result<(), SimctlError>
xcrun simctl delete <udid> — delete a simulator device.