Backport dotnet-watch changes to main/.NET 11#10960
Open
jonathanpeppers wants to merge 5 commits intomainfrom
Open
Backport dotnet-watch changes to main/.NET 11#10960jonathanpeppers wants to merge 5 commits intomainfrom
dotnet-watch changes to main/.NET 11#10960jonathanpeppers wants to merge 5 commits intomainfrom
Conversation
Context: dotnet/sdk@bd5d3af `dotnet run` now passes in `dotnet run -e FOO=BAR` as `@(RuntimeEnvironmentVariable)` MSBuild items. To opt in to this new feature, we need to add: <ProjectCapability Include="RuntimeEnvironmentVariableSupport" /> As well as update the `_GenerateEnvironmentFiles` MSBuild target: <!-- RuntimeEnvironmentVariable items come from 'dotnet run -e NAME=VALUE' --> <_GeneratedAndroidEnvironment Include="@(RuntimeEnvironmentVariable->'%(Identity)=%(Value)')" /> I added a new test to verify we have the env vars on-device at runtime. Note that I tested this in combination with a local .NET SDK build: * #10769 We won't be able to merge this until we have a .NET SDK here that includes the above commit. Merging with nightly .NET 10.0.3xx SDK.
Context: dotnet/sdk#52492 Context: dotnet/sdk#52581 `dotnet-watch` now runs Android applications via: dotnet watch 🚀 [helloandroid (net10.0-android)] Launched 'D:\src\xamarin-android\bin\Debug\dotnet\dotnet.exe' with arguments 'run --no-build -e DOTNET_WATCH=1 -e DOTNET_WATCH_ITERATION=1 -e DOTNET_MODIFIABLE_ASSEMBLIES=debug -e DOTNET_WATCH_HOTRELOAD_WEBSOCKET_ENDPOINT=ws://localhost:9000 -e DOTNET_STARTUP_HOOKS=D:\src\xamarin-android\bin\Debug\dotnet\sdk\10.0.300-dev\DotnetTools\dotnet-watch\10.0.300-dev\tools\net10.0\any\hotreload\net10.0\Microsoft.Extensions.DotNetDeltaApplier.dll -bl': process id 3356 And so the pieces on Android for this to work are: ~~ Startup Hook Assembly ~~ Parse out the value: <_AndroidHotReloadAgentAssemblyPath>@(RuntimeEnvironmentVariable->WithMetadataValue('Identity', 'DOTNET_STARTUP_HOOKS')->'%(Value)'->Exists())</_AndroidHotReloadAgentAssemblyPath> And verify this assembly is included in the app: <ResolvedFileToPublish Include="$(_AndroidHotReloadAgentAssemblyPath)" /> Then, for Android, we need to patch up `$DOTNET_STARTUP_HOOKS` to be just the assembly name, not the full path: <_AndroidHotReloadAgentAssemblyName>$([System.IO.Path]::GetFileNameWithoutExtension('$(_AndroidHotReloadAgentAssemblyPath)'))</_AndroidHotReloadAgentAssemblyName> ... <RuntimeEnvironmentVariable Include="DOTNET_STARTUP_HOOKS" Value="$(_AndroidHotReloadAgentAssemblyName)" /> ~~ Port Forwarding ~~ A new `_AndroidConfigureAdbReverse` target runs after deploying apps, that does: adb reverse tcp:9000 tcp:9000 I parsed the value out of: <_AndroidWebSocketEndpoint>@(RuntimeEnvironmentVariable->WithMetadataValue('Identity', 'DOTNET_WATCH_HOTRELOAD_WEBSOCKET_ENDPOINT')->'%(Value)')</_AndroidWebSocketEndpoint> <_AndroidWebSocketPort>$([System.Text.RegularExpressions.Regex]::Match('$(_AndroidWebSocketEndpoint)', ':(\d+)').Groups[1].Value)</_AndroidWebSocketPort> ~~ Prevent Startup Hooks in Microsoft.Android.Run ~~ When I was implementing this, I keep seeing *two* clients connect to `dotnet-watch` and I was pulling my hair to figure out why! Then I realized that `Microsoft.Android.Run` was also getting `$DOTNET_STARTUP_HOOKS`, and so we had a desktop process + mobile process both trying to connect! Easiest fix, is to disable startup hook support in `Microsoft.Android.Run`. I reviewed the code in `dotnet run`, and it doesn't seem correct to try to clear the env vars. ~~ Conclusion ~~ With these changes, everything is working! dotnet watch 🔥 C# and Razor changes applied in 23ms.
Contributor
There was a problem hiding this comment.
Pull request overview
Backport of .NET SDK dotnet run -e / dotnet watch behaviors into .NET for Android (.NET 11) by flowing @(RuntimeEnvironmentVariable) into the Android environment file, adding Hot Reload wiring (startup hook deployment + adb reverse), and extending device tests to validate the scenarios end-to-end.
Changes:
- Add
@(RuntimeEnvironmentVariable)support sodotnet run -e NAME=VALUEis written into the app’s generated environment file. - Add
dotnet watchHot Reload support by deploying the startup hook assembly, rewritingDOTNET_STARTUP_HOOKSfor Android, and configuringadb reversebased on the websocket endpoint env var. - Add/extend device integration tests and test infrastructure (
DotNetCLI,ProjectBuilder) to exercisedotnet run -eanddotnet watchhot reload.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs | Adds device tests for dotnet watch hot reload and dotnet run -e environment variable propagation; adjusts run property passing. |
| src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets | Writes @(RuntimeEnvironmentVariable) into __environment__.txt and ensures Hot Reload env adjustments happen first. |
| src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/ProjectBuilder.cs | Exposes BuiltBefore to support external build flows like dotnet watch while still using ProjectTools file update infrastructure. |
| src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetCLI.cs | Adds StartWatch() and changes Run/StartRun parameter handling to allow passing non-MSBuild args (e.g. -e). |
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ProjectCapabilities.targets | Advertises new project capabilities needed by the .NET SDK (RuntimeEnvironmentVariableSupport, HotReloadWebSockets). |
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.HotReload.targets | New targets to rewrite startup hook env var, deploy the delta applier assembly, and set up adb reverse. |
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.BuildOrder.targets | Hooks Hot Reload port forwarding and environment file generation into install/deploy target ordering. |
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets | Ensures Hot Reload startup hook assembly is included in files to publish/deploy. |
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Application.targets | Refactors _AdbToolPath computation into _AndroidAdbToolPath target for reuse. |
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.After.targets | Imports the new Hot Reload targets for Android application projects. |
| src/Microsoft.Android.Run/Microsoft.Android.Run.csproj | Disables startup hook support to avoid host-side startup hooks interfering with device Hot Reload. |
| Documentation/docs-mobile/building-apps/build-items.md | Documents @(RuntimeEnvironmentVariable) usage and the dotnet run -e integration. |
| .github/copilot-instructions.md | Documents test best-practice for modifying project files via ProjectTools (Touch + Save). |
Comment on lines
+78
to
+79
| <Exec Condition=" '$(_AndroidWebSocketPort)' != '' " | ||
| Command=""$(_AdbToolPath)" reverse tcp:$(_AndroidWebSocketPort) tcp:$(_AndroidWebSocketPort)" /> |
When multiple devices/emulators are connected, the adb reverse command needs (e.g. -s emulator-5554) to target the correct device. Without it, the command fails with 'more than one device' or forwards on the wrong device. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backport of:
@(RuntimeEnvironmentVariable)items #10770dotnet watchsupport, based on env vars #10778