diff --git a/src/Microsoft.Android.Templates/android-bindinglib/.template.config/template.json b/src/Microsoft.Android.Templates/android-bindinglib/.template.config/template.json
index fa0ce3e3110..97403c7632a 100644
--- a/src/Microsoft.Android.Templates/android-bindinglib/.template.config/template.json
+++ b/src/Microsoft.Android.Templates/android-bindinglib/.template.config/template.json
@@ -15,5 +15,14 @@
"primaryOutputs": [
{ "path": "AndroidBinding1.csproj" }
],
+ "symbols": {
+ "supportedOSVersion": {
+ "type": "parameter",
+ "description": "Overrides $(SupportedOSPlatformVersion) in the project",
+ "datatype": "string",
+ "replaces": "SUPPORTED_OS_PLATFORM_VERSION",
+ "defaultValue": "21"
+ }
+ },
"defaultName": "AndroidBinding1"
}
\ No newline at end of file
diff --git a/src/Microsoft.Android.Templates/android-bindinglib/AndroidBinding1.csproj b/src/Microsoft.Android.Templates/android-bindinglib/AndroidBinding1.csproj
index 7cf29802739..5a6a74ace70 100644
--- a/src/Microsoft.Android.Templates/android-bindinglib/AndroidBinding1.csproj
+++ b/src/Microsoft.Android.Templates/android-bindinglib/AndroidBinding1.csproj
@@ -1,6 +1,7 @@
net6.0-android
+ SUPPORTED_OS_PLATFORM_VERSION
AndroidBinding1
\ No newline at end of file
diff --git a/src/Microsoft.Android.Templates/android/.template.config/template.json b/src/Microsoft.Android.Templates/android/.template.config/template.json
index 0945e22e66c..b04d7f07d2d 100644
--- a/src/Microsoft.Android.Templates/android/.template.config/template.json
+++ b/src/Microsoft.Android.Templates/android/.template.config/template.json
@@ -28,6 +28,13 @@
"description": "Overrides the package name in the AndroidManifest.xml",
"datatype": "string",
"replaces": "com.companyname.AndroidApp1"
+ },
+ "supportedOSVersion": {
+ "type": "parameter",
+ "description": "Overrides $(SupportedOSPlatformVersion) in the project",
+ "datatype": "string",
+ "replaces": "SUPPORTED_OS_PLATFORM_VERSION",
+ "defaultValue": "21"
}
},
"defaultName": "AndroidApp1"
diff --git a/src/Microsoft.Android.Templates/android/AndroidApp1.csproj b/src/Microsoft.Android.Templates/android/AndroidApp1.csproj
index a46e175509f..1fd328a5c21 100644
--- a/src/Microsoft.Android.Templates/android/AndroidApp1.csproj
+++ b/src/Microsoft.Android.Templates/android/AndroidApp1.csproj
@@ -1,6 +1,7 @@
net6.0-android
+ SUPPORTED_OS_PLATFORM_VERSION
AndroidApp1
Exe
diff --git a/src/Microsoft.Android.Templates/android/AndroidManifest.xml b/src/Microsoft.Android.Templates/android/AndroidManifest.xml
index 3ce625444d4..c669bdfaa58 100644
--- a/src/Microsoft.Android.Templates/android/AndroidManifest.xml
+++ b/src/Microsoft.Android.Templates/android/AndroidManifest.xml
@@ -3,7 +3,6 @@
android:versionCode="1"
android:versionName="1.0"
package="com.companyname.AndroidApp1">
-
\ No newline at end of file
diff --git a/src/Microsoft.Android.Templates/androidlib/.template.config/template.json b/src/Microsoft.Android.Templates/androidlib/.template.config/template.json
index 53991ab827a..061c49cc1b2 100644
--- a/src/Microsoft.Android.Templates/androidlib/.template.config/template.json
+++ b/src/Microsoft.Android.Templates/androidlib/.template.config/template.json
@@ -15,5 +15,14 @@
"primaryOutputs": [
{ "path": "AndroidLib1.csproj" }
],
+ "symbols": {
+ "supportedOSVersion": {
+ "type": "parameter",
+ "description": "Overrides $(SupportedOSPlatformVersion) in the project",
+ "datatype": "string",
+ "replaces": "SUPPORTED_OS_PLATFORM_VERSION",
+ "defaultValue": "21"
+ }
+ },
"defaultName": "AndroidLib1"
}
\ No newline at end of file
diff --git a/src/Microsoft.Android.Templates/androidlib/AndroidLib1.csproj b/src/Microsoft.Android.Templates/androidlib/AndroidLib1.csproj
index 687d1512882..5eb4df59b23 100644
--- a/src/Microsoft.Android.Templates/androidlib/AndroidLib1.csproj
+++ b/src/Microsoft.Android.Templates/androidlib/AndroidLib1.csproj
@@ -1,6 +1,7 @@
net6.0-android
+ SUPPORTED_OS_PLATFORM_VERSION
AndroidLib1
\ No newline at end of file
diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Designer.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Designer.targets
index 7eee40439d2..4b8f8388493 100644
--- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Designer.targets
+++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Designer.targets
@@ -99,6 +99,7 @@ Copyright (C) 2016 Xamarin. All rights reserved.
FrameworkDirectories="$(_XATargetFrameworkDirectories);$(_XATargetFrameworkDirectories)Facades"
AcwMapFile="$(_AcwMapFile)"
SupportedAbis="$(_BuildTargetAbis)"
+ SupportedOSPlatformVersion="$(SupportedOSPlatformVersion)"
InstantRunEnabled="$(_InstantRunEnabled)">
<_GetChildProjectCopyToPublishDirectoryItems>false
true
+
+ $(SupportedOSPlatformVersion).0
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Aapt.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Aapt.cs
index 045dfc2e2f4..e8b09e8cf33 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/Aapt.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/Aapt.cs
@@ -263,7 +263,7 @@ protected string GenerateCommandLineCommands (string ManifestFile, string curren
Directory.CreateDirectory (manifestDir);
manifestFile = Path.Combine (manifestDir, Path.GetFileName (ManifestFile));
ManifestDocument manifest = new ManifestDocument (ManifestFile);
- manifest.SdkVersion = AndroidSdkPlatform;
+ manifest.TargetSdkVersion = AndroidSdkPlatform;
if (!string.IsNullOrEmpty (VersionCodePattern)) {
try {
manifest.CalculateVersionCode (currentAbi, VersionCodePattern, VersionCodeProperties);
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/Aapt2Link.cs b/src/Xamarin.Android.Build.Tasks/Tasks/Aapt2Link.cs
index 74578f992bc..cf3b0fc3384 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/Aapt2Link.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/Aapt2Link.cs
@@ -139,7 +139,7 @@ string [] GenerateCommandLineCommands (string ManifestFile, string currentAbi, s
Directory.CreateDirectory (manifestDir);
string manifestFile = Path.Combine (manifestDir, Path.GetFileName (ManifestFile));
ManifestDocument manifest = new ManifestDocument (ManifestFile);
- manifest.SdkVersion = AndroidSdkPlatform;
+ manifest.TargetSdkVersion = AndroidSdkPlatform;
if (!string.IsNullOrEmpty (VersionCodePattern)) {
try {
manifest.CalculateVersionCode (currentAbi, VersionCodePattern, VersionCodeProperties);
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
index c6b76468af3..973d180ece8 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
@@ -82,6 +82,8 @@ public class GenerateJavaStubs : AndroidTask
public string CheckedBuild { get; set; }
+ public string SupportedOSPlatformVersion { get; set; }
+
[Output]
public string [] GeneratedBinaryTypeMaps { get; set; }
@@ -259,6 +261,12 @@ void Run (DirectoryAssemblyResolver res)
Log.LogCodedError ("XA4215", Properties.Resources.XA4215_Details, kvp.Key, typeName);
}
+ // NOTE: $(SupportedOSPlatformVersion) will potentially be 21.0
+ string minSdkVersion = null;
+ if (Version.TryParse (SupportedOSPlatformVersion, out var version)) {
+ minSdkVersion = version.Major.ToString ();
+ }
+
// Step 3 - Merge [Activity] and friends into AndroidManifest.xml
var manifest = new ManifestDocument (ManifestTemplate) {
PackageName = PackageName,
@@ -267,7 +275,8 @@ void Run (DirectoryAssemblyResolver res)
Placeholders = ManifestPlaceholders,
Resolver = res,
SdkDir = AndroidSdkDir,
- SdkVersion = AndroidSdkPlatform,
+ TargetSdkVersion = AndroidSdkPlatform,
+ MinSdkVersion = minSdkVersion,
Debug = Debug,
MultiDex = MultiDex,
NeedsInternet = NeedsInternet,
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs
index 3212f882e2a..0fc2e67c499 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs
@@ -1,7 +1,7 @@
using System;
using System.IO;
using System.Linq;
-using System.Reflection;
+using System.Xml.Linq;
using Mono.Cecil;
using NUnit.Framework;
using Xamarin.Android.Tasks;
@@ -448,6 +448,15 @@ public void DotNetBuild (string runtimeIdentifiers, bool isRelease)
}
}
+ // Check AndroidManifest.xml
+ var manifestPath = Path.Combine (intermediateOutputPath, "android", "AndroidManifest.xml");
+ FileAssert.Exists (manifestPath);
+ var manifest = XDocument.Load (manifestPath);
+ XNamespace ns = "http://schemas.android.com/apk/res/android";
+ var uses_sdk = manifest.Root.Element ("uses-sdk");
+ Assert.AreEqual ("21", uses_sdk.Attribute (ns + "minSdkVersion").Value);
+ Assert.AreEqual ("30", uses_sdk.Attribute (ns + "targetSdkVersion").Value);
+
bool expectEmbeddedAssembies = !(CommercialBuildAvailable && !isRelease);
var apkPath = Path.Combine (outputPath, $"{proj.PackageName}.apk");
FileAssert.Exists (apkPath);
@@ -468,6 +477,32 @@ public void DotNetBuild (string runtimeIdentifiers, bool isRelease)
}
}
+ [Test]
+ public void SupportedOSPlatformVersion ([Values (21, 30)] int minSdkVersion)
+ {
+ var proj = new XASdkProject {
+ SupportedOSPlatformVersion = minSdkVersion.ToString (),
+ };
+ // Call AccessibilityTraversalAfter from API level 22
+ // https://developer.android.com/reference/android/view/View#getAccessibilityTraversalAfter()
+ proj.MainActivity = proj.DefaultMainActivity.Replace ("button.Click", "button.AccessibilityTraversalAfter.ToString ();\nbutton.Click");
+
+ var dotnet = CreateDotNetBuilder (proj);
+ Assert.IsTrue (dotnet.Build (), "`dotnet build` should succeed");
+
+ if (minSdkVersion < 22) {
+ StringAssertEx.Contains ("warning CA1416", dotnet.LastBuildOutput, "Should get warning about Android 22 API");
+ } else {
+ dotnet.AssertHasNoWarnings ();
+ }
+
+ var manifestPath = Path.Combine (FullProjectDirectory, proj.IntermediateOutputPath, "android", "AndroidManifest.xml");
+ FileAssert.Exists (manifestPath);
+ var manifest = XDocument.Load (manifestPath);
+ XNamespace ns = "http://schemas.android.com/apk/res/android";
+ Assert.AreEqual (minSdkVersion.ToString (), manifest.Root.Element ("uses-sdk").Attribute (ns + "minSdkVersion").Value);
+ }
+
[Test]
[Category ("SmokeTests")]
public void DotNetBuildXamarinForms ([Values (true, false)] bool useInterpreter)
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownProperties.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownProperties.cs
index 3ac6af77f8a..43c92db5284 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownProperties.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownProperties.cs
@@ -17,6 +17,7 @@ public static class KnownProperties
public const string RuntimeIdentifier = "RuntimeIdentifier";
public const string RuntimeIdentifiers = "RuntimeIdentifiers";
public const string PublishTrimmed = "PublishTrimmed";
+ public const string SupportedOSPlatformVersion = "SupportedOSPlatformVersion";
public const string Deterministic = "Deterministic";
public const string BundleAssemblies = "BundleAssemblies";
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XASdkProject.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XASdkProject.cs
index 38c5b73357a..6882724244f 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XASdkProject.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/XASdkProject.cs
@@ -56,8 +56,7 @@ public XASdkProject (string outputType = "Exe", [CallerMemberName] string packag
{
Sdk = "Microsoft.NET.Sdk";
TargetFramework = "net6.0-android";
-
- TargetSdkVersion = AndroidSdkResolver.GetMaxInstalledPlatform ().ToString ();
+ SupportedOSPlatformVersion = "21";
PackageName = $"com.xamarin.{(packageName ?? ProjectName).ToLower ()}";
JavaPackageName = JavaPackageName ?? PackageName.ToLowerInvariant ();
GlobalPackagesFolder = FileSystemUtils.FindNugetGlobalPackageFolder ();
@@ -89,34 +88,19 @@ public XASdkProject (string outputType = "Exe", [CallerMemberName] string packag
public string AndroidManifest { get; set; } = default_android_manifest;
///
- /// Defaults to AndroidSdkResolver.GetMaxInstalledPlatform ()
- ///
- public string TargetSdkVersion { get; set; }
-
- ///
- /// Defaults to API 19
+ /// Defaults to 21.0
///
- public string MinSdkVersion { get; set; } = "19";
+ public string SupportedOSPlatformVersion {
+ get { return GetProperty (KnownProperties.SupportedOSPlatformVersion); }
+ set { SetProperty (KnownProperties.SupportedOSPlatformVersion, value); }
+ }
public virtual string ProcessManifestTemplate ()
{
- var uses_sdk = new StringBuilder ("");
-
return AndroidManifest
.Replace ("${PROJECT_NAME}", ProjectName)
.Replace ("${PACKAGENAME}", PackageName)
- .Replace ("${USES_SDK}", uses_sdk.ToString ());
+ .Replace ("${USES_SDK}", "");
}
public override string ProcessSourceTemplate (string source)
diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs
index e1baadddd05..a1ec85f5780 100644
--- a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs
+++ b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs
@@ -84,7 +84,8 @@ internal class ManifestDocument
public List Assemblies { get; set; }
public DirectoryAssemblyResolver Resolver { get; set; }
public string SdkDir { get; set; }
- public string SdkVersion { get; set; }
+ public string TargetSdkVersion { get; set; }
+ public string MinSdkVersion { get; set; }
public bool Debug { get; set; }
public bool MultiDex { get; set; }
public bool NeedsInternet { get; set; }
@@ -118,7 +119,7 @@ public string GetMinimumSdk () {
var minAttr = doc.Root.Element ("uses-sdk")?.Attribute (androidNs + "minSdkVersion");
if (minAttr == null) {
int minSdkVersion;
- if (!int.TryParse (SdkVersionName, out minSdkVersion))
+ if (!int.TryParse (MinSdkVersionName, out minSdkVersion))
minSdkVersion = defaultMinSdkVersion;
return Math.Min (minSdkVersion, defaultMinSdkVersion).ToString ();
}
@@ -129,7 +130,7 @@ public string GetTargetSdk ()
{
var targetAttr = doc.Root.Element ("uses-sdk")?.Attribute (androidNs + "targetSdkVersion");
if (targetAttr == null) {
- return SdkVersionName;
+ return TargetSdkVersionName;
}
return targetAttr.Value;
}
@@ -150,9 +151,12 @@ public ManifestDocument (string templateFilename) : base ()
}
}
- string SdkVersionName {
- get { return MonoAndroidHelper.SupportedVersions.GetIdFromApiLevel (SdkVersion); }
- }
+ string TargetSdkVersionName => MonoAndroidHelper.SupportedVersions.GetIdFromApiLevel (TargetSdkVersion);
+
+ string MinSdkVersionName =>
+ string.IsNullOrEmpty (MinSdkVersion) ?
+ TargetSdkVersionName :
+ MonoAndroidHelper.SupportedVersions.GetIdFromApiLevel (MinSdkVersion);
string ToFullyQualifiedName (string typeName)
{
@@ -293,8 +297,8 @@ public IList Merge (TaskLoggingHelper log, TypeDefinitionCache cache, Li
if (!manifest.Elements ("uses-sdk").Any ()) {
manifest.AddFirst (
new XElement ("uses-sdk",
- new XAttribute (androidNs + "minSdkVersion", SdkVersionName),
- new XAttribute (androidNs + "targetSdkVersion", SdkVersionName)));
+ new XAttribute (androidNs + "minSdkVersion", MinSdkVersionName),
+ new XAttribute (androidNs + "targetSdkVersion", TargetSdkVersionName)));
}
// If no minSdkVersion is specified, set it to TargetFrameworkVersion
@@ -302,7 +306,7 @@ public IList Merge (TaskLoggingHelper log, TypeDefinitionCache cache, Li
if (uses.Attribute (androidNs + "minSdkVersion") == null) {
int minSdkVersion;
- if (!int.TryParse (SdkVersionName, out minSdkVersion))
+ if (!int.TryParse (MinSdkVersionName, out minSdkVersion))
minSdkVersion = XABuildConfig.NDKMinimumApiAvailable;
minSdkVersion = Math.Min (minSdkVersion, XABuildConfig.NDKMinimumApiAvailable);
uses.SetAttributeValue (androidNs + "minSdkVersion", minSdkVersion.ToString ());
@@ -313,7 +317,7 @@ public IList Merge (TaskLoggingHelper log, TypeDefinitionCache cache, Li
if (tsv != null)
targetSdkVersion = tsv.Value;
else {
- targetSdkVersion = SdkVersionName;
+ targetSdkVersion = TargetSdkVersionName;
uses.AddBeforeSelf (new XComment ("suppress UsesMinSdkAttributes"));
}
diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
index 5752f8eef53..e7c8c57d736 100644
--- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
+++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
@@ -1449,6 +1449,7 @@ because xbuild doesn't support framework reference assemblies.
FrameworkDirectories="$(_XATargetFrameworkDirectories);$(_XATargetFrameworkDirectories)Facades"
AcwMapFile="$(_AcwMapFile)"
SupportedAbis="@(_BuildTargetAbis)"
+ SupportedOSPlatformVersion="$(SupportedOSPlatformVersion)"
SkipJniAddNativeMethodRegistrationAttributeScan="$(_SkipJniAddNativeMethodRegistrationAttributeScan)"
CheckedBuild="$(_AndroidCheckedBuild)">