Skip to content

Commit e1d3646

Browse files
[xabt] dotnet watch support, based on env vars (#10960)
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. * Include $(AdbTarget) in adb reverse command 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. NOTE: we run the test on MonoVM-only for now, until we get: * dotnet/sdk#53501 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 061a89f commit e1d3646

File tree

1 file changed

+1
-1
lines changed

1 file changed

+1
-1
lines changed

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.HotReload.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ See: https://github.com/dotnet/sdk/pull/52581
7676
</PropertyGroup>
7777

7878
<Exec Condition=" '$(_AndroidWebSocketPort)' != '' "
79-
Command="&quot;$(_AdbToolPath)&quot; reverse tcp:$(_AndroidWebSocketPort) tcp:$(_AndroidWebSocketPort)" />
79+
Command="&quot;$(_AdbToolPath)&quot; $(AdbTarget) reverse tcp:$(_AndroidWebSocketPort) tcp:$(_AndroidWebSocketPort)" />
8080

8181
</Target>
8282

0 commit comments

Comments
 (0)