From c6f2fad5c413f1ee01d70ba194e5e4d229951f61 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Mon, 6 Mar 2023 11:04:20 +0000 Subject: [PATCH 1/2] Initial Commit --- .../Tasks/GenerateJavaStubs.cs | 3 +++ .../Tasks/GetImportedLibraries.cs | 27 ++++++++++++++----- .../Tasks/ReadImportedLibrariesCache.cs | 26 ++++++++++-------- .../ManifestTest.cs | 27 +++++++++++++++++++ .../Android/KnownPackages.cs | 10 +++++++ .../Utilities/ManifestDocument.cs | 16 ++++++++--- .../Xamarin.Android.Common.targets | 1 + .../Xamarin.Android.EmbeddedResource.targets | 1 + 8 files changed, 90 insertions(+), 21 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs index e1c36a308d8..0742c5c4543 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs @@ -90,6 +90,8 @@ public class GenerateJavaStubs : AndroidTask public string SupportedOSPlatformVersion { get; set; } + public string LibraryMinSdk { get; set; } = string.Empty; + public ITaskItem[] Environments { get; set; } [Output] @@ -345,6 +347,7 @@ void Run (DirectoryAssemblyResolver res, bool useMarshalMethods) SdkDir = AndroidSdkDir, TargetSdkVersion = AndroidSdkPlatform, MinSdkVersion = minSdkVersion, + LibraryMinSdkVersion = LibraryMinSdk, Debug = Debug, MultiDex = MultiDex, NeedsInternet = NeedsInternet, diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GetImportedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GetImportedLibraries.cs index e3b3bd46861..285497c278d 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GetImportedLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GetImportedLibraries.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Xml; using System.Xml.Linq; using Microsoft.Build.Utilities; using Microsoft.Build.Framework; @@ -22,7 +23,7 @@ public class GetImportedLibraries : AndroidTask [Required] public string TargetDirectory { get; set; } - public string CacheFile { get; set;} + public string CacheFile { get; set;} [Output] public ITaskItem [] Jars { get; set; } @@ -33,6 +34,9 @@ public class GetImportedLibraries : AndroidTask [Output] public ITaskItem [] ManifestDocuments { get; set; } + [Output] + public string LibraryMinSdk { get; set; } = string.Empty; + public override bool RunTask () { if (!Directory.Exists (TargetDirectory)) { @@ -43,6 +47,7 @@ public override bool RunTask () var manifestDocuments = new List (); var nativeLibraries = new List (); var jarFiles = new List (); + int libraryMinSdk = -1; foreach (var file in Directory.EnumerateFiles (TargetDirectory, "*", SearchOption.AllDirectories)) { if (file.EndsWith (".so", StringComparison.OrdinalIgnoreCase)) { if (AndroidRidAbiHelper.GetNativeLibraryAbi (file) != null) @@ -55,11 +60,23 @@ public override bool RunTask () var directory = Path.GetFileName (Path.GetDirectoryName (file)); if (IgnoredManifestDirectories.Contains (directory)) continue; - manifestDocuments.Add (new TaskItem (file)); + var item = new TaskItem (file); + XDocument doc = XDocument.Load (file); + var minAttr = doc.Root.Element ("uses-sdk")?.Attribute (ManifestDocument.AndroidXmlNamespace + "minSdkVersion"); + if (minAttr != null) { + if (int.TryParse (minAttr.Value, out int minSDK)) + libraryMinSdk = Math.Max (libraryMinSdk, minSDK); + } + manifestDocuments.Add (item); } } } + XAttribute minSdk = null; + if (libraryMinSdk != -1) { + LibraryMinSdk = libraryMinSdk.ToString (); + minSdk = new XAttribute ("libraryMinSdk", LibraryMinSdk); + } ManifestDocuments = manifestDocuments.ToArray (); NativeLibraries = nativeLibraries.ToArray (); Jars = jarFiles.ToArray (); @@ -68,17 +85,13 @@ public override bool RunTask () var document = new XDocument ( new XDeclaration ("1.0", "UTF-8", null), new XElement ("Paths", - new XElement ("ManifestDocuments", ManifestDocuments.Select(e => new XElement ("ManifestDocument", e.ItemSpec))), + new XElement ("ManifestDocuments", minSdk, ManifestDocuments.Select(e => new XElement ("ManifestDocument", e.ItemSpec))), new XElement ("NativeLibraries", NativeLibraries.Select(e => new XElement ("NativeLibrary", e.ItemSpec))), new XElement ("Jars", Jars.Select(e => new XElement ("Jar", e.ItemSpec))) )); document.SaveIfChanged (CacheFile); } - Log.LogDebugTaskItems (" NativeLibraries: ", NativeLibraries); - Log.LogDebugTaskItems (" Jars: ", Jars); - Log.LogDebugTaskItems (" ManifestDocuments: ", ManifestDocuments); - return true; } } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/ReadImportedLibrariesCache.cs b/src/Xamarin.Android.Build.Tasks/Tasks/ReadImportedLibrariesCache.cs index d138c2c9593..f01eaca75f8 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/ReadImportedLibrariesCache.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/ReadImportedLibrariesCache.cs @@ -1,21 +1,21 @@ -// +// // ReadImportedLibrariesCache.cs -// +// // Author: // Dean Ellis -// +// // Copyright (c) 2013 Xamarin Inc. -// +// // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: -// +// // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. -// +// // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -39,7 +39,7 @@ public class ReadImportedLibrariesCache : AndroidTask public override string TaskPrefix => "RIL"; [Required] - public string CacheFile { get; set;} + public string CacheFile { get; set;} [Output] public ITaskItem [] Jars { get; set; } @@ -50,6 +50,9 @@ public class ReadImportedLibrariesCache : AndroidTask [Output] public ITaskItem [] ManifestDocuments { get; set; } + [Output] + public string LibraryMinSdk { get; set; } + public override bool RunTask () { if (!File.Exists (CacheFile)) { @@ -60,10 +63,11 @@ public override bool RunTask () Jars = doc.GetPathsAsTaskItems ("Jars", "Jar"); NativeLibraries = doc.GetPathsAsTaskItems ("NativeLibraries", "NativeLibrary"); ManifestDocuments = doc.GetPathsAsTaskItems ("ManifestDocuments", "ManifestDocument"); - - Log.LogDebugTaskItems (" NativeLibraries: ", NativeLibraries); - Log.LogDebugTaskItems (" Jars: ", Jars); - Log.LogDebugTaskItems (" ManifestDocuments: ", ManifestDocuments); + var minSdk = doc.Element ("Paths")?.Element ("ManifestDocuments")?.Attribute ("libraryMinSdk"); + LibraryMinSdk = string.Empty; + if (minSdk != null) + if (int.TryParse (minSdk.Value, out int minSDK)) + LibraryMinSdk = minSdk.Value; return !Log.HasLoggedErrors; } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs index 4559fada920..d3a472f70fa 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs @@ -685,6 +685,33 @@ public void ModifyManifest ([Values (true, false)] bool isRelease) } } + [Test] + public void EmptyUsesSdkElementBuildsOK ([Values (false, true)] bool addReference) + { + var proj = new XamarinAndroidApplicationProject () { + IsRelease = true, + }; + if (addReference) + proj.PackageReferences.Add (KnownPackages.AndroidXSecurityCrypto); + proj.AndroidManifest = @" + + + + +"; + using (var b = CreateApkBuilder ($"temp/{TestName}", cleanupAfterSuccessfulBuild: true, cleanupOnDispose: false)) { + Assert.IsTrue (b.Build (proj), "Build should have succeeded."); + var manifestFile = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "AndroidManifest.xml"); + var doc = XDocument.Load (manifestFile); + var ns = XNamespace.Get ("http://schemas.android.com/apk/res/android"); + var usesSdk = doc.Element ("manifest")?.Element ("uses-sdk"); + Assert.IsNotNull (usesSdk, "Should have found a uses-sdk element."); + var expected = addReference ? "23" : "19"; + Assert.AreEqual (expected, usesSdk.Attribute ("minSdkVersion")?.Value, $"minSdkVersion should have been '{expected}' but was '{usesSdk.Attribute ("minSdkVersion")?.Value}'"); + + } + } + [Test] public void MergeLibraryManifest () { diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs index 007ff8d4172..07954695152 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs @@ -328,6 +328,16 @@ public static class KnownPackages } } }; + public static Package AndroidXSecurityCrypto = new Package { + Id = "Xamarin.AndroidX.Security.SecurityCrypto", + Version = "1.0.0.9", + TargetFramework = "MonoAndroid90", + References = { + new BuildItem.Reference("Xamarin.AndroidX.Security.SecurityCrypto") { + MetadataValues = "HintPath=..\\packages\\Xamarin.AndroidX.Security.SecurityCrypto.1.0.0.9\\lib\\MonoAndroid90\\Xamarin.AndroidX.Security.SecurityCrypto.dll" + } + } + }; public static Package XamarinGoogleAndroidMaterial = new Package { Id = "Xamarin.Google.Android.Material", Version = "1.0.0.1", diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs index 3f648c5cfcb..af52b3bc896 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs @@ -87,6 +87,7 @@ internal class ManifestDocument public string SdkDir { get; set; } public string TargetSdkVersion { get; set; } public string MinSdkVersion { get; set; } + public string LibraryMinSdkVersion { get; set; } = string.Empty; public bool Debug { get; set; } public bool MultiDex { get; set; } public bool NeedsInternet { get; set; } @@ -119,13 +120,17 @@ public string VersionCode { public string GetMinimumSdk () { int defaultMinSdkVersion = MonoAndroidHelper.SupportedVersions.MinStableVersion.ApiLevel; + Console.WriteLine ($"DEBUG GetMinimumSdk: {defaultMinSdkVersion}"); var minAttr = doc.Root.Element ("uses-sdk")?.Attribute (androidNs + "minSdkVersion"); if (minAttr == null) { int minSdkVersion; + Console.WriteLine ($"DEBUG GetMinimumSdk: Parsing {MinSdkVersionName}"); if (!int.TryParse (MinSdkVersionName, out minSdkVersion)) minSdkVersion = defaultMinSdkVersion; + Console.WriteLine ($"DEBUG GetMinimumSdk: Using {Math.Min (minSdkVersion, defaultMinSdkVersion)}"); return Math.Min (minSdkVersion, defaultMinSdkVersion).ToString (); } + Console.WriteLine ($"DEBUG GetMinimumSdk: Found {minAttr.Value}"); return minAttr.Value; } @@ -309,10 +314,15 @@ public IList Merge (TaskLoggingHelper log, TypeDefinitionCache cache, Li if (uses.Attribute (androidNs + "minSdkVersion") == null) { int minSdkVersion; - if (!int.TryParse (MinSdkVersionName, out minSdkVersion)) + if (!int.TryParse (MinSdkVersionName, out minSdkVersion)) { minSdkVersion = XABuildConfig.NDKMinimumApiAvailable; - minSdkVersion = Math.Min (minSdkVersion, XABuildConfig.NDKMinimumApiAvailable); - uses.SetAttributeValue (androidNs + "minSdkVersion", minSdkVersion.ToString ()); + } + if (!string.IsNullOrEmpty (LibraryMinSdkVersion) && int.TryParse (LibraryMinSdkVersion, out minSdkVersion)) { + uses.SetAttributeValue (androidNs + "minSdkVersion", minSdkVersion.ToString ()); + } else { + minSdkVersion = Math.Min (minSdkVersion, XABuildConfig.NDKMinimumApiAvailable); + uses.SetAttributeValue (androidNs + "minSdkVersion", minSdkVersion.ToString ()); + } } string targetSdkVersion; diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 9c5fedf7980..fa1c3469b5e 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1545,6 +1545,7 @@ because xbuild doesn't support framework reference assemblies. LinkingEnabled="$(_LinkingEnabled)" HaveMultipleRIDs="$(_HaveMultipleRIDs)" IntermediateOutputDirectory="$(IntermediateOutputPath)" + LibraryMinSdk="$(_LibraryMinSdk)" Environments="@(AndroidEnvironment);@(LibraryEnvironments)"> diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.EmbeddedResource.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.EmbeddedResource.targets index 1b629e13c06..92a3511fdaf 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.EmbeddedResource.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.EmbeddedResource.targets @@ -102,6 +102,7 @@ This file is used by all project types, including binding projects. + From 5cbe7d1aed3dd42b435651241ed6e504c310ac9a Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Mon, 13 Mar 2023 10:44:03 +0000 Subject: [PATCH 2/2] Fix the test --- .../Tests/Xamarin.Android.Build.Tests/ManifestTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs index d3a472f70fa..67a6cc33b2d 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs @@ -707,7 +707,7 @@ public void EmptyUsesSdkElementBuildsOK ([Values (false, true)] bool addReferenc var usesSdk = doc.Element ("manifest")?.Element ("uses-sdk"); Assert.IsNotNull (usesSdk, "Should have found a uses-sdk element."); var expected = addReference ? "23" : "19"; - Assert.AreEqual (expected, usesSdk.Attribute ("minSdkVersion")?.Value, $"minSdkVersion should have been '{expected}' but was '{usesSdk.Attribute ("minSdkVersion")?.Value}'"); + Assert.AreEqual (expected, usesSdk.Attribute (ns + "minSdkVersion")?.Value, $"minSdkVersion should have been '{expected}' but was '{usesSdk.Attribute ("minSdkVersion")?.Value}'"); } }