Skip to content

Add simulator app lifecycle APIs (install/uninstall/launch/terminate/get_app_container)#176

Merged
rmarinho merged 2 commits into
mainfrom
copilot/add-simulator-app-lifecycle-apis
May 5, 2026
Merged

Add simulator app lifecycle APIs (install/uninstall/launch/terminate/get_app_container)#176
rmarinho merged 2 commits into
mainfrom
copilot/add-simulator-app-lifecycle-apis

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 30, 2026

SimulatorService had no post-boot app management surface, forcing callers to shell out to xcrun simctl directly. This adds the five missing lifecycle methods as first-class API.

Xamarin.MacDev/SimulatorService.cs

Five new methods, each validating arguments and logging via ICustomLogger:

Method Returns Wraps
Install(udid, appBundlePath) bool simctl install
Uninstall(udid, bundleIdentifier) bool simctl uninstall
Launch(udid, bundleIdentifier, params extraArgs) bool simctl launch
Terminate(udid, bundleIdentifier) bool simctl terminate
GetAppContainer(udid, bundleIdentifier, containerType?) string? simctl get_app_container

Launch forwards optional extra arguments to the app process. GetAppContainer accepts an optional container-type selector ("app", "data", "groups", etc.) and returns the trimmed path or null on failure.

var svc = new SimulatorService(log);
svc.Install(udid, "/path/to/MyApp.app");
svc.Launch(udid, "com.example.MyApp", "--arg1", "--arg2");
var dataDir = svc.GetAppContainer(udid, "com.example.MyApp", "data");
svc.Terminate(udid, "com.example.MyApp");
svc.Uninstall(udid, "com.example.MyApp");

tests/SimulatorServiceTests.cs

New test file with argument-validation unit tests for all five methods, plus a macOS-gated live test verifying GetAppContainer returns null for a non-existent app.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 0t3vsblobprodcus362.vsblob.vsassets.io
    • Triggering command: /usr/bin/dotnet dotnet build Xamarin.MacDev.sln (dns block)
    • Triggering command: /usr/bin/dotnet dotnet restore --no-dependencies /home/REDACTED/work/macios-devtools/macios-devtools/Xamarin.MacDev.sln --packages /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
  • 2kmvsblobprodcus39.vsblob.vsassets.io
    • Triggering command: /usr/bin/dotnet dotnet restore --no-dependencies /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/EAFBC6E33F4372D62A064209AA87BA2F/missingpackages_workingdir --packages /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
    • Triggering command: /usr/bin/dotnet dotnet restore --no-dependencies /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/46EB19D8E6D150879BD3367A72FC2FBC/missingpackages_workingdir --packages /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • 4myvsblobprodcus32.vsblob.vsassets.io
    • Triggering command: /usr/bin/dotnet dotnet restore --no-dependencies /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/5A662EEFB2568432D6FDBE7CF1D19C8E/missingpackages_workingdir --packages /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • 51yvsblobprodcus36.vsblob.vsassets.io
    • Triggering command: /usr/bin/dotnet dotnet build Xamarin.MacDev.sln (dns block)
    • Triggering command: /usr/bin/dotnet dotnet build Xamarin.MacDev/Xamarin.MacDev.csproj --no-restore (dns block)
    • Triggering command: /usr/bin/dotnet dotnet restore --no-dependencies /home/REDACTED/work/macios-devtools/macios-devtools/Xamarin.MacDev.sln --packages /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
  • 7devsblobprodcus323.vsblob.vsassets.io
    • Triggering command: /usr/bin/dotnet dotnet restore --no-dependencies /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/C31F48A60590A971E376753BAE25D343/missingpackages_workingdir --packages /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • 7k6vsblobprodcus337.vsblob.vsassets.io
    • Triggering command: /usr/bin/dotnet dotnet build Xamarin.MacDev.sln (dns block)
  • jd4vsblobprodcus366.vsblob.vsassets.io
    • Triggering command: /usr/bin/dotnet dotnet restore --no-dependencies /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/5707D9CCD3909344C2384588AB311A3D/missingpackages_workingdir --packages /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • kgfvsblobprodcus314.vsblob.vsassets.io
    • Triggering command: /usr/bin/dotnet dotnet restore --no-dependencies /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/5707D9CCD3909344C2384588AB311A3D/missingpackages_workingdir --packages /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • kmuvsblobprodcus389.vsblob.vsassets.io
    • Triggering command: /usr/bin/dotnet dotnet build Xamarin.MacDev.sln (dns block)
    • Triggering command: /usr/bin/dotnet dotnet restore --no-dependencies /home/REDACTED/work/macios-devtools/macios-devtools/Xamarin.MacDev.sln --packages /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/packages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal /p:TargetFrameworkRootPath=/tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/emptyFakeDotnetRoot /p:NetCoreTargetingPackRoot=/tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/emptyFakeDotnetRoot /p:AllowMissingPrunePackageData=true (dns block)
    • Triggering command: /usr/bin/dotnet dotnet restore --no-dependencies /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/1381A7934071EB35EC16B755076CAB69/missingpackages_workingdir --packages /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • kxqvsblobprodcus376.vsblob.vsassets.io
    • Triggering command: /usr/bin/dotnet dotnet restore --no-dependencies /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/047D30272EE2B8A118836103AA894C89/missingpackages_workingdir --packages /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/missingpackages /p:DisableImplicitNuGetFallbackFolder=true --verbosity normal --configfile /tmp/codeql-scratch-05016c733fb84ab0/dbs/csharp/working/nugetconfig/nuget.config --force (dns block)
  • securitytools.pkgs.visualstudio.com
    • Triggering command: /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/csharp/tools/linux64/Semmle.Autobuild.CSharp /opt/hostedtoolcache/CodeQL/2.25.1/x64/codeql/csharp/tools/linux64/Semmle.Autobuild.CSharp (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

…terminate/get_app_container)

Agent-Logs-Url: https://github.com/dotnet/macios-devtools/sessions/90cfa0ab-cd62-4bbe-b644-991a95ac7a3a

Co-authored-by: rmarinho <1235097+rmarinho@users.noreply.github.com>
Copilot AI changed the title [WIP] Add simulator app lifecycle APIs for MAUI DevTools CLI Add simulator app lifecycle APIs (install/uninstall/launch/terminate/get_app_container) Apr 30, 2026
Copilot AI requested a review from rmarinho April 30, 2026 19:49
@rmarinho rmarinho marked this pull request as ready for review May 4, 2026 17:22
@rmarinho rmarinho requested a review from Copilot May 4, 2026 17:33
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a first-class post-boot app lifecycle surface to Xamarin.MacDev’s SimulatorService, reducing the need for callers to shell out to xcrun simctl directly.

Changes:

  • Added SimulatorService lifecycle methods: Install, Uninstall, Launch, Terminate, and GetAppContainer.
  • Implemented success/failure handling via existing SimCtl.Run(...) behavior and added informational logging on success.
  • Added NUnit tests focused on argument validation plus a macOS-only live test for GetAppContainer’s failure behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
Xamarin.MacDev/SimulatorService.cs Introduces five new simulator app lifecycle APIs wrapping xcrun simctl subcommands.
tests/SimulatorServiceTests.cs Adds validation-focused NUnit coverage for the new APIs plus one macOS-gated live assertion.

Comment on lines +151 to +163
public bool Launch (string udid, string bundleIdentifier, params string [] extraArgs)
{
if (string.IsNullOrEmpty (udid))
throw new ArgumentException ("UDID must not be null or empty.", nameof (udid));
if (string.IsNullOrEmpty (bundleIdentifier))
throw new ArgumentException ("Bundle identifier must not be null or empty.", nameof (bundleIdentifier));

var args = new string [3 + extraArgs.Length];
args [0] = "launch";
args [1] = udid;
args [2] = bundleIdentifier;
Array.Copy (extraArgs, 0, args, 3, extraArgs.Length);


string? output;
if (!string.IsNullOrEmpty (containerType))
output = simctl.Run ("get_app_container", udid, bundleIdentifier, containerType!);
@rmarinho rmarinho merged commit 87eb6ab into main May 5, 2026
11 checks passed
jfversluis pushed a commit to dotnet/maui-labs that referenced this pull request May 6, 2026
…app lifecycle commands (#231)

* bump: Xamarin.Apple.Tools.MaciOS to 1.0.0-preview.1.26255.1

Updates from dotnet/macios-devtools:
- Add PDictionary.OpenFile and TryOpenFile methods (#172)
- Add simulator app lifecycle APIs (install/uninstall/launch/terminate/get_app_container) (#176)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* feat(cli): add simulator app lifecycle commands (install/uninstall/launch/terminate/get-app-container)

Leverages the new SimulatorService APIs from Xamarin.Apple.Tools.MaciOS 1.0.0-preview.1.26255.1
(dotnet/macios-devtools#176).

New commands:
- maui apple simulator install <udid> <app-bundle-path>
- maui apple simulator uninstall <udid> <bundle-identifier>
- maui apple simulator launch <udid> <bundle-identifier> [--args ...]
- maui apple simulator terminate <udid> <bundle-identifier>
- maui apple simulator get-app-container <udid> <bundle-identifier> [--type app|data|groups]

All commands support --json output mode and emit structured error codes (E2209–E2213).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address PR review feedback: fix JSON output, add validation and tests

- Fix moderate issue: install command JSON output now emits 'app_path'
  instead of a misleading 'bundle_identifier' (was just filename)
- Make BundleIdentifier nullable with JsonIgnore when null
- Add .app extension validation before attempting install
- Use InvalidArgument (E1004) for input validation errors vs
  AppleSimulatorInstallFailed (E2209) for platform failures
- Add 18 unit tests covering command registration, fake provider
  tracking, JSON serialization, and error code correctness

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Address review: UDID validation, handler-level tests, smoke tests

- Add SimulatorExists() helper that pre-validates UDID against
  GetSimulators() before calling lifecycle commands (install, uninstall,
  launch, terminate, get-app-container). Returns E2204 early if the
  simulator is not found.
- Add 3 handler-level tests exercising full CLI argument parsing:
  - LaunchCommand_ForwardsArgsToProvider: verifies --args tokens are
    preserved as extraArgs array
  - InstallCommand_InvalidUdid_ReturnsSimulatorNotFound: verifies E2204
    error when UDID doesn't match any simulator
  - UninstallCommand_ValidUdid_CallsProvider: verifies successful path
- Update smoke test script with 3 new tests (8-10) that validate error
  handling for invalid UDIDs on the new lifecycle commands
- Mark AppleSimulatorCommandsTests with [Collection("CLI")] for safe
  Program.Services mutation in handler-level tests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add simulator app lifecycle APIs (install/uninstall/launch/terminate/get_app_container)

4 participants