Skip to content

Commit ffaba75

Browse files
authored
[spec] better dotnet run extensibility for .NET MAUI (#51337)
2 parents 0f5c106 + 8b1e787 commit ffaba75

File tree

1 file changed

+222
-0
lines changed

1 file changed

+222
-0
lines changed
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
# `dotnet run` for .NET MAUI Scenarios
2+
3+
The current state of `dotnet run` for .NET MAUI projects is summarized
4+
by this issue from 2021:
5+
6+
* [Figure out 'dotnet run' CLI experience for iOS and Android](https://github.com/dotnet/xamarin/issues/26)
7+
8+
The pain points being:
9+
10+
* iOS and Android use different properties to select a device,
11+
emulator, or simulator. It is difficult for developers to make this
12+
selection as you need to run platform-specific commands along with
13+
complex MSBuild properties.
14+
15+
* Each platform has different behavior, regards to displaying console
16+
output, etc.
17+
18+
* Using an MSIX with WindowsAppSDK doesn't support `dotnet run` at all,
19+
relying completely on IDEs like Visual Studio.
20+
21+
* `dotnet run` does not have a concept of a "deploy" step.
22+
23+
This has become more relevant in the AI era, as someone is going to
24+
expect AIs in "agent mode" to build and run their app. If the
25+
command-line options are difficult, AIs will fail just as badly as
26+
humans do today.
27+
28+
## The `dotnet run` Pipeline
29+
30+
These are the high-level steps during `dotnet run`, that we would like
31+
to make extensible for .NET MAUI (and future) scenarios.
32+
33+
* `restore`: unchanged
34+
35+
* "Pre-run evaluation"
36+
37+
* If the project is multi-targeted, containing the
38+
`$(TargetFrameworks)` property _and_ that property has more than
39+
one item in it, and `-f` was not supplied...
40+
41+
* Prompt the user to select from a list of the
42+
`$(TargetFrameworks)`
43+
44+
* Non-interactive mode will give a friendly error message,
45+
suggesting to supply the `-f` property, listing available target
46+
frameworks in the project.
47+
48+
* Once a `$(TargetFramework)` is selected, either from previous
49+
steps or `-f`...
50+
51+
* If a `ComputeAvailableDevices` MSBuild target is available, provided by
52+
the iOS or Android workload, etc. ...
53+
54+
* Call the MSBuild target, which returns a list of `@(Devices)` items...
55+
56+
```xml
57+
<ItemGroup>
58+
<!-- Android examples -->
59+
<Devices Include="emulator-5554" Description="Pixel 7 - API 35" Type="Emulator" Status="Offline" />
60+
<Devices Include="emulator-5555" Description="Pixel 7 - API 36" Type="Emulator" Status="Online" />
61+
<Devices Include="0A041FDD400327" Description="Pixel 7 Pro" Type="Device" Status="Online" />
62+
<!-- iOS examples -->
63+
<Devices Include="94E71AE5-8040-4DB2-8A9C-6CD24EF4E7DE" Description="iPhone 11 - iOS 18.6" Type="Simulator" Status="Shutdown" />
64+
<Devices Include="FBF5DCE8-EE2B-4215-8118-3A2190DE1AD7" Description="iPhone 14 - iOS 26.0" Type="Simulator" Status="Booted" />
65+
<Devices Include="23261B78-1E31-469C-A46E-1776D386EFD8" Description="My iPhone 13" Type="Device" Status="Unavailable" />
66+
<Devices Include="AF40CC64-2CDB-5F16-9651-86BCDF380881" Description="My iPhone 15" Type="Device" Status="Paired" />
67+
</ItemGroup>
68+
```
69+
70+
_NOTE: each workload can decide which metadata values for `%(Type)`
71+
and `%(Status)` are useful, filtering offline devices, etc. The output
72+
above would be analogous to running `adb devices`, `xcrun simctl list
73+
devices`, or `xcrun devicectl list devices`._
74+
75+
* Continuing on...
76+
77+
* Prompt the user to select from this list of devices, emulators,
78+
or simulators.
79+
80+
* Non-interactive mode will error, suggesting to supply the
81+
`--device` switch. Listing the options returned by the
82+
`ComputeAvailableDevices` MSBuild target.
83+
84+
* `build`: unchanged, but is passed `-p:Device`.
85+
86+
* `deploy`
87+
88+
* If a `DeployToDevice` MSBuild target is available, provided by the
89+
iOS or Android workload, etc.
90+
91+
* Call the MSBuild target, passing in the identifier for the selected
92+
`-p:Device` global MSBuild property.
93+
94+
* This step needs to run, even with `--no-build`, as you may have
95+
selected a different device.
96+
97+
* `ComputeRunArguments`: unchanged, but is passed `-p:Device`.
98+
99+
* `run`: unchanged. `ComputeRunArguments` should have set a valid
100+
`$(RunCommand)` and `$(RunArguments)` using the value supplied by
101+
`-p:Device`.
102+
103+
## New `dotnet run` Command-line Switches
104+
105+
So far, it feels like no new subcommand is needed. In interactive
106+
mode, `dotnet run` will now prompt to select a `$(TargetFramework)`
107+
for all multi-targeted projects. Platform-specific projects like
108+
Android, iOS, etc. will prompt for device selection.
109+
110+
`dotnet run --list-devices` will:
111+
112+
* Prompt for `$(TargetFramework)` for multi-targeted projects just
113+
like when `--list-devices` is omitted.
114+
115+
* If there is a single `$(TargetFramework)`, skip to the next step.
116+
117+
* Call `ComputeAvailableDevices` if the MSBuild target exists, just
118+
like when `--list-devices` is omitted.
119+
120+
* List the available targets by name, a unique identifier, and an
121+
optional status of the device.
122+
123+
* Print a friendly message that says how to run `dotnet run` with
124+
the new `--device` switch.
125+
126+
* If `ComputeAvailableDevices` does not exist in the project
127+
(workload), it can print a friendly message and exit.
128+
129+
* `dotnet run --list-devices` will then basically exit early, never
130+
running any build, deploy, `ComputeRunArguments`, or run steps.
131+
132+
A new `--device` switch will:
133+
134+
* bypass the device-selection portion of the `run` workflow described above
135+
136+
* Pass in the `-p:Device` global MSBuild property to all build,
137+
deploy, `ComputeRunArguments`, or run steps.
138+
139+
* The iOS and Android workloads will know how to interpret `$(Device)`
140+
to select an appropriate device, emulator, or simulator.
141+
142+
## What about Launch Profiles?
143+
144+
The iOS and Android workloads ignore all
145+
`Properties/launchSettings.json` files and do nothing with them.
146+
147+
WindowsAppSDK requires a launch profile to select between "packaged"
148+
MSIX and an "unpackaged" .exe, and so we currently provide this in the
149+
`dotnet new maui` project template:
150+
151+
```json
152+
{
153+
"profiles": {
154+
"Windows Machine": {
155+
"commandName": "Project",
156+
"nativeDebugging": false
157+
}
158+
}
159+
}
160+
```
161+
162+
Or if you want to be "packaged":
163+
164+
```json
165+
{
166+
"profiles": {
167+
"Windows Machine": {
168+
"commandName": "MsixPackage",
169+
"nativeDebugging": false
170+
}
171+
}
172+
}
173+
```
174+
175+
Launch profiles don't immediately look useful for iOS or Android, as
176+
the identifier you'd put in here would be different per developer --
177+
you wouldn't want the value saved in source control. You could put a
178+
generic selection like device vs emulator/simulator, but that isn't
179+
addressing the problem we are interested in. Full launch profile
180+
support for .NET MAUI projects may be interesting to address in the
181+
future.
182+
183+
## iOS and Android workload behavior
184+
185+
We will work to align as much behavior as possible between the
186+
platforms. Most of this work will happen in the dotnet/android and
187+
dotnet/macios repo, and would be orthogonal to the changes in the .NET
188+
SDK.
189+
190+
## macOS and MacCatalyst Behavior
191+
192+
`dotnet run` "just works" on macOS Desktop, because `$(RunCommand)`
193+
can launch the app directly -- similar to console apps.
194+
195+
## WindowsAppSDK Behavior
196+
197+
Running a `dotnet new maui` project works today because of the default
198+
launch profile in "unpackaged" mode:
199+
200+
```dotnetcli
201+
> dotnet run -f net10.0-windows10.0.19041.0
202+
Using launch settings from D:\src\hellomaui\Properties\launchSettings.json...
203+
```
204+
205+
To improve the behavior for "packaged" / MSIX, we could:
206+
207+
* Implement the `DeployToDevice` MSBuild target.
208+
209+
* `ComputeAvailableDevices` is not needed.
210+
211+
* Implement the `ComputeRunArguments` MSBuild target.
212+
213+
In the future, we can either add this logic into the .NET MAUI
214+
workload or WindowsAppSDK itself.
215+
216+
## Other frameworks: Avalonia, Uno, MonoGame, etc.
217+
218+
When these frameworks run on iOS or Android, they are basically using
219+
the `ios` and `android` workloads _without_ .NET MAUI. Any iOS or
220+
Android-specific behavior would apply to these project types in the
221+
same way a `dotnet new android` or `dotnet new ios` project template
222+
would.

0 commit comments

Comments
 (0)