Skip to content

Commit 018cbc8

Browse files
[xabt] support @(RuntimeEnvironmentVariable) items (#10770)
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.
1 parent 44c6d8d commit 018cbc8

File tree

5 files changed

+77
-12
lines changed

5 files changed

+77
-12
lines changed

Documentation/docs-mobile/building-apps/build-items.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,3 +581,29 @@ this build action, see
581581
These files are ignored unless the
582582
[`$(EnableProguard)`](/xamarin/android/deploy-test/building-apps/build-properties#enableproguard)
583583
MSBuild property is `True`.
584+
585+
## RuntimeEnvironmentVariable
586+
587+
`@(RuntimeEnvironmentVariable)` items allow environment variables to be
588+
passed to the Android application at runtime via `dotnet run -e`. For example:
589+
590+
```sh
591+
dotnet run -e DOTNET_RUN_FOO=TestValue123 -e DOTNET_RUN_BAR=AnotherValue456
592+
```
593+
594+
These items are automatically populated by the .NET SDK when using
595+
`dotnet run -e NAME=VALUE` and are included in the generated
596+
environment file during the build. Each item's `%(Identity)` is the
597+
variable name and `%(Value)` is the variable value.
598+
599+
```xml
600+
<ItemGroup>
601+
<RuntimeEnvironmentVariable Include="DOTNET_RUN_FOO" Value="TestValue123" />
602+
</ItemGroup>
603+
```
604+
605+
This feature is only available for Android application projects and
606+
requires a .NET SDK that supports the
607+
`RuntimeEnvironmentVariableSupport` project capability.
608+
609+
This build item was introduced in .NET 10.0.300 SDK and .NET 11.

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Docs about @(ProjectCapability):
1717
<ProjectCapability Include="Mobile" />
1818
<ProjectCapability Include="Android" />
1919
<ProjectCapability Include="AndroidApplication" Condition="$(AndroidApplication)" />
20+
<ProjectCapability Include="RuntimeEnvironmentVariableSupport" Condition="$(AndroidApplication)" />
2021
<ProjectCapability Condition="'$(_KeepLaunchProfiles)' != 'true'" Remove="LaunchProfiles" />
2122
</ItemGroup>
2223

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetCLI.cs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -136,20 +136,20 @@ public bool Publish (string target = null, string runtimeIdentifier = null, stri
136136
return Execute (arguments.ToArray ());
137137
}
138138

139-
public bool Run (bool waitForExit = false, string [] parameters = null)
139+
public bool Run (bool waitForExit = false, bool noBuild = true, string [] parameters = null)
140140
{
141141
string binlog = Path.Combine (Path.GetDirectoryName (projectOrSolution), "run.binlog");
142142
var arguments = new List<string> {
143143
"run",
144144
"--project", $"\"{projectOrSolution}\"",
145-
"--no-build",
146-
$"/bl:\"{binlog}\"",
147-
$"/p:WaitForExit={waitForExit.ToString (CultureInfo.InvariantCulture)}"
148145
};
146+
if (noBuild) {
147+
arguments.Add ("--no-build");
148+
}
149+
arguments.Add ($"/bl:\"{binlog}\"");
150+
arguments.Add ($"/p:WaitForExit={waitForExit.ToString (CultureInfo.InvariantCulture)}");
149151
if (parameters != null) {
150-
foreach (var parameter in parameters) {
151-
arguments.Add ($"/p:{parameter}");
152-
}
152+
arguments.AddRange (parameters);
153153
}
154154
return Execute (arguments.ToArray ());
155155
}
@@ -158,7 +158,7 @@ public bool Run (bool waitForExit = false, string [] parameters = null)
158158
/// Starts `dotnet run` and returns a running Process that can be monitored and killed.
159159
/// </summary>
160160
/// <param name="waitForExit">Whether to use Microsoft.Android.Run tool which waits for app exit and streams logcat.</param>
161-
/// <param name="parameters">Optional MSBuild properties to pass (e.g., "Device=emulator-5554").</param>
161+
/// <param name="parameters">Additional arguments to pass to `dotnet run`.</param>
162162
/// <returns>A running Process instance. Caller is responsible for disposing.</returns>
163163
public Process StartRun (bool waitForExit = true, string [] parameters = null)
164164
{
@@ -171,9 +171,7 @@ public Process StartRun (bool waitForExit = true, string [] parameters = null)
171171
$"/p:WaitForExit={waitForExit.ToString (CultureInfo.InvariantCulture)}"
172172
};
173173
if (parameters != null) {
174-
foreach (var parameter in parameters) {
175-
arguments.Add ($"/p:{parameter}");
176-
}
174+
arguments.AddRange (parameters);
177175
}
178176

179177
return ExecuteProcess (arguments.ToArray ());

src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,6 +1591,8 @@ because xbuild doesn't support framework reference assemblies.
15911591
<_GeneratedAndroidEnvironment Include="mono.enable_assembly_preload=0" Condition=" '$(AndroidEnablePreloadAssemblies)' != 'True' " />
15921592
<_GeneratedAndroidEnvironment Include="DOTNET_MODIFIABLE_ASSEMBLIES=Debug" Condition=" '$(AndroidIncludeDebugSymbols)' == 'true' and '$(AndroidUseInterpreter)' == 'true' " />
15931593
<_GeneratedAndroidEnvironment Include="DOTNET_DiagnosticPorts=$(DiagnosticConfiguration)" Condition=" '$(DiagnosticConfiguration)' != '' " />
1594+
<!-- RuntimeEnvironmentVariable items come from 'dotnet run -e NAME=VALUE' -->
1595+
<_GeneratedAndroidEnvironment Include="@(RuntimeEnvironmentVariable->'%(Identity)=%(Value)')" />
15941596
</ItemGroup>
15951597
<WriteLinesToFile
15961598
File="$(IntermediateOutputPath)__environment__.txt"

tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ public void DotNetRunWithDeviceParameter ()
149149
var serial = GetAttachedDeviceSerial ();
150150

151151
// Start dotnet run with Device parameter, which should set $(AdbTarget)
152-
using var process = dotnet.StartRun (waitForExit: true, parameters: [$"Device={serial}"]);
152+
using var process = dotnet.StartRun (waitForExit: true, parameters: [$"/p:Device={serial}"]);
153153

154154
var locker = new Lock ();
155155
var output = new StringBuilder ();
@@ -1456,6 +1456,44 @@ public void FastDeployEnvironmentFiles (bool isRelease, bool embedAssembliesInto
14561456
}
14571457
}
14581458

1459+
[Test]
1460+
public void DotNetRunEnvironmentVariables ()
1461+
{
1462+
var proj = new XamarinAndroidApplicationProject {
1463+
ProjectName = nameof (DotNetRunEnvironmentVariables),
1464+
RootNamespace = nameof (DotNetRunEnvironmentVariables),
1465+
IsRelease = false,
1466+
EnableDefaultItems = true,
1467+
};
1468+
proj.MainActivity = proj.DefaultMainActivity.Replace ("//${AFTER_ONCREATE}", @"
1469+
Console.WriteLine (""DOTNET_RUN_FOO="" + Environment.GetEnvironmentVariable(""DOTNET_RUN_FOO""));
1470+
Console.WriteLine (""DOTNET_RUN_BAR="" + Environment.GetEnvironmentVariable(""DOTNET_RUN_BAR""));
1471+
");
1472+
using var builder = CreateApkBuilder ();
1473+
builder.Save (proj);
1474+
1475+
var dotnet = new DotNetCLI (Path.Combine (Root, builder.ProjectDirectory, proj.ProjectFilePath));
1476+
Assert.IsTrue (dotnet.Run (noBuild: false, parameters: new [] { "-e", "DOTNET_RUN_FOO=TestValue123", "-e", "DOTNET_RUN_BAR=AnotherValue456" }), "`dotnet run` should succeed");
1477+
1478+
WaitForPermissionActivity (Path.Combine (Root, builder.ProjectDirectory, "permission-logcat.log"));
1479+
bool didLaunch = WaitForActivityToStart (proj.PackageName, "MainActivity",
1480+
Path.Combine (Root, builder.ProjectDirectory, "logcat.log"), 30);
1481+
Assert.IsTrue (didLaunch, "Activity should have started.");
1482+
var appStartupLogcatFile = Path.Combine (Root, builder.ProjectDirectory, "logcat.log");
1483+
var logcatOutput = File.ReadAllText (appStartupLogcatFile);
1484+
1485+
StringAssert.Contains (
1486+
"DOTNET_RUN_FOO=TestValue123",
1487+
logcatOutput,
1488+
"The Environment variable \"DOTNET_RUN_FOO\" was not set to expected value \"TestValue123\"."
1489+
);
1490+
StringAssert.Contains (
1491+
"DOTNET_RUN_BAR=AnotherValue456",
1492+
logcatOutput,
1493+
"The Environment variable \"DOTNET_RUN_BAR\" was not set to expected value \"AnotherValue456\"."
1494+
);
1495+
}
1496+
14591497
[Test]
14601498
public void FixLegacyResourceDesignerStep ([Values (true, false)] bool isRelease)
14611499
{

0 commit comments

Comments
 (0)