Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Documentation/docs-mobile/building-apps/build-items.md
Original file line number Diff line number Diff line change
Expand Up @@ -567,3 +567,29 @@ this build action, see
These files are ignored unless the
[`$(EnableProguard)`](/xamarin/android/deploy-test/building-apps/build-properties#enableproguard)
MSBuild property is `True`.

## RuntimeEnvironmentVariable

`@(RuntimeEnvironmentVariable)` items allow environment variables to be
passed to the Android application at runtime via `dotnet run -e`. For example:

```sh
dotnet run -e DOTNET_RUN_FOO=TestValue123 -e DOTNET_RUN_BAR=AnotherValue456
```

These items are automatically populated by the .NET SDK when using
`dotnet run -e NAME=VALUE` and are included in the generated
environment file during the build. Each item's `%(Identity)` is the
variable name and `%(Value)` is the variable value.

```xml
<ItemGroup>
<RuntimeEnvironmentVariable Include="DOTNET_RUN_FOO" Value="TestValue123" />
</ItemGroup>
```

This feature is only available for Android application projects and
requires a .NET SDK that supports the
`RuntimeEnvironmentVariableSupport` project capability.

This build item was introduced in .NET 10.0.300 SDK and .NET 11.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Docs about @(ProjectCapability):
<ProjectCapability Include="Mobile" />
<ProjectCapability Include="Android" />
<ProjectCapability Include="AndroidApplication" Condition="$(AndroidApplication)" />
<ProjectCapability Include="RuntimeEnvironmentVariableSupport" Condition="$(AndroidApplication)" />
<ProjectCapability Condition="'$(_KeepLaunchProfiles)' != 'true'" Remove="LaunchProfiles" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,20 +131,20 @@ public bool Publish (string target = null, string runtimeIdentifier = null, stri
return Execute (arguments.ToArray ());
}

public bool Run (bool waitForExit = false, string [] parameters = null)
public bool Run (bool waitForExit = false, bool noBuild = true, string [] parameters = null)
{
string binlog = Path.Combine (Path.GetDirectoryName (projectOrSolution), "run.binlog");
var arguments = new List<string> {
"run",
"--project", $"\"{projectOrSolution}\"",
"--no-build",
$"/bl:\"{binlog}\"",
$"/p:WaitForExit={waitForExit.ToString (CultureInfo.InvariantCulture)}"
};
if (noBuild) {
arguments.Add ("--no-build");
}
arguments.Add ($"/bl:\"{binlog}\"");
arguments.Add ($"/p:WaitForExit={waitForExit.ToString (CultureInfo.InvariantCulture)}");
if (parameters != null) {
foreach (var parameter in parameters) {
arguments.Add ($"/p:{parameter}");
}
arguments.AddRange (parameters);
}
return Execute (arguments.ToArray ());
}
Expand All @@ -153,7 +153,7 @@ public bool Run (bool waitForExit = false, string [] parameters = null)
/// Starts `dotnet run` and returns a running Process that can be monitored and killed.
/// </summary>
/// <param name="waitForExit">Whether to use Microsoft.Android.Run tool which waits for app exit and streams logcat.</param>
/// <param name="parameters">Optional MSBuild properties to pass (e.g., "Device=emulator-5554").</param>
/// <param name="parameters">Additional arguments to pass to `dotnet run`.</param>
/// <returns>A running Process instance. Caller is responsible for disposing.</returns>
public Process StartRun (bool waitForExit = true, string [] parameters = null)
{
Expand All @@ -166,9 +166,7 @@ public Process StartRun (bool waitForExit = true, string [] parameters = null)
$"/p:WaitForExit={waitForExit.ToString (CultureInfo.InvariantCulture)}"
};
if (parameters != null) {
foreach (var parameter in parameters) {
arguments.Add ($"/p:{parameter}");
}
arguments.AddRange (parameters);
}

return ExecuteProcess (arguments.ToArray ());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1778,6 +1778,8 @@ because xbuild doesn't support framework reference assemblies.
<_GeneratedAndroidEnvironment Include="mono.enable_assembly_preload=0" Condition=" '$(AndroidEnablePreloadAssemblies)' != 'True' " />
<_GeneratedAndroidEnvironment Include="DOTNET_MODIFIABLE_ASSEMBLIES=Debug" Condition=" '$(AndroidIncludeDebugSymbols)' == 'true' and '$(AndroidUseInterpreter)' == 'true' " />
<_GeneratedAndroidEnvironment Include="DOTNET_DiagnosticPorts=$(DiagnosticConfiguration)" Condition=" '$(DiagnosticConfiguration)' != '' " />
<!-- RuntimeEnvironmentVariable items come from 'dotnet run -e NAME=VALUE' -->
<_GeneratedAndroidEnvironment Include="@(RuntimeEnvironmentVariable->'%(Identity)=%(Value)')" />
</ItemGroup>
<WriteLinesToFile
File="$(IntermediateOutputPath)__environment__.txt"
Expand Down
40 changes: 39 additions & 1 deletion tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ public void DotNetRunWithDeviceParameter ()
var serial = GetAttachedDeviceSerial ();

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

var locker = new Lock ();
var output = new StringBuilder ();
Expand Down Expand Up @@ -1352,6 +1352,44 @@ public void FastDeployEnvironmentFiles (bool isRelease, bool embedAssembliesInto
}
}

[Test]
public void DotNetRunEnvironmentVariables ()
{
var proj = new XamarinAndroidApplicationProject {
ProjectName = nameof (DotNetRunEnvironmentVariables),
RootNamespace = nameof (DotNetRunEnvironmentVariables),
IsRelease = false,
EnableDefaultItems = true,
};
proj.MainActivity = proj.DefaultMainActivity.Replace ("//${AFTER_ONCREATE}", @"
Console.WriteLine (""DOTNET_RUN_FOO="" + Environment.GetEnvironmentVariable(""DOTNET_RUN_FOO""));
Console.WriteLine (""DOTNET_RUN_BAR="" + Environment.GetEnvironmentVariable(""DOTNET_RUN_BAR""));
");
using var builder = CreateApkBuilder ();
builder.Save (proj);

var dotnet = new DotNetCLI (Path.Combine (Root, builder.ProjectDirectory, proj.ProjectFilePath));
Assert.IsTrue (dotnet.Run (noBuild: false, parameters: new [] { "-e", "DOTNET_RUN_FOO=TestValue123", "-e", "DOTNET_RUN_BAR=AnotherValue456" }), "`dotnet run` should succeed");

WaitForPermissionActivity (Path.Combine (Root, builder.ProjectDirectory, "permission-logcat.log"));
bool didLaunch = WaitForActivityToStart (proj.PackageName, "MainActivity",
Path.Combine (Root, builder.ProjectDirectory, "logcat.log"), 30);
Assert.IsTrue (didLaunch, "Activity should have started.");
var appStartupLogcatFile = Path.Combine (Root, builder.ProjectDirectory, "logcat.log");
var logcatOutput = File.ReadAllText (appStartupLogcatFile);

StringAssert.Contains (
"DOTNET_RUN_FOO=TestValue123",
logcatOutput,
"The Environment variable \"DOTNET_RUN_FOO\" was not set to expected value \"TestValue123\"."
);
StringAssert.Contains (
"DOTNET_RUN_BAR=AnotherValue456",
logcatOutput,
"The Environment variable \"DOTNET_RUN_BAR\" was not set to expected value \"AnotherValue456\"."
);
}

[Test]
public void FixLegacyResourceDesignerStep ([Values (true, false)] bool isRelease)
{
Expand Down