Expose simulator extras (privacy, appearance, status-bar, openurl, push, location, add-media, screenshot, record-video) via maui apple simulator#308
Conversation
maui apple simulator
There was a problem hiding this comment.
Pull request overview
Adds new “simulator extras” commands under maui apple simulator, exposing additional xcrun simctl-backed functionality via Xamarin.Apple.Tools.MaciOS and extending JSON output + tests accordingly.
Changes:
- Adds 9 new
maui apple simulatorsubcommands (privacy, appearance, status-bar, openurl, push, location, add-media, screenshot, record-video). - Extends
IAppleProvider/AppleProviderand introduces shared enum/token parsing for simulator-related options. - Adds JSON output models + source-gen context registrations and expands unit/smoke-test coverage.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Cli/Microsoft.Maui.Cli/Providers/Apple/SimulatorEnumParsing.cs | New shared token→enum parsing helpers for simulator commands. |
| src/Cli/Microsoft.Maui.Cli/Providers/Apple/IAppleProvider.cs | Extends provider interface with simulator extras operations. |
| src/Cli/Microsoft.Maui.Cli/Providers/Apple/AppleProvider.cs | Implements new simulator extras operations via SimulatorService. |
| src/Cli/Microsoft.Maui.Cli/Output/MauiCliJsonContext.cs | Registers new simulator extras JSON models for source-gen serialization. |
| src/Cli/Microsoft.Maui.Cli/Output/JsonOutputModels.cs | Adds JSON result records for new simulator extras commands. |
| src/Cli/Microsoft.Maui.Cli/Errors/ErrorCodes.cs | Adds new error codes for simulator extras failures. |
| src/Cli/Microsoft.Maui.Cli/DevFlow/DevFlowCommands.cs | Updates DevFlow permission flow to use shared parsing + provider privacy API. |
| src/Cli/Microsoft.Maui.Cli/Commands/AppleCommands.cs | Adds command handlers for simulator extras subcommands. |
| src/Cli/Microsoft.Maui.Cli.UnitTests/Fakes/FakeAppleProvider.cs | Extends test fake with new APIs + call tracking. |
| src/Cli/Microsoft.Maui.Cli.UnitTests/AppleSimulatorCommandsTests.cs | Adds unit coverage for command tree, parsing, JSON models, and handler behavior. |
| plugins/dotnet-maui/skills/maui-devflow-debug/references/ios-and-mac.md | Documents new maui apple simulator … wrappers vs raw simctl. |
| eng/smoke-tests/apple-cli-smoke-test.sh | Extends smoke tests to cover new simulator extras commands. |
| // Emit a "recording started" signal so JSON consumers know we're active. | ||
| if (useJson) | ||
| formatter.WriteInfo("{\"status\":\"recording\",\"udid\":\"" + udid + "\",\"output_path\":\"" + outputPath.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"}"); | ||
| else | ||
| formatter.WriteInfo($"Recording simulator '{udid}' to '{outputPath}'. Press Ctrl-C to stop."); |
| formatter.Write(new SimulatorPrivacyResult { Udid = udid, Action = action, Service = SimulatorPrivacy.ToSimctlServiceName(permission), BundleIdentifier = bundleId, Success = true }); | ||
| else | ||
| formatter.WriteSuccess($"Permission '{permissionText}' {action}ed on simulator '{udid}'" + (bundleId != null ? $" for {bundleId}." : ".")); |
| public const string AppleSimulatorPrivacyFailed = "E2215"; | ||
| public const string AppleSimulatorAppearanceFailed = "E2216"; | ||
| public const string AppleSimulatorStatusBarFailed = "E2217"; | ||
| public const string AppleSimulatorOpenUrlFailed = "E2218"; | ||
| public const string AppleSimulatorPushFailed = "E2219"; |
…o SimulatorService Co-authored-by: rmarinho <1235097+rmarinho@users.noreply.github.com>
Co-authored-by: rmarinho <1235097+rmarinho@users.noreply.github.com>
…rd-video signal - Refactor 'appearance' from positional args to proper subcommands (get/light/dark <udid>) for consistency with other simulator commands where <udid> is always first - Fix location set: change Argument<double> to Argument<string> with manual parsing to avoid System.CommandLine failing on negative longitude values (e.g. -122.009) - Emit JSON 'recording started' status before blocking in record-video so consumers know recording is active without waiting for Ctrl-C - Add clarifying comment for '+' token handling in TryParseDataNetwork - Add AppearanceCommand_HasGetLightDarkSubcommands structural test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ac216b4 to
f95ccd0
Compare
| { | ||
| var udidArg = new Argument<string>("udid") { Description = "Simulator UDID" }; | ||
| var outputArg = new Argument<string>("output-path") { Description = "Path to write the recorded video to" }; | ||
| var formatOption = new Option<string?>("--format") { Description = "Video format: mp4 (default), h264, fmp4, gif" }; |
There was a problem hiding this comment.
This option currently exposes formats that simctl recordVideo no longer accepts. The MacDev wrapper maps RecordingOptions.Format to xcrun simctl io <udid> recordVideo --type=<value>, but current simctl io help only supports recordVideo [--codec=h264|hevc]; it does not accept --type, mp4, fmp4, or gif. As a result, any invocation with --format will cause simctl to exit immediately, while StartRecording() can still return a process handle and this command will wait for Ctrl-C before reporting success.
Can we switch this surface to a --codec h264|hevc option or update the provider/package to emit --codec=... and reject unsupported values? It would also be good to detect early simctl process exit before blocking/reporting success.
- Replace --format with --codec h264|hevc on record-video command (modern simctl only accepts --codec, not --type/format) - Fix recording-started JSON output: use proper typed model instead of raw JSON string inside WriteInfo (fixes machine-readable output) - Fix privacy success message grammar: 'revokeed' → 'revoked', 'reseted' → 'reset' via explicit past-tense mapping - Add SimulatorRecordingStartedResult model + JSON context registration - Add TryParseVideoCodec() for validated codec parsing - Add tests for codec parsing and record-video --codec option Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Exposes 9 new simulator extras commands under
maui apple simulator, wrapping the upstreamSimulatorServiceAPIs fromXamarin.Apple.Tools.MaciOS:privacy grant|revoke|reset— manage app privacy permissions (location, photos, camera, etc.)appearance get|light|dark— get/set simulator appearance modestatus-bar override|clear— override status bar (time, battery, network, etc.)openurl— open a URL in the simulatorpush— send a push notification via APNs payload JSONlocation set|clear— set/clear simulated GPS coordinatesadd-media— add photos/videos to the simulator photo libraryscreenshot— capture simulator screenshot (png/tiff/bmp/gif/jpeg)record-video— record simulator screen (mp4/fmp4)Changes
AppleCommands.cs— 9 new command registrations with full--jsonsupportIAppleProvider.cs/AppleProvider.cs— 13 new provider methods delegating to upstream servicesFakeAppleProvider.cs— test fake with call trackingSimulatorEnumParsing.cs— shared token→enum mappers for privacy services, data networks, cell bars, wifi bars, battery stateMauiCliJsonContext.cs— JSON serialization contexts for new response modelsErrorCodes.cs— 5 new error codes (E2211–E2215)AppleSimulatorCommandsTests.cs— 93 unit tests covering all commandsapple-cli-smoke-test.sh— updated smoke test scriptFixes Applied During Review
appearancerefactored to subcommands — changed fromappearance <mode> <udid>(positional args) toappearance get|light|dark <udid>(proper subcommands), consistent with all other simulator commandslocation setnegative longitude —Argument<double>failed to parse-122.009(System.CommandLine interpreted-1as option flag). Fixed withArgument<string>+ manualdouble.TryParseusingInvariantCulturerecord-videoJSON signal — now emits{"status":"recording",...}before the blocking wait, so JSON consumers know recording startedTryParseDataNetworkcomment — added explanatory comment about+token survival throughNormalize()Local Testing (macOS, iPhone 17 Pro simulator)
All commands tested successfully on a booted simulator:
Unit Tests
93/93 tests passing: