From 3df037de35f4abe20a2cc9f47383e0b14ee06d01 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Thu, 18 Jan 2024 09:13:57 -1000 Subject: [PATCH 01/12] [Xamarin.Android.Build.Tasks] Enable POM verification features. --- .../Tasks/JavaDependencyVerification.cs | 704 ++++++++++++++++++ .../Tasks/MavenDownload.cs | 2 + .../Tasks/JavaDependencyVerificationTests.cs | 523 +++++++++++++ .../Tasks/MavenDownloadTests.cs | 18 +- .../Utilities/MavenExtensions.cs | 88 ++- .../Xamarin.Android.Build.Tasks.csproj | 4 + 6 files changed, 1330 insertions(+), 9 deletions(-) create mode 100644 src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs b/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs new file mode 100644 index 00000000000..7c4cd90aed0 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs @@ -0,0 +1,704 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using Java.Interop.Maven; +using Java.Interop.Maven.Models; +using Microsoft.Android.Build.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Newtonsoft.Json; +using NuGet.ProjectModel; + +namespace Xamarin.Android.Tasks; + +public class JavaDependencyVerification : AndroidTask +{ + public override string TaskPrefix => "JDV"; + + /// + /// Java libraries whose dependencies we are being asked to verify. + /// + public ITaskItem []? AndroidLibraries { get; set; } + + /// + /// Additional POM files (like parent POMs) that we should use to resolve dependencies. + /// + public ITaskItem []? AdditionalManifests { get; set; } + + /// + /// NuGet packages this project consumes, which may fulfill Java dependencies. + /// + public ITaskItem []? PackageReferences { get; set; } + + /// + /// Projects this project references, which may fulfill Java dependencies. + /// + public ITaskItem []? ProjectReferences { get; set; } + + /// + /// Dependencies that we should ignore if they are missing. + /// + public ITaskItem []? IgnoredMavenDependencies { get; set; } + + /// + /// The cache directory to use for Maven artifacts. + /// + [Required] + public string MavenCacheDirectory { get; set; } = null!; // NRT enforced by [Required] + + [Required] + public string ProjectAssetsLockFile { get; set; } = null!; + + public override bool RunTask () + { + // Bail if no specifies a "Manifest" we need to verify + if (!(AndroidLibraries?.Select (al => al.GetMetadata ("Manifest")).Any (al => al.HasValue ()) ?? false)) + return true; + + // Populate the POM resolver with the POMs we know about + var pom_resolver = new MSBuildLoggingPomResolver (Log); + var poms_to_verify = new List (); + + foreach (var pom in AndroidLibraries.Select (al => al.GetMetadata ("Manifest"))) + if (pom.HasValue () && pom_resolver.Register (pom) is Artifact art) + poms_to_verify.Add (art); + + foreach (var pom in AdditionalManifests?.Select (al => al.ItemSpec) ?? []) + pom_resolver.Register (pom); + + // If there were errors loading the requested POMs, bail + if (Log.HasLoggedErrors) + return false; + + // Populate the dependency resolver with every dependency we know about + var resolver = new DependencyResolver (ProjectAssetsLockFile, Log); + + resolver.AddAndroidLibraries (AndroidLibraries); + resolver.AddPackageReferences (PackageReferences); + resolver.AddProjectReferences (ProjectReferences); + resolver.AddIgnoredDependencies (IgnoredMavenDependencies); + + // Parse microsoft-packages.json so we can provide package recommendations + var ms_packages = new MicrosoftNuGetPackageFinder (MavenCacheDirectory, Log); + + // Verify dependencies + foreach (var pom in poms_to_verify) { + var resolved_pom = ResolvedProject.FromArtifact (pom, pom_resolver); + + foreach (var dependency in resolved_pom.Dependencies) + resolver.EnsureDependencySatisfied (dependency, ms_packages); + } + + return !Log.HasLoggedErrors; + } +} + +class DependencyResolver +{ + List artifacts = new List (); + + readonly NuGetPackageVersionFinder? finder; + readonly TaskLoggingHelper log; + + public DependencyResolver (string? lockFile, TaskLoggingHelper log) + { + this.log = log; + + if (File.Exists (lockFile)) + finder = NuGetPackageVersionFinder.Create (lockFile!, log); + } + + public bool EnsureDependencySatisfied (ResolvedDependency dependency, MicrosoftNuGetPackageFinder packages) + { + if (!dependency.Version.HasValue ()) + log.LogWarning ("Could not determine required version of Java dependency '{0}:{1}'. Validation of this dependency will not take version into account.", dependency.GroupId, dependency.ArtifactId); + + var satisfied = TrySatisfyDependency (dependency); + + if (satisfied) + return true; + + var suggestion = packages.GetNuGetPackage ($"{dependency.GroupId}:{dependency.ArtifactId}"); + + // Message if we couldn't determine the required version + if (!dependency.Version.HasValue ()) { + if (suggestion is string nuget) + log.LogError ("Java dependency '{0}:{1}' is not satisfied. Microsoft maintains the NuGet package '{2}' that could fulfill this dependency.", dependency.GroupId, dependency.ArtifactId, nuget); + else + log.LogError ("Java dependency '{0}:{1}' is not satisfied.", dependency.GroupId, dependency.ArtifactId); + + return false; + } + + // Message if we could determine the required version + if (suggestion is string nuget2) + log.LogError ("Java dependency '{0}:{1}' version '{2}' is not satisfied. Microsoft maintains the NuGet package '{3}' that could fulfill this dependency.", dependency.GroupId, dependency.ArtifactId, dependency.Version, nuget2); + else + log.LogError ("Java dependency '{0}:{1}' version '{2}' is not satisfied.", dependency.GroupId, dependency.ArtifactId, dependency.Version); + + return false; + } + + public void AddAndroidLibraries (ITaskItem []? tasks) + { + foreach (var task in tasks.OrEmpty ()) { + var id = task.GetMetadataOrDefault ("JavaArtifact", string.Empty); + var version = task.GetMetadataOrDefault ("JavaVersion", string.Empty); + + // TODO: Should raise an error if JavaArtifact is specified but JavaVersion is not + if (!id.HasValue () || !version.HasValue ()) + continue; + + if (version != null && MavenExtensions.TryParseArtifact (id, version, log, out var art)) { + log.LogMessage ("Found Java dependency '{0}:{1}' version '{2}' from AndroidLibrary '{3}'", art.GroupId, art.Id, art.Version, task.ItemSpec); + artifacts.Add (art); + } + } + } + + public void AddPackageReferences (ITaskItem []? tasks) + { + foreach (var task in tasks.OrEmpty ()) { + + // See if JavaArtifact/JavaVersion overrides were used + if (TryParseJavaArtifactAndVersion ("PackageReference", task)) + continue; + + // Try parsing the NuGet metadata for Java version information instead + var artifact = finder?.GetJavaInformation (task.ItemSpec, task.GetMetadataOrDefault ("Version", string.Empty), log); + + if (artifact != null) { + log.LogMessage ("Found Java dependency '{0}:{1}' version '{2}' from PackageReference '{3}'", artifact.GroupId, artifact.Id, artifact.Version, task.ItemSpec); + artifacts.Add (artifact); + + continue; + } + + log.LogMessage ("No Java artifact information found for PackageReference '{0}'", task.ItemSpec); + } + } + + public void AddProjectReferences (ITaskItem []? tasks) + { + foreach (var task in tasks.OrEmpty ()) { + // See if JavaArtifact/JavaVersion overrides were used + if (TryParseJavaArtifactAndVersion ("ProjectReference", task)) + continue; + + // There currently is no alternate way to figure this out. Perhaps in + // the future we could somehow parse the project to find it automatically? + } + } + + public void AddIgnoredDependencies (ITaskItem []? tasks) + { + foreach (var task in tasks.OrEmpty ()) { + var id = task.ItemSpec; + var version = task.GetRequiredMetadata ("AndroidIgnoredJavaDependency", "Version", log); + + if (version is null) + continue; + + if (version != null && MavenExtensions.TryParseArtifact (id, version, log, out var art)) { + log.LogMessage ("Ignoring Java dependency '{0}:{1}' version '{2}'", art.GroupId, art.Id, art.Version); + artifacts.Add (art); + } + } + } + + // "type" is PackageReference or ProjectReference + // Returns "true" if JavaArtifact/JavaVersion is used, even if it was used incorrectly and is useless. + // This is so the caller will know to try alternate methods if neither JavaArtifact or JavaVersion were specified. + bool TryParseJavaArtifactAndVersion (string type, ITaskItem task) + { + var item_name = task.ItemSpec; + + // Convert "../../src/blah/Blah.csproj" to "Blah.csproj" + if (type == "ProjectReference") + item_name = Path.GetFileName (item_name); + + var has_artifact = task.HasMetadata ("JavaArtifact"); + var has_version = task.HasMetadata ("JavaVersion"); + + if (has_artifact && !has_version) { + log.LogError ("'JavaVersion' is required when using 'JavaArtifact' for {0} '{1}'.", type, item_name); + return true; + } + + if (!has_artifact && has_version) { + log.LogError ("'JavaArtifact' is required when using 'JavaVersion' for {0} '{1}'.", type, item_name); + return true; + } + + if (has_artifact && has_version) { + var id = task.GetMetadata ("JavaArtifact"); + var version = task.GetMetadata ("JavaVersion"); + + if (string.IsNullOrWhiteSpace (id)) { + log.LogError ("'JavaArtifact' cannot be empty for {0} '{1}'.", type, item_name); + return true; + } + + if (string.IsNullOrWhiteSpace (version)) { + log.LogError ("'JavaVersion' cannot be empty for {0} '{1}'.", type, item_name); + return true; + } + + if (MavenExtensions.TryParseArtifact (id, version, log, out var art)) { + log.LogMessage ("Found Java dependency '{0}:{1}' version '{2}' from {3} '{4}' (JavaArtifact)", art.GroupId, art.Id, art.Version, type, item_name); + artifacts.Add (art); + } + + return true; + } + + return false; + } + + bool TrySatisfyDependency (ResolvedDependency dependency) + { + if (!dependency.Version.HasValue ()) + return artifacts.Any (a => + a.GroupId == dependency.GroupId + && a.Id == dependency.ArtifactId); + + var dep_versions = MavenVersionRange.Parse (dependency.Version); + + var satisfied = artifacts.Any (a => + a.GroupId == dependency.GroupId + && a.Id == dependency.ArtifactId + && dep_versions.Any (r => r.ContainsVersion (MavenVersion.Parse (a.Version))) + ); + + return satisfied; + } +} + +class MSBuildLoggingPomResolver : IPomResolver +{ + readonly TaskLoggingHelper logger; + readonly Dictionary poms = new (); + + public MSBuildLoggingPomResolver (TaskLoggingHelper logger) + { + this.logger = logger; + } + + public Artifact? Register (string filename) + { + if (!File.Exists (filename)) { + logger.LogError ("Requested POM file '{0}' does not exist.", filename); + return null; + } + + try { + using (var file = File.OpenRead (filename)) { + var project = Project.Parse (file); + poms.Add (project.ToString (), project); + + logger.LogDebugMessage ("Registered POM for artifact '{0}' from '{1}'", project, filename); + return Artifact.Parse (project.ToString ()); + } + } catch (Exception ex) { + logger.LogError ("Failed to register POM file '{0}': '{1}'", filename, ex); + return null; + } + } + + public Project ResolveRawProject (Artifact artifact) + { + if (poms.TryGetValue (artifact.ToString (), out var project)) + return project; + + logger.LogError ("Unable to resolve POM for artifact '{0}'.", artifact); + + throw new InvalidOperationException ($"No POM registered for {artifact}"); + } +} + +class MicrosoftNuGetPackageFinder +{ + readonly PackageListFile? package_list; + + public MicrosoftNuGetPackageFinder (string mavenCacheDir, TaskLoggingHelper log) + { + var file = Path.Combine (mavenCacheDir, "microsoft-packages.json"); + + if (!File.Exists (file)) { + log.LogMessage ("'microsoft-packages.json' file not found, Android NuGet suggestions will not be provided"); + return; + } + + try { + var json = File.ReadAllText (file); + package_list = JsonConvert.DeserializeObject (json); + } catch (Exception ex) { + log.LogMessage ("There was an error reading 'microsoft-packages.json', Android NuGet suggestions will not be provided: {0}", ex); + } + } + + public string? GetNuGetPackage (string javaId) + { + return package_list?.Packages?.FirstOrDefault (p => p.JavaId?.Equals (javaId, StringComparison.OrdinalIgnoreCase) == true)?.NuGetId; + } + + public class PackageListFile + { + [JsonProperty ("packages")] + public List? Packages { get; set; } + } + + public class Package + { + [JsonProperty ("javaId")] + public string? JavaId { get; set; } + + [JsonProperty ("nugetId")] + public string? NuGetId { get; set; } + } +} + +public class NuGetPackageVersionFinder +{ + LockFile lock_file; + Dictionary cache = new Dictionary (); + Regex tag = new Regex ("artifact_versioned=(?.+)?:(?.+?):(?.+)\\s?", RegexOptions.Compiled); + Regex tag2 = new Regex ("artifact=(?.+)?:(?.+?):(?.+)\\s?", RegexOptions.Compiled); + + NuGetPackageVersionFinder (LockFile lockFile) + { + lock_file = lockFile; + } + + public static NuGetPackageVersionFinder? Create (string filename, TaskLoggingHelper log) + { + try { + var lock_file_format = new LockFileFormat (); + var lock_file = lock_file_format.Read (filename); + return new NuGetPackageVersionFinder (lock_file); + } catch (Exception e) { + log.LogError (e.Message); + return null; + } + } + + public Artifact? GetJavaInformation (string library, string version, TaskLoggingHelper log) + { + // Check if we already have this one in the cache + var dictionary_key = $"{library.ToLowerInvariant ()}:{version}"; + + if (cache.TryGetValue (dictionary_key, out var artifact)) + return artifact; + + // Find the LockFileLibrary + var nuget = lock_file.GetLibrary (library, new NuGet.Versioning.NuGetVersion (version)); + + if (nuget is null) { + log.LogError ("Could not find NuGet package '{0}' version '{1}' in lock file. Ensure NuGet Restore has run since this was added.", library, version); + return null; + } + + foreach (var path in lock_file.PackageFolders) + if (CheckFilePath (path.Path, nuget) is Artifact art) { + cache.Add (dictionary_key, art); + return art; + } + + return null; + } + + Artifact? CheckFilePath (string nugetPackagePath, LockFileLibrary package) + { + // Check NuGet tags + var nuspec = package.Files.FirstOrDefault (f => f.EndsWith (".nuspec", StringComparison.OrdinalIgnoreCase)); + + if (nuspec is null) + return null; + + nuspec = Path.Combine (nugetPackagePath, package.Path, nuspec); + + if (!File.Exists (nuspec)) + return null; + + var reader = new NuGet.Packaging.NuspecReader (nuspec); + var tags = reader.GetTags (); + + // Try the first tag format + var match = tag.Match (tags); + + // Try the second tag format + if (!match.Success) + match = tag2.Match (tags); + + if (!match.Success) + return null; + + // TODO: Define a well-known file that can be included in the package like "java-package.txt" + + return new Artifact (match.Groups ["ArtifactId"].Value, match.Groups ["GroupId"].Value, match.Groups ["Version"].Value); + } +} +// https://docs.oracle.com/middleware/1212/core/MAVEN/maven_version.htm#MAVEN8855 +public class MavenVersion : IComparable, IComparable, IEquatable +{ + public string? Major { get; private set; } + public string? Minor { get; private set; } + public string? Patch { get; private set; } + public string RawVersion { get; private set; } + public bool IsValid { get; private set; } = true; + + private MavenVersion (string rawVersion) => RawVersion = rawVersion; + + public static MavenVersion Parse (string version) + { + var mv = new MavenVersion (version); + + if (!version.HasValue ()) { + mv.IsValid = false; + return mv; + } + + // We're going to parse through this assuming it's a valid Maven version + mv.Major = version.FirstSubset ('.'); + version = version.ChompFirst ('.'); + + if (!TryParsePart (mv.Major, out var _, out var _)) + mv.IsValid = false; + + if (!version.HasValue ()) + return mv; + + mv.Minor = version.FirstSubset ('.'); + version = version.ChompFirst ('.'); + + if (!TryParsePart (mv.Minor, out var _, out var _)) + mv.IsValid = false; + + if (!version.HasValue ()) + return mv; + + mv.Patch = version.FirstSubset ('.'); + version = version.ChompFirst ('.'); + + if (!TryParsePart (mv.Patch, out var _, out var _)) + mv.IsValid = false; + + if (!version.HasValue ()) + return mv; + + // If there's something left, this is a nonstandard Maven version and all bets are off + mv.IsValid = false; + + return mv; + } + + public int CompareTo (object obj) + { + return CompareTo (obj as MavenVersion); + } + + public int CompareTo (MavenVersion? other) + { + if (other is null) + return 1; + + // If either instance is nonstandard, Maven does a simple string compare + if (!IsValid || !other.IsValid) + return string.Compare (RawVersion, other.RawVersion); + + var major_compare = ComparePart (Major ?? "0", other.Major ?? "0"); + + if (major_compare != 0) + return major_compare; + + var minor_compare = ComparePart (Minor ?? "0", other.Minor ?? "0"); + + if (minor_compare != 0) + return minor_compare; + + return ComparePart (Patch ?? "0", other.Patch ?? "0"); + } + + public bool Equals (MavenVersion other) + { + return CompareTo (other) == 0; + } + + int ComparePart (string a, string b) + { + // Check if they're the same string + if (a == b) + return 0; + + // Don't need to check the return because this shouldn't be called if IsValid = false + TryParsePart (a, out var a_version, out var a_qualifier); + TryParsePart (b, out var b_version, out var b_qualifier); + + // If neither have a qualifier, treat them like numbers + if (a_qualifier is null && b_qualifier is null) + return a_version.CompareTo (b_version); + + // If the numeric versions are different, just use those + if (a_version != b_version) + return a_version.CompareTo (b_version); + + // Identical versions with different qualifier fields are compared by using basic string comparison. + if (a_qualifier is not null && b_qualifier is not null) + return a_qualifier.CompareTo (b_qualifier); + + // All versions with a qualifier are older than the same version without a qualifier (release version). + if (a_qualifier is not null) + return -1; + + return 1; + } + + static bool TryParsePart (string part, out int version, out string? qualifier) + { + // These can look like: + // 1 + // 1-anything + var version_string = part.FirstSubset ('-'); + qualifier = null; + + // The first piece must be a number + if (!int.TryParse (version_string, out version)) + return false; + + part = part.ChompFirst ('-'); + + if (part.HasValue ()) + qualifier = part; + + return true; + } +} + +public class MavenVersionRange +{ + public string? MinVersion { get; private set; } + public string? MaxVersion { get; private set; } + public bool IsMinInclusive { get; private set; } = true; + public bool IsMaxInclusive { get; private set; } + public bool HasLowerBound { get; private set; } + public bool HasUpperBound { get; private set; } + + // Adapted from https://github.com/Redth/MavenNet/blob/master/MavenNet/MavenVersionRange.cs + // Original version uses NuGetVersion, which doesn't cover all "valid" Maven version cases + public static IEnumerable Parse (string range) + { + if (!range.HasValue ()) + yield break; + + var versionGroups = new List (); + + // Do a pass over the range string to parse out version groups + // eg: (1.0],(1.1,] + var in_group = false; + var current_group = string.Empty; + + foreach (var c in range) { + if (c == '(' || c == '[') { + current_group += c; + in_group = true; + } else if (c == ')' || c == ']' || (!in_group && c == ',')) { + // Don't add the , separating groups + if (in_group) + current_group += c; + + in_group = false; + + if (current_group.HasValue ()) + yield return ParseSingle (current_group); + + current_group = string.Empty; + } else { + current_group += c; + } + } + + if (!string.IsNullOrEmpty (current_group)) + yield return ParseSingle (current_group); + } + + static MavenVersionRange ParseSingle (string range) + { + var mv = new MavenVersionRange (); + + // Check for opening ( or [ + if (range [0] == '(') { + mv.IsMinInclusive = false; + range = range.Substring (1); + } else if (range [0] == '[') { + range = range.Substring (1); + } + + var last = range.Length - 1; + + // Check for closing ) or ] + if (range [last] == ')') { + mv.IsMaxInclusive = false; + range = range.Substring (0, last); + } else if (range [last] == ']') { + mv.IsMaxInclusive = true; + range = range.Substring (0, last); + } + + // Look for a single value + if (!range.Contains (",")) { + mv.MinVersion = range; + mv.HasLowerBound = true; + + // Special case [1.0] + if (mv.IsMinInclusive && mv.IsMaxInclusive) { + mv.MaxVersion = range; + mv.HasUpperBound = true; + } + + return mv; + } + + // Split the 2 values (note either can be empty) + var lower = range.FirstSubset (',').Trim (); + var upper = range.LastSubset (',').Trim (); + + if (lower.HasValue ()) { + mv.MinVersion = lower; + mv.HasLowerBound = true; + } + + if (upper.HasValue ()) { + mv.MaxVersion = upper; + mv.HasUpperBound = true; + } + + return mv; + } + + public bool ContainsVersion (MavenVersion version) + { + if (HasLowerBound) { + var min_version = MavenVersion.Parse (MinVersion!); + + if (IsMinInclusive && version.CompareTo (min_version) < 0) + return false; + else if (!IsMinInclusive && version.CompareTo (min_version) <= 0) + return false; + } + + if (HasUpperBound) { + var max_version = MavenVersion.Parse (MaxVersion!); + + if (IsMaxInclusive && version.CompareTo (max_version) > 0) + return false; + else if (!IsMaxInclusive && version.CompareTo (max_version) >= 0) + return false; + } + + return true; + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs b/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs index 1a0928d1552..8e3d6aeb849 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; using System.Collections.Generic; using System.Linq; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs new file mode 100644 index 00000000000..f8dd1793494 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs @@ -0,0 +1,523 @@ +#nullable enable + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml; +using Java.Interop.Maven.Models; +using Microsoft.Build.Utilities; +using Newtonsoft.Json; +using NUnit.Framework; +using Xamarin.Android.Tasks; + +namespace Xamarin.Android.Build.Tests; + +// - PackageReference with nuget tags +// - ProjectAssetsLockFile? +// - Download microsoft-packages.json + +public class JavaDependencyVerificationTests +{ + [Test] + public void NoManifestsSpecified () + { + var engine = new MockBuildEngine (TestContext.Out, []); + var task = new JavaDependencyVerification { + BuildEngine = engine, + MavenCacheDirectory = "", + ProjectAssetsLockFile = "", + }; + + Assert.True (task.RunTask ()); + } + + [Test] + public void MissingPom () + { + var engine = new MockBuildEngine (TestContext.Out, []); + var task = new JavaDependencyVerification { + BuildEngine = engine, + AndroidLibraries = [CreateAndroidLibraryTaskItem ("com.google.android.material.jar", "missing.pom")], + MavenCacheDirectory = "", + ProjectAssetsLockFile = "", + }; + + var result = task.RunTask (); + + Assert.False (result); + Assert.AreEqual (1, engine.Errors.Count); + Assert.AreEqual ("Requested POM file 'missing.pom' does not exist.", engine.Errors [0].Message); + } + + [Test] + public void MalformedPom () + { + using var pom = new TemporaryFile ("this is not valid XML"); + + var engine = new MockBuildEngine (TestContext.Out, []); + var task = new JavaDependencyVerification { + BuildEngine = engine, + AndroidLibraries = [CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath)], + MavenCacheDirectory = "", + ProjectAssetsLockFile = "", + }; + + var result = task.RunTask (); + + Assert.False (result); + Assert.AreEqual (1, engine.Errors.Count); + Assert.True (engine.Errors [0].Message?.StartsWith ("Failed to register POM file")); + } + + [Test] + public void NoSpecifiedDependencies () + { + using var pom = new PomBuilder ("com.google.android", "material", "1.0").BuildTemporary (); + + var engine = new MockBuildEngine (TestContext.Out, []); + var task = new JavaDependencyVerification { + BuildEngine = engine, + AndroidLibraries = [CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath)], + MavenCacheDirectory = "", + ProjectAssetsLockFile = "", + }; + + var result = task.RunTask (); + + Assert.True (result); + Assert.AreEqual (0, engine.Errors.Count); + } + + [Test] + public void MissingSpecifiedDependency () + { + using var pom = new PomBuilder ("com.google.android", "material", "1.0") + .WithDependency ("com.google.android", "missing", "1.0") + .BuildTemporary (); + + var engine = new MockBuildEngine (TestContext.Out, []); + var task = new JavaDependencyVerification { + BuildEngine = engine, + AndroidLibraries = [CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath)], + MavenCacheDirectory = "", + ProjectAssetsLockFile = "", + }; + + var result = task.RunTask (); + + Assert.False (result); + Assert.AreEqual (1, engine.Errors.Count); + Assert.AreEqual ("Java dependency 'com.google.android:missing' version '1.0' is not satisfied.", engine.Errors [0].Message); + } + + [Test] + public void MissingParentSpecifiedDependency () + { + using var parent_pom = new PomBuilder ("com.google.android", "material-parent", "1.0") + .WithDependencyManagement ("com.google.android", "missing", "2.0") + .BuildTemporary (); + + using var pom = new PomBuilder ("com.google.android", "material", "1.0") + .WithParent ("com.google.android", "material-parent", "1.0") + .WithDependency ("com.google.android", "missing", "") + .BuildTemporary (); + + var engine = new MockBuildEngine (TestContext.Out, []); + var task = new JavaDependencyVerification { + BuildEngine = engine, + AndroidLibraries = [CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath)], + AdditionalManifests = [CreateAndroidAdditionManifestTaskItem (parent_pom.FilePath)], + MavenCacheDirectory = "", + ProjectAssetsLockFile = "", + }; + + var result = task.RunTask (); + + Assert.False (result); + Assert.AreEqual (1, engine.Errors.Count); + Assert.AreEqual ("Java dependency 'com.google.android:missing' version '2.0' is not satisfied.", engine.Errors [0].Message); + } + + [Test] + public void MissingSpecifiedDependencyWithNugetSuggestion () + { + using var pom = new PomBuilder ("com.google.android", "material", "1.0") + .WithDependency ("com.google.android", "material-core", "1.0") + .BuildTemporary (); + + using var package_finder = CreateMicrosoftNuGetPackageFinder ("com.google.android:material-core", "Xamarin.Google.Material.Core"); + + var engine = new MockBuildEngine (TestContext.Out, []); + var task = new JavaDependencyVerification { + BuildEngine = engine, + AndroidLibraries = [CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath)], + MavenCacheDirectory = Path.GetDirectoryName (package_finder.FilePath)!, + ProjectAssetsLockFile = "", + }; + + var result = task.RunTask (); + + Assert.False (result); + Assert.AreEqual (1, engine.Errors.Count); + Assert.AreEqual ("Java dependency 'com.google.android:material-core' version '1.0' is not satisfied. Microsoft maintains the NuGet package 'Xamarin.Google.Material.Core' that could fulfill this dependency.", engine.Errors [0].Message); + } + + [Test] + public void MalformedMicrosoftPackagesJson () + { + using var pom = new PomBuilder ("com.google.android", "material", "1.0") + .WithDependency ("com.google.android", "material-core", "1.0") + .BuildTemporary (); + + using var package_finder = new TemporaryFile ("This is not valid json!", "microsoft-packages.json"); + + var engine = new MockBuildEngine (TestContext.Out, []); + var task = new JavaDependencyVerification { + BuildEngine = engine, + AndroidLibraries = [ + CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath), + CreateAndroidLibraryTaskItem ("com.google.android.material-core.jar", null, "com.google.android:material-core", "1.0"), + ], + MavenCacheDirectory = Path.GetDirectoryName (package_finder.FilePath)!, + ProjectAssetsLockFile = "", + }; + + var result = task.RunTask (); + + Assert.True (result); + Assert.AreEqual (0, engine.Errors.Count); + } + + [Test] + public void DependencyFulfilledByAndroidLibrary () + { + using var pom = new PomBuilder ("com.google.android", "material", "1.0") + .WithDependency ("com.google.android", "material-core", "1.0") + .BuildTemporary (); + + var engine = new MockBuildEngine (TestContext.Out, []); + var task = new JavaDependencyVerification { + BuildEngine = engine, + AndroidLibraries = [ + CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath), + CreateAndroidLibraryTaskItem ("com.google.android.material-core.jar", null, "com.google.android:material-core", "1.0"), + ], + MavenCacheDirectory = "", + ProjectAssetsLockFile = "", + }; + + var result = task.RunTask (); + + Assert.True (result); + Assert.AreEqual (0, engine.Errors.Count); + } + + [Test] + public void DependencyFulfilledByProjectReferenceExplicitMetadata () + { + using var pom = new PomBuilder ("com.google.android", "material", "1.0") + .WithDependency ("com.google.android", "material-core", "1.0") + .BuildTemporary (); + + var engine = new MockBuildEngine (TestContext.Out, []); + var task = new JavaDependencyVerification { + BuildEngine = engine, + AndroidLibraries = [ + CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath), + ], + ProjectReferences = [ + CreateAndroidLibraryTaskItem ("Google.Material.Core.csproj", null, "com.google.android:material-core", "1.0"), + ], + MavenCacheDirectory = "", + ProjectAssetsLockFile = "", + }; + + var result = task.RunTask (); + + Assert.True (result); + Assert.AreEqual (0, engine.Errors.Count); + } + + [Test] + public void DependencyFulfilledByPackageReferenceExplicitMetadata () + { + using var pom = new PomBuilder ("com.google.android", "material", "1.0") + .WithDependency ("com.google.android", "material-core", "1.0") + .BuildTemporary (); + + var engine = new MockBuildEngine (TestContext.Out, []); + var task = new JavaDependencyVerification { + BuildEngine = engine, + AndroidLibraries = [ + CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath), + ], + PackageReferences = [ + CreateAndroidLibraryTaskItem ("Xamarin.Google.Material.Core", null, "com.google.android:material-core", "1.0"), + ], + MavenCacheDirectory = "", + ProjectAssetsLockFile = "", + }; + + var result = task.RunTask (); + + Assert.True (result); + Assert.AreEqual (0, engine.Errors.Count); + } + + [Test] + public void DependencyIgnored () + { + using var pom = new PomBuilder ("com.google.android", "material", "1.0") + .WithDependency ("com.google.android", "material-core", "1.0") + .BuildTemporary (); + + var engine = new MockBuildEngine (TestContext.Out, []); + var task = new JavaDependencyVerification { + BuildEngine = engine, + AndroidLibraries = [ + CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath), + ], + IgnoredMavenDependencies = [ + CreateAndroidLibraryTaskItem ("com.google.android:material-core", rawVersion: "1.0"), + ], + MavenCacheDirectory = "", + ProjectAssetsLockFile = "", + }; + + var result = task.RunTask (); + + Assert.True (result); + Assert.AreEqual (0, engine.Errors.Count); + } + + [Test] + public void DependencyWithoutVersionFulfilled () + { + // The dependency is fulfilled but the version isn't checked + using var pom = new PomBuilder ("com.google.android", "material", "1.0") + .WithDependency ("com.google.android", "material-core", null) + .BuildTemporary (); + + var engine = new MockBuildEngine (TestContext.Out, [], []); + var task = new JavaDependencyVerification { + BuildEngine = engine, + AndroidLibraries = [ + CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath), + CreateAndroidLibraryTaskItem ("com.google.android.material-core.jar", null, "com.google.android:material-core", "1.0"), + ], + MavenCacheDirectory = "", + ProjectAssetsLockFile = "", + }; + + var result = task.RunTask (); + + Assert.True (result); + Assert.AreEqual (0, engine.Errors.Count); + Assert.AreEqual (1, engine.Warnings.Count); + Assert.AreEqual ("Could not determine required version of Java dependency 'com.google.android:material-core'. Validation of this dependency will not take version into account.", engine.Warnings [0].Message); + } + + [Test] + public void DependencyWithoutVersionNotFulfilled () + { + using var pom = new PomBuilder ("com.google.android", "material", "1.0") + .WithDependency ("com.google.android", "material-core", null) + .BuildTemporary (); + + var engine = new MockBuildEngine (TestContext.Out, [], []); + var task = new JavaDependencyVerification { + BuildEngine = engine, + AndroidLibraries = [ + CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath), + ], + MavenCacheDirectory = "", + ProjectAssetsLockFile = "", + }; + + var result = task.RunTask (); + + Assert.False (result); + Assert.AreEqual (1, engine.Warnings.Count); + Assert.AreEqual ("Could not determine required version of Java dependency 'com.google.android:material-core'. Validation of this dependency will not take version into account.", engine.Warnings [0].Message); + Assert.AreEqual (1, engine.Errors.Count); + Assert.AreEqual ("Java dependency 'com.google.android:material-core' is not satisfied.", engine.Errors [0].Message); + } + + TaskItem CreateAndroidLibraryTaskItem (string name, string? manifest = null, string? javaArtifact = null, string? javaVersion = null, string? rawVersion = null) + { + var item = new TaskItem (name); + + if (manifest is not null) + item.SetMetadata ("Manifest", manifest); + if (javaArtifact is not null) + item.SetMetadata ("JavaArtifact", javaArtifact); + if (javaVersion is not null) + item.SetMetadata ("JavaVersion", javaVersion); + if (rawVersion is not null) + item.SetMetadata ("Version", rawVersion); + + return item; + } + + TaskItem CreateAndroidAdditionManifestTaskItem (string name) + { + var item = new TaskItem (name); + + return item; + } + + TemporaryFile CreateMicrosoftNuGetPackageFinder (string javaId, string nugetId) + { + var package = new MicrosoftNuGetPackageFinder.PackageListFile { + Packages = [new MicrosoftNuGetPackageFinder.Package { JavaId = javaId, NuGetId = nugetId }] + }; + + return new TemporaryFile (JsonConvert.SerializeObject (package), "microsoft-packages.json"); + } +} + +class TemporaryFile : IDisposable +{ + public string Content { get; } + public string FilePath { get; } + + public TemporaryFile (string content, string? filename = null) + { + Content = content; + FilePath = Path.Combine (Path.GetTempPath (), filename ?? Path.GetTempFileName ()); + + File.WriteAllText (FilePath, content); + } + + public void Dispose () + { + try { + File.Delete (FilePath); + } catch { + } + } +} + +class PomBuilder +{ + public string GroupId { get; } + public string ArtifactId { get; } + public string? Version { get; } + public List Dependencies { get; } = new (); + public List DependencyManagement { get; } = new (); + public string? ParentGroupId { get; set; } + public string? ParentArtifactId { get; set; } + public string? ParentVersion { get; set; } + + public PomBuilder (string groupId, string artifactId, string? version) + { + GroupId = groupId; + ArtifactId = artifactId; + Version = version; + } + + public string Build () + { + using var sw = new StringWriter (); + using var xw = XmlWriter.Create (sw); + + xw.WriteStartDocument (); + xw.WriteStartElement ("project", "http://maven.apache.org/POM/4.0.0"); + + xw.WriteElementString ("modelVersion", "4.0.0"); + xw.WriteElementString ("groupId", GroupId); + xw.WriteElementString ("artifactId", ArtifactId); + + if (Version.HasValue ()) + xw.WriteElementString ("version", Version); + + if (ParentGroupId.HasValue () && ParentArtifactId.HasValue ()) { + xw.WriteStartElement ("parent"); + + xw.WriteElementString ("groupId", ParentGroupId); + xw.WriteElementString ("artifactId", ParentArtifactId); + + if (ParentVersion.HasValue ()) + xw.WriteElementString ("version", ParentVersion); + + xw.WriteEndElement (); // parent + } + + if (DependencyManagement.Any ()) { + xw.WriteStartElement ("dependencyManagement"); + xw.WriteStartElement ("dependencies"); + + foreach (var dependency in DependencyManagement) { + xw.WriteStartElement ("dependency"); + + xw.WriteElementString ("groupId", dependency.GroupId); + xw.WriteElementString ("artifactId", dependency.ArtifactId); + + if (dependency.Version.HasValue ()) + xw.WriteElementString ("version", dependency.Version); + + xw.WriteEndElement (); // dependency + } + + xw.WriteEndElement (); // dependencies + xw.WriteEndElement (); // dependencyManagement + } + + + if (Dependencies.Any ()) { + xw.WriteStartElement ("dependencies"); + + foreach (var dependency in Dependencies) { + xw.WriteStartElement ("dependency"); + + xw.WriteElementString ("groupId", dependency.GroupId); + xw.WriteElementString ("artifactId", dependency.ArtifactId); + + if (dependency.Version.HasValue ()) + xw.WriteElementString ("version", dependency.Version); + + xw.WriteEndElement (); // dependency + } + + xw.WriteEndElement (); // dependencies + } + xw.WriteEndElement (); // project + xw.Close (); + + return sw.ToString (); + } + + public PomBuilder WithDependency (string groupId, string artifactId, string? version) + { + Dependencies.Add (new Dependency { + GroupId = groupId, + ArtifactId = artifactId, + Version = version, + }); + + return this; + } + + public PomBuilder WithDependencyManagement (string groupId, string artifactId, string? version) + { + DependencyManagement.Add (new Dependency { + GroupId = groupId, + ArtifactId = artifactId, + Version = version, + }); + + return this; + } + + public PomBuilder WithParent (string groupId, string artifactId, string? version) + { + ParentGroupId = groupId; + ParentArtifactId = artifactId; + ParentVersion = version; + + return this; + } + + public TemporaryFile BuildTemporary () => new TemporaryFile (Build ()); +} diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/MavenDownloadTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/MavenDownloadTests.cs index 5d9c6bda151..5c2d4535285 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/MavenDownloadTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/MavenDownloadTests.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; using System.Collections.Generic; using System.IO; @@ -83,7 +85,7 @@ public async Task UnknownArtifact () await task.RunTaskAsync (); Assert.AreEqual (1, engine.Errors.Count); - Assert.AreEqual ($"Cannot download Maven artifact 'com.example:dummy'.{Environment.NewLine}- com.example_dummy.jar: Response status code does not indicate success: 404 (Not Found).{Environment.NewLine}- com.example_dummy.aar: Response status code does not indicate success: 404 (Not Found).", engine.Errors [0].Message.ReplaceLineEndings ()); + Assert.AreEqual ($"Cannot download Maven artifact 'com.example:dummy'.{Environment.NewLine}- com.example_dummy.jar: Response status code does not indicate success: 404 (Not Found).{Environment.NewLine}- com.example_dummy.aar: Response status code does not indicate success: 404 (Not Found).", engine.Errors [0].Message?.ReplaceLineEndings ()); } [Test] @@ -101,14 +103,14 @@ public async Task UnknownPom () // Create the dummy jar so we bypass that step and try to download the dummy pom var dummy_jar = Path.Combine (temp_cache_dir, "central", "com.example", "dummy", "1.0.0", "com.example_dummy.jar"); - Directory.CreateDirectory (Path.GetDirectoryName (dummy_jar)); + Directory.CreateDirectory (Path.GetDirectoryName (dummy_jar)!); using (File.Create (dummy_jar)) { } await task.RunTaskAsync (); Assert.AreEqual (1, engine.Errors.Count); - Assert.AreEqual ($"Cannot download POM file for Maven artifact 'com.example:dummy'.{Environment.NewLine}- com.example_dummy.pom: Response status code does not indicate success: 404 (Not Found).", engine.Errors [0].Message.ReplaceLineEndings ()); + Assert.AreEqual ($"Cannot download POM file for Maven artifact 'com.example:dummy'.{Environment.NewLine}- com.example_dummy.pom: Response status code does not indicate success: 404 (Not Found).", engine.Errors [0].Message?.ReplaceLineEndings ()); } finally { DeleteTempDirectory (temp_cache_dir); } @@ -130,9 +132,9 @@ public async Task MavenCentralSuccess () await task.RunTaskAsync (); Assert.AreEqual (0, engine.Errors.Count); - Assert.AreEqual (1, task.ResolvedAndroidMavenLibraries.Length); + Assert.AreEqual (1, task.ResolvedAndroidMavenLibraries?.Length); - var output_item = task.ResolvedAndroidMavenLibraries [0]; + var output_item = task.ResolvedAndroidMavenLibraries! [0]; Assert.AreEqual ("com.google.auto.value:auto-value-annotations", output_item.GetMetadata ("ArtifactSpec")); Assert.AreEqual (Path.Combine (temp_cache_dir, "central", "com.google.auto.value", "auto-value-annotations", "1.10.4", "com.google.auto.value_auto-value-annotations.jar"), output_item.GetMetadata ("ArtifactFile")); @@ -161,9 +163,9 @@ public async Task MavenGoogleSuccess () await task.RunTaskAsync (); Assert.AreEqual (0, engine.Errors.Count); - Assert.AreEqual (1, task.ResolvedAndroidMavenLibraries.Length); + Assert.AreEqual (1, task.ResolvedAndroidMavenLibraries?.Length); - var output_item = task.ResolvedAndroidMavenLibraries [0]; + var output_item = task.ResolvedAndroidMavenLibraries! [0]; Assert.AreEqual ("androidx.core:core", output_item.GetMetadata ("ArtifactSpec")); Assert.AreEqual (Path.Combine (temp_cache_dir, "google", "androidx.core", "core", "1.12.0", "androidx.core_core.aar"), output_item.GetMetadata ("ArtifactFile")); @@ -176,7 +178,7 @@ public async Task MavenGoogleSuccess () } } - ITaskItem CreateMavenTaskItem (string name, string version, string repository = null) + ITaskItem CreateMavenTaskItem (string name, string? version, string? repository = null) { var item = new TaskItem (name); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs index 4fc7f031833..3189cda88ee 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; using System.Diagnostics.CodeAnalysis; using System.IO; @@ -25,6 +27,74 @@ static class MavenExtensions /// public static bool HasValue ([NotNullWhen (true)] this string? s) => !string.IsNullOrWhiteSpace (s); + /// + /// Removes the first subset of a delimited string. ("127.0.0.1" -> "0.0.1") + /// + [return: NotNullIfNotNull (nameof (s))] + public static string? ChompFirst (this string? s, char separator) + { + if (!s.HasValue ()) + return s; + + var index = s.IndexOf (separator); + + if (index < 0) + return string.Empty; + + return s.Substring (index + 1); + } + + /// + /// Removes the final subset of a delimited string. ("127.0.0.1" -> "127.0.0") + /// + [return: NotNullIfNotNull (nameof (s))] + public static string? ChompLast (this string? s, char separator) + { + if (!s.HasValue ()) + return s; + + var index = s.LastIndexOf (separator); + + if (index < 0) + return string.Empty; + + return s.Substring (0, index); + } + + /// + /// Returns the first subset of a delimited string. ("127.0.0.1" -> "127") + /// + [return: NotNullIfNotNull (nameof (s))] + public static string? FirstSubset (this string? s, char separator) + { + if (!s.HasValue ()) + return s; + + var index = s.IndexOf (separator); + + if (index < 0) + return s; + + return s.Substring (0, index); + } + + /// + /// Returns the final subset of a delimited string. ("127.0.0.1" -> "1") + /// + [return: NotNullIfNotNull (nameof (s))] + public static string? LastSubset (this string? s, char separator) + { + if (!s.HasValue ()) + return s; + + var index = s.LastIndexOf (separator); + + if (index < 0) + return s; + + return s.Substring (index + 1); + } + // Helps to 'foreach' into a possibly null array public static T [] OrEmpty (this T []? value) { @@ -45,9 +115,25 @@ public static T [] OrEmpty (this T []? value) return artifact; } + public static bool TryParseArtifact (string id, string version, TaskLoggingHelper log, [NotNullWhen (true)] out Java.Interop.Maven.Models.Artifact? artifact) + { + artifact = null; + + var parts = id.Split (separator, StringSplitOptions.RemoveEmptyEntries); + + if (parts.Length != 2 || parts.Any (string.IsNullOrWhiteSpace)) { + log.LogCodedError ("XA4235", Properties.Resources.XA4235, id); + return false; + } + + artifact = new Java.Interop.Maven.Models.Artifact (parts [0], parts [1], version); + + return true; + } + public static Project ParsePom (string pomFile) { - Project result = null; + Project? result = null; using (var sr = File.OpenRead (pomFile)) result = (Project) pom_serializer.Deserialize (new XmlTextReader (sr) { diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj index 3bef384882d..7f253e10b05 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj @@ -29,6 +29,9 @@ + + + @@ -225,6 +228,7 @@ + + + + +``` + +Building the binding project now should result in verification errors if `my_binding_library.pom` specifies dependencies that are not met. + +For example: + +``` +error : Java dependency 'androidx.collection:collection' version '1.0.0' is not satisfied. +``` + +Seeing these error(s) or no errors should indicate that the Java dependency verification is working. Follow the [Resolving Java Dependencies](ResolvingJavaDependencies.md) guide to fix any missing dependency errors. + +## Additional POM Files + +POM files can sometimes have some optional features in use that make them more complicated than the above example. + +That is, a POM file can depend on a "parent" POM file: + +```xml + + com.squareup.okio + okio-parent + 1.17.4 + +``` + +Additionally, a POM file can "import" dependency information from another POM file: + +```xml + + + + com.squareup.okio + okio-bom + 3.0.0 + pom + import + + + +``` + +Dependency information cannot be accurately determined without also having access to these additional POM files, and will results in errors like: + +``` +error : Unable to resolve POM for artifact 'com.squareup.okio:okio-parent:1.17.4'. +error : Could not verify Java dependencies for artifact 'com.squareup.okio:okio:1.17.4' due to missing POM files. See other error(s) for details. +``` + +In this case, we need to provide the POM file for `com.squareup.okio:okio-parent:1.17.4`: + +```xml + + + + +``` + +Note that as "Parent" and "Import" POMs can themselves have parent and imported POMs, this step may need to be repeated until all POM files can be resolved. + +Note also that if using `` this should all be handled automatically. + +At this point, if there are dependency errors, follow the [Resolving Java Dependencies](ResolvingJavaDependencies.md) guide to fix any missing dependency errors. \ No newline at end of file diff --git a/Documentation/guides/ResolvingJavaDependencies.md b/Documentation/guides/ResolvingJavaDependencies.md new file mode 100644 index 00000000000..daf67170d15 --- /dev/null +++ b/Documentation/guides/ResolvingJavaDependencies.md @@ -0,0 +1,99 @@ +# Resolving Java Dependencies + +Note: This feature is only available in .NET 9+. + +## Description + +Once Java dependency verification has been enabled for a bindings project, either automatically via `` or manually via ``, there may be errors to resolve, such as: + +``` +error : Java dependency 'androidx.collection:collection' version '1.0.0' is not satisfied. +``` + +These dependencies can be fulfilled in many different ways. + +## `` + +In the best case scenario, there is already an existing binding of the Java dependency available on NuGet.org. This package may be provided by Microsoft or the .NET community. Packages maintained by Microsoft may be surfaced in the error message like this: + +``` +error : Java dependency 'androidx.collection:collection' version '1.0.0' is not satisfied. Microsoft maintains the NuGet package 'Xamarin.AndroidX.Collection' that could fulfill this dependency. +``` + +Adding the `Xamarin.AndroidX.Collection` package to the project should automatically resolve this error, as the package provides metadata to advertise that it provides the `androidx.collection:collection` dependency. This is done by looking for a specially crafted NuGet tag. For example, for the AndroidX Collection library, the tag looks like this: + +```xml + +artifact=androidx.collection:collection:1.0.0 +``` + +However there may be NuGet packages which fulfill a dependency but have not had this metadata added to it. In this case, you will need to explicitly specify which dependency the package contains with `JavaArtifact` and `JavaVersion`: + +```xml + +``` + +With this, the binding process knows the Java dependency is satisfied by the NuGet package. + +> Note: NuGet packages specify their own dependencies, so you will not need to worry about transitive dependencies. + +## `` + +If the needed Java dependency is provided by another project in your solution, you can annotate the `` to specify the dependency it fulfills: + +```xml + +``` + +With this, the binding process knows the Java dependency is satisfied by the referenced project. + +> Note: Each project specifies their own dependencies, so you will not need to worry about transitive dependencies. + +## `` + +If you are creating a public NuGet package, you will want to follow NuGet's "one library per package" policy so that the NuGet dependency graph works. However, if creating a binding for private use, you may want to include your Java dependencies directly inside the parent binding. + +This can be done by adding additional `` items to the project: + +```xml + + + +``` + +To include the Java library but not produce C# bindings for it, mark it with `Bind="false"`: + +```xml + + + +``` + +Alternatively, `` can be used to retrieve a Java library from a Maven repository: + +``` + + + +``` + +> Note: If the dependency library has its own dependencies, you will be required to ensure they are fulfilled. + +## `` + +As a last resort, a needed Java dependency can be ignored. An example of when this is useful is if the dependency library is a collection of Java annotations that are only used at compile type and not runtime. + +Note that while the error message will go away, it does not mean the package will magically work. If the dependency is actually needed at runtime and not provided the Android application will crash with a `Java.Lang.NoClassDefFoundError` error. + +```xml + + + +``` \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.JavaDependencyVerification.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.JavaDependencyVerification.targets new file mode 100644 index 00000000000..abdd69f3819 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.JavaDependencyVerification.targets @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.After.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.After.targets index 95063269a7b..53614fc28f1 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.After.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.After.targets @@ -18,6 +18,7 @@ This file is imported *after* the Microsoft.NET.Sdk/Sdk.targets. + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GetMicrosoftNuGetPackagesMap.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GetMicrosoftNuGetPackagesMap.cs new file mode 100644 index 00000000000..253549158d5 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GetMicrosoftNuGetPackagesMap.cs @@ -0,0 +1,46 @@ +#nullable enable + +using System; +using System.IO; +using Microsoft.Build.Framework; +using Microsoft.Android.Build.Tasks; +using System.Net.Http; + +namespace Xamarin.Android.Tasks; + +public class GetMicrosoftNuGetPackagesMap : AndroidAsyncTask +{ + public override string TaskPrefix => "GNP"; + + /// + /// The cache directory to use for Maven artifacts. + /// + [Required] + public string MavenCacheDirectory { get; set; } = null!; // NRT enforced by [Required] + + [Output] + public string? ResolvedPackageMap { get; set; } + + public async override System.Threading.Tasks.Task RunTaskAsync () + { + // TODO: We should check the age of the existing file and only download if it's too old + var outfile = Path.Combine (MavenCacheDirectory, "microsoft-packages.json"); + + if (File.Exists (outfile)) { + ResolvedPackageMap = outfile; + return; + } + + // File missing, download new one + try { + var http = new HttpClient (); + var json = await http.GetStringAsync ("https://aka.ms/ms-nuget-packages"); + + File.WriteAllText (outfile, json); + ResolvedPackageMap = outfile; + } catch (Exception ex) { + Log.LogMessage ("Could not download microsoft-packages.json: {0}", ex); + } + } +} + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs b/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs index 7c4cd90aed0..19bb29d87da 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs @@ -2,8 +2,10 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; +using System.Runtime.InteropServices.ComTypes; using System.Text.RegularExpressions; using Java.Interop.Maven; using Java.Interop.Maven.Models; @@ -42,16 +44,14 @@ public class JavaDependencyVerification : AndroidTask /// /// Dependencies that we should ignore if they are missing. /// - public ITaskItem []? IgnoredMavenDependencies { get; set; } + public ITaskItem []? IgnoredDependencies { get; set; } /// - /// The cache directory to use for Maven artifacts. + /// The file location of 'microsoft-packages.json'. /// - [Required] - public string MavenCacheDirectory { get; set; } = null!; // NRT enforced by [Required] + public string? MicrosoftPackagesFile { get; set; } - [Required] - public string ProjectAssetsLockFile { get; set; } = null!; + public string? ProjectAssetsLockFile { get; set; } public override bool RunTask () { @@ -63,12 +63,16 @@ public override bool RunTask () var pom_resolver = new MSBuildLoggingPomResolver (Log); var poms_to_verify = new List (); - foreach (var pom in AndroidLibraries.Select (al => al.GetMetadata ("Manifest"))) - if (pom.HasValue () && pom_resolver.Register (pom) is Artifact art) + foreach (var pom in AndroidLibraries ?? []) + if (pom_resolver.RegisterFromAndroidLibrary (pom) is Artifact art) poms_to_verify.Add (art); - foreach (var pom in AdditionalManifests?.Select (al => al.ItemSpec) ?? []) - pom_resolver.Register (pom); + //foreach (var pom in AndroidLibraries.Select (al => al.GetMetadata ("Manifest"))) + // if (pom.HasValue () && pom_resolver.Register (pom) is Artifact art) + // poms_to_verify.Add (art); + + foreach (var pom in AdditionalManifests ?? []) + pom_resolver.RegisterFromAndroidAdditionalJavaManifest (pom); // If there were errors loading the requested POMs, bail if (Log.HasLoggedErrors) @@ -80,21 +84,36 @@ public override bool RunTask () resolver.AddAndroidLibraries (AndroidLibraries); resolver.AddPackageReferences (PackageReferences); resolver.AddProjectReferences (ProjectReferences); - resolver.AddIgnoredDependencies (IgnoredMavenDependencies); + resolver.AddIgnoredDependencies (IgnoredDependencies); // Parse microsoft-packages.json so we can provide package recommendations - var ms_packages = new MicrosoftNuGetPackageFinder (MavenCacheDirectory, Log); + var ms_packages = new MicrosoftNuGetPackageFinder (MicrosoftPackagesFile, Log); // Verify dependencies foreach (var pom in poms_to_verify) { - var resolved_pom = ResolvedProject.FromArtifact (pom, pom_resolver); - - foreach (var dependency in resolved_pom.Dependencies) - resolver.EnsureDependencySatisfied (dependency, ms_packages); + if (TryResolveProject (pom, pom_resolver, out var resolved_pom)) { + foreach (var dependency in resolved_pom.Dependencies.Where (d => (d.IsRuntimeDependency () || d.IsCompileDependency ()) && !d.IsOptional ())) + resolver.EnsureDependencySatisfied (dependency, ms_packages); + } else { + Log.LogError ("Could not verify Java dependencies for artifact '{0}' due to missing POM file(s). See other error(s) for details.", pom); + } } return !Log.HasLoggedErrors; } + + static bool TryResolveProject (Artifact artifact, IPomResolver resolver, [NotNullWhen (true)]out ResolvedProject? project) + { + // ResolvedProject.FromArtifact will throw if a POM cannot be resolved, but our MSBuildLoggingPomResolver + // has already logged the failure as an MSBuild error. We don't want to log it again as an unhandled exception. + try { + project = ResolvedProject.FromArtifact (artifact, resolver); + return true; + } catch { + project = null; + return false; + } + } } class DependencyResolver @@ -288,7 +307,7 @@ public MSBuildLoggingPomResolver (TaskLoggingHelper logger) this.logger = logger; } - public Artifact? Register (string filename) + Artifact? Register (string filename) { if (!File.Exists (filename)) { logger.LogError ("Requested POM file '{0}' does not exist.", filename); @@ -309,6 +328,52 @@ public MSBuildLoggingPomResolver (TaskLoggingHelper logger) } } + public Artifact? RegisterFromAndroidLibrary (ITaskItem item) + { + var pom_file = item.GetMetadata ("Manifest"); + + if (!pom_file.HasValue ()) + return null; + + return RegisterFromTaskItem (item, "AndroidLibrary", pom_file); + } + + public Artifact? RegisterFromAndroidAdditionalJavaManifest (ITaskItem item) + => RegisterFromTaskItem (item, "AndroidAdditionalJavaManifest", item.ItemSpec); + + Artifact? RegisterFromTaskItem (ITaskItem item, string itemName, string filename) + { + item.TryParseJavaArtifactAndVersion (itemName, logger, out var artifact); + + if (!File.Exists (filename)) { + logger.LogError ("Requested POM file '{0}' does not exist.", filename); + return null; + } + + try { + using (var file = File.OpenRead (filename)) { + var project = Project.Parse (file); + var registered_artifact = Artifact.Parse (project.ToString ()); + + // Return the registered artifact, preferring any overrides specified in the task item + var final_artifact = new Artifact ( + artifact?.GroupId ?? registered_artifact.GroupId, + artifact?.Id ?? registered_artifact.Id, + artifact?.Version ?? registered_artifact.Version + ); + + poms.Add (final_artifact.ToString (), project); + + logger.LogDebugMessage ("Registered POM for artifact '{0}' from '{1}'", final_artifact, filename); + + return final_artifact; + } + } catch (Exception ex) { + logger.LogError ("Failed to register POM file '{0}': '{1}'", filename, ex); + return null; + } + } + public Project ResolveRawProject (Artifact artifact) { if (poms.TryGetValue (artifact.ToString (), out var project)) @@ -324,11 +389,9 @@ class MicrosoftNuGetPackageFinder { readonly PackageListFile? package_list; - public MicrosoftNuGetPackageFinder (string mavenCacheDir, TaskLoggingHelper log) + public MicrosoftNuGetPackageFinder (string? file, TaskLoggingHelper log) { - var file = Path.Combine (mavenCacheDir, "microsoft-packages.json"); - - if (!File.Exists (file)) { + if (file is null || !File.Exists (file)) { log.LogMessage ("'microsoft-packages.json' file not found, Android NuGet suggestions will not be provided"); return; } @@ -439,7 +502,7 @@ public class NuGetPackageVersionFinder // TODO: Define a well-known file that can be included in the package like "java-package.txt" - return new Artifact (match.Groups ["ArtifactId"].Value, match.Groups ["GroupId"].Value, match.Groups ["Version"].Value); + return new Artifact (match.Groups ["GroupId"].Value, match.Groups ["ArtifactId"].Value, match.Groups ["Version"].Value); } } // https://docs.oracle.com/middleware/1212/core/MAVEN/maven_version.htm#MAVEN8855 diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs b/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs index 8e3d6aeb849..4ad90bbb275 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs @@ -95,7 +95,9 @@ public async override System.Threading.Tasks.Task RunTaskAsync () result.SetMetadata ("ArtifactSpec", item.ItemSpec); result.SetMetadata ("ArtifactFile", artifact_file); - result.SetMetadata ("ArtifactPom", pom_file); + result.SetMetadata ("Manifest", pom_file); + result.SetMetadata ("JavaArtifact", $"{artifact.GroupId}:{artifact.Id}"); + result.SetMetadata ("JavaVersion", artifact.Versions.FirstOrDefault ()); return result; } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs index f8dd1793494..e0c67b22841 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs @@ -25,8 +25,6 @@ public void NoManifestsSpecified () var engine = new MockBuildEngine (TestContext.Out, []); var task = new JavaDependencyVerification { BuildEngine = engine, - MavenCacheDirectory = "", - ProjectAssetsLockFile = "", }; Assert.True (task.RunTask ()); @@ -39,8 +37,6 @@ public void MissingPom () var task = new JavaDependencyVerification { BuildEngine = engine, AndroidLibraries = [CreateAndroidLibraryTaskItem ("com.google.android.material.jar", "missing.pom")], - MavenCacheDirectory = "", - ProjectAssetsLockFile = "", }; var result = task.RunTask (); @@ -59,8 +55,6 @@ public void MalformedPom () var task = new JavaDependencyVerification { BuildEngine = engine, AndroidLibraries = [CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath)], - MavenCacheDirectory = "", - ProjectAssetsLockFile = "", }; var result = task.RunTask (); @@ -79,8 +73,6 @@ public void NoSpecifiedDependencies () var task = new JavaDependencyVerification { BuildEngine = engine, AndroidLibraries = [CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath)], - MavenCacheDirectory = "", - ProjectAssetsLockFile = "", }; var result = task.RunTask (); @@ -100,8 +92,6 @@ public void MissingSpecifiedDependency () var task = new JavaDependencyVerification { BuildEngine = engine, AndroidLibraries = [CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath)], - MavenCacheDirectory = "", - ProjectAssetsLockFile = "", }; var result = task.RunTask (); @@ -128,8 +118,6 @@ public void MissingParentSpecifiedDependency () BuildEngine = engine, AndroidLibraries = [CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath)], AdditionalManifests = [CreateAndroidAdditionManifestTaskItem (parent_pom.FilePath)], - MavenCacheDirectory = "", - ProjectAssetsLockFile = "", }; var result = task.RunTask (); @@ -152,8 +140,7 @@ public void MissingSpecifiedDependencyWithNugetSuggestion () var task = new JavaDependencyVerification { BuildEngine = engine, AndroidLibraries = [CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath)], - MavenCacheDirectory = Path.GetDirectoryName (package_finder.FilePath)!, - ProjectAssetsLockFile = "", + MicrosoftPackagesFile = package_finder.FilePath, }; var result = task.RunTask (); @@ -179,8 +166,7 @@ public void MalformedMicrosoftPackagesJson () CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath), CreateAndroidLibraryTaskItem ("com.google.android.material-core.jar", null, "com.google.android:material-core", "1.0"), ], - MavenCacheDirectory = Path.GetDirectoryName (package_finder.FilePath)!, - ProjectAssetsLockFile = "", + MicrosoftPackagesFile = package_finder.FilePath, }; var result = task.RunTask (); @@ -203,8 +189,6 @@ public void DependencyFulfilledByAndroidLibrary () CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath), CreateAndroidLibraryTaskItem ("com.google.android.material-core.jar", null, "com.google.android:material-core", "1.0"), ], - MavenCacheDirectory = "", - ProjectAssetsLockFile = "", }; var result = task.RunTask (); @@ -229,8 +213,6 @@ public void DependencyFulfilledByProjectReferenceExplicitMetadata () ProjectReferences = [ CreateAndroidLibraryTaskItem ("Google.Material.Core.csproj", null, "com.google.android:material-core", "1.0"), ], - MavenCacheDirectory = "", - ProjectAssetsLockFile = "", }; var result = task.RunTask (); @@ -255,8 +237,6 @@ public void DependencyFulfilledByPackageReferenceExplicitMetadata () PackageReferences = [ CreateAndroidLibraryTaskItem ("Xamarin.Google.Material.Core", null, "com.google.android:material-core", "1.0"), ], - MavenCacheDirectory = "", - ProjectAssetsLockFile = "", }; var result = task.RunTask (); @@ -278,11 +258,9 @@ public void DependencyIgnored () AndroidLibraries = [ CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath), ], - IgnoredMavenDependencies = [ + IgnoredDependencies = [ CreateAndroidLibraryTaskItem ("com.google.android:material-core", rawVersion: "1.0"), ], - MavenCacheDirectory = "", - ProjectAssetsLockFile = "", }; var result = task.RunTask (); @@ -306,8 +284,6 @@ public void DependencyWithoutVersionFulfilled () CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath), CreateAndroidLibraryTaskItem ("com.google.android.material-core.jar", null, "com.google.android:material-core", "1.0"), ], - MavenCacheDirectory = "", - ProjectAssetsLockFile = "", }; var result = task.RunTask (); @@ -331,8 +307,6 @@ public void DependencyWithoutVersionNotFulfilled () AndroidLibraries = [ CreateAndroidLibraryTaskItem ("com.google.android.material.jar", pom.FilePath), ], - MavenCacheDirectory = "", - ProjectAssetsLockFile = "", }; var result = task.RunTask (); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs index 3189cda88ee..85a0d5e628f 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs @@ -13,6 +13,7 @@ using MavenNet; using MavenNet.Models; using Microsoft.Android.Build.Tasks; +using Microsoft.Build.Framework; using Microsoft.Build.Utilities; namespace Xamarin.Android.Tasks; @@ -131,6 +132,51 @@ public static bool TryParseArtifact (string id, string version, TaskLoggingHelpe return true; } + public static bool TryParseJavaArtifactAndVersion (this ITaskItem task, string type, TaskLoggingHelper log, [NotNullWhen (true)] out Java.Interop.Maven.Models.Artifact? artifact) + { + artifact = null; + + var item_name = task.ItemSpec; + + // Convert "../../src/blah/Blah.csproj" to "Blah.csproj" + if (type == "ProjectReference") + item_name = Path.GetFileName (item_name); + + var has_artifact = task.HasMetadata ("JavaArtifact"); + var has_version = task.HasMetadata ("JavaVersion"); + + if (has_artifact && !has_version) { + log.LogError ("'JavaVersion' is required when using 'JavaArtifact' for {0} '{1}'.", type, item_name); + return false; + } + + if (!has_artifact && has_version) { + log.LogError ("'JavaArtifact' is required when using 'JavaVersion' for {0} '{1}'.", type, item_name); + return false; + } + + if (has_artifact && has_version) { + var id = task.GetMetadata ("JavaArtifact"); + var version = task.GetMetadata ("JavaVersion"); + + if (string.IsNullOrWhiteSpace (id)) { + log.LogError ("'JavaArtifact' cannot be empty for {0} '{1}'.", type, item_name); + return false; + } + + if (string.IsNullOrWhiteSpace (version)) { + log.LogError ("'JavaVersion' cannot be empty for {0} '{1}'.", type, item_name); + return false; + } + + if (TryParseArtifact (id, version, log, out artifact)) + return true; + + } + + return false; + } + public static Project ParsePom (string pomFile) { Project? result = null; @@ -300,9 +346,11 @@ public static void FixDependency (Project project, Project? parent, Dependency d return version; } - public static bool IsCompileDependency (this Dependency dependency) => string.IsNullOrWhiteSpace (dependency.Scope) || dependency.Scope.IndexOf ("compile", StringComparison.OrdinalIgnoreCase) != -1; + public static bool IsCompileDependency (this Java.Interop.Maven.Models.ResolvedDependency dependency) => string.IsNullOrWhiteSpace (dependency.Scope) || dependency.Scope.IndexOf ("compile", StringComparison.OrdinalIgnoreCase) != -1; + + public static bool IsRuntimeDependency (this Java.Interop.Maven.Models.ResolvedDependency dependency) => dependency?.Scope != null && dependency.Scope.IndexOf ("runtime", StringComparison.OrdinalIgnoreCase) != -1; - public static bool IsRuntimeDependency (this Dependency dependency) => dependency?.Scope != null && dependency.Scope.IndexOf ("runtime", StringComparison.OrdinalIgnoreCase) != -1; + public static bool IsOptional (this Java.Interop.Maven.Models.ResolvedDependency dependency) => dependency?.Optional != null && dependency.Optional.IndexOf ("true", StringComparison.OrdinalIgnoreCase) != -1; public static Dependency? FindParentDependency (this Project project, Dependency dependency) { diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets index 258389e3d18..fdad2d1bfe2 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets @@ -56,6 +56,11 @@ PreserveNewest Xamarin.Android.Bindings.JarToXml.targets + + PreserveNewest + Xamarin.Android.Bindings.JavaDependencyVerification.targets + PreserveNewest From 655d753bf880d5938fbb3f407f1655334386d622 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Wed, 24 Jan 2024 09:23:57 -1000 Subject: [PATCH 03/12] =?UTF-8?q?=EF=BB=BFFlush.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Documentation/guides/AndroidMavenLibrary.md | 3 +- .../installers/create-installers.targets | 5 +- .../xaprepare/ThirdPartyNotices/MavenNet.cs | 40 -- external/xamarin-android-tools | 2 +- ...indings.JavaDependencyVerification.targets | 6 +- .../Xamarin.Android.Bindings.Maven.targets | 4 +- .../Properties/Resources.Designer.cs | 547 +++++++++--------- .../Properties/Resources.resx | 10 +- .../Tasks/GetMicrosoftNuGetPackagesMap.cs | 93 ++- .../Tasks/JavaDependencyVerification.cs | 37 +- .../Tasks/MavenDownload.cs | 142 +++-- .../BindingBuildTest.cs | 98 ++++ .../GetMicrosoftNuGetPackagesMapTests.cs | 158 +++++ .../Tasks/JavaDependencyVerificationTests.cs | 6 +- .../Tasks/MavenDownloadTests.cs | 26 +- .../Utilities/MavenExtensions.cs | 199 +------ .../Xamarin.Android.Build.Tasks.csproj | 3 +- .../Xamarin.Android.Build.Tasks.targets | 2 - 18 files changed, 778 insertions(+), 603 deletions(-) delete mode 100644 build-tools/xaprepare/xaprepare/ThirdPartyNotices/MavenNet.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetMicrosoftNuGetPackagesMapTests.cs diff --git a/Documentation/guides/AndroidMavenLibrary.md b/Documentation/guides/AndroidMavenLibrary.md index e1e22bc5659..df3e09d6707 100644 --- a/Documentation/guides/AndroidMavenLibrary.md +++ b/Documentation/guides/AndroidMavenLibrary.md @@ -17,9 +17,10 @@ Note: This feature is only available in .NET 9+. ``` -This will do two things at build time: +This will do several things at build time: - Download the Java [artifact](https://central.sonatype.com/artifact/com.squareup.okhttp3/okhttp/4.9.3) with group id `com.squareup.okhttp3`, artifact id `okhttp`, and version `4.9.3` from [Maven Central](https://central.sonatype.com/) to a local cache (if not already cached). - Add the cached package to the .NET Android bindings build as an [``](https://github.com/xamarin/xamarin-android/blob/main/Documentation/guides/building-apps/build-items.md#androidlibrary). +- Download the Java artifact's POM file (and any needed parent/imported POM files) to enable [Java Dependency Verification](JavaDependencyVerification.md). To opt out of this feature, add `VerifyDependencies="false"` to the `` item. Note that only the requested Java artifact is added to the .NET Android bindings build. Any artifact dependencies are not added. If the requested artifact has dependencies, they must be fulfilled individually. diff --git a/build-tools/installers/create-installers.targets b/build-tools/installers/create-installers.targets index 85c8b990475..daa577014a5 100644 --- a/build-tools/installers/create-installers.targets +++ b/build-tools/installers/create-installers.targets @@ -104,14 +104,14 @@ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)HtmlAgilityPack.dll" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)HtmlAgilityPack.pdb" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Irony.dll" /> + <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Java.Interop.Tools.Maven.dll" /> + <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Java.Interop.Tools.Maven.pdb" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java-interop.jar" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java-source-utils.jar" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)LayoutBinding.cs" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libZipSharp.dll" /> <_MSBuildFiles Include="@(_LocalizationLanguages->'$(MicrosoftAndroidSdkOutDir)%(Identity)\libZipSharp.resources.dll')" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)libZipSharp.pdb" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)MavenNet.dll" /> - <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)MavenNet.pdb" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Mono.Unix.dll" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Mono.Unix.pdb" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Microsoft.Android.Build.BaseTasks.dll" /> @@ -139,6 +139,7 @@ <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Assets.targets" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Bindings.ClassParse.targets" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Bindings.Core.targets" /> + <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Bindings.JavaDependencyVerification.targets" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Bindings.Maven.targets" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Build.Tasks.dll" /> <_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)Xamarin.Android.Build.Tasks.pdb" /> diff --git a/build-tools/xaprepare/xaprepare/ThirdPartyNotices/MavenNet.cs b/build-tools/xaprepare/xaprepare/ThirdPartyNotices/MavenNet.cs deleted file mode 100644 index a09a63de12f..00000000000 --- a/build-tools/xaprepare/xaprepare/ThirdPartyNotices/MavenNet.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace Xamarin.Android.Prepare -{ - [TPN] - class MavenNet_TPN : ThirdPartyNotice - { - static readonly Uri url = new Uri ("https://github.com/Redth/MavenNet/"); - - public override string LicenseFile => string.Empty; - public override string Name => "Redth/MavenNet"; - public override Uri SourceUrl => url; - public override string LicenseText => @" -MIT License - -Copyright (c) 2017 Jonathan Dick - -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 -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE."; - - public override bool Include (bool includeExternalDeps, bool includeBuildDeps) => includeExternalDeps; - } -} diff --git a/external/xamarin-android-tools b/external/xamarin-android-tools index 37d79c9dcdf..a698a33aa4f 160000 --- a/external/xamarin-android-tools +++ b/external/xamarin-android-tools @@ -1 +1 @@ -Subproject commit 37d79c9dcdf738a181084b0b5890877128d75f1e +Subproject commit a698a33aa4ffcaac90b54caf5e77236d57b0cf9e diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.JavaDependencyVerification.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.JavaDependencyVerification.targets index abdd69f3819..31d59919a65 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.JavaDependencyVerification.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.JavaDependencyVerification.targets @@ -13,10 +13,10 @@ that Java binding dependencies are satisfied. - + DependsOnTargets="_MavenRestore"> @@ -29,7 +29,7 @@ that Java binding dependencies are satisfied. AdditionalManifests="@(AndroidAdditionalJavaManifest)" PackageReferences="@(PackageReference)" ProjectReferences="@(ProjectReference)" - IgnoredDependencies="@(AndroidIgnoredDependency)" + IgnoredDependencies="@(AndroidIgnoredJavaDependency)" MicrosoftPackagesFile="$(_ResolvedPackageMap)" ProjectAssetsLockFile="$(ProjectAssetsFile)" /> diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Maven.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Maven.targets index e47e4b6bd93..07e287a991a 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Maven.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.Maven.targets @@ -19,7 +19,7 @@ This file contains MSBuild targets used to enable @(AndroidMavenLibrary) support $([MSBuild]::EnsureTrailingSlash('$(MavenCacheDirectory)')) - @@ -27,11 +27,13 @@ This file contains MSBuild targets used to enable @(AndroidMavenLibrary) support + + diff --git a/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs b/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs index c5df25bdcc2..f7024bb0342 100644 --- a/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs +++ b/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs @@ -10,8 +10,8 @@ namespace Xamarin.Android.Tasks.Properties { using System; - - + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -23,15 +23,15 @@ namespace Xamarin.Android.Tasks.Properties { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Resources { - + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// @@ -45,7 +45,7 @@ internal Resources() { return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. @@ -59,7 +59,7 @@ internal Resources() { resourceCulture = value; } } - + /// /// Looks up a localized string similar to {0}. /// @@ -70,7 +70,7 @@ public static string AAPTManifestError { return ResourceManager.GetString("AAPTManifestError", resourceCulture); } } - + /// /// Looks up a localized string similar to Unknown option `{0}`. Please check `$(AndroidAapt2CompileExtraArgs)` and `$(AndroidAapt2LinkExtraArgs)` to see if they include any `aapt` command line arguments that are no longer valid for `aapt2` and ensure that all other arguments are valid for `aapt2`.. /// @@ -79,7 +79,7 @@ public static string APT0001 { return ResourceManager.GetString("APT0001", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid file name: It must contain only {0}.. /// @@ -88,7 +88,7 @@ public static string APT0002 { return ResourceManager.GetString("APT0002", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid file name: It must contain only {0}.. /// @@ -97,7 +97,7 @@ public static string APT0003 { return ResourceManager.GetString("APT0003", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid file name: It must start with A-z or a-z or an underscore.. /// @@ -106,27 +106,36 @@ public static string APT0004 { return ResourceManager.GetString("APT0004", resourceCulture); } } - + /// - /// Looks up a localized string similar to Directory '{0}' is from '{1}'.. + /// Looks up a localized string similar to This could be caused by the project exceeding the Windows maximum path length limitation. See https://learn.microsoft.com/xamarin/android/errors-and-warnings/apt2264 for details.. /// - public static string XA_Directory_Is_From { + public static string APT2264 { get { - return ResourceManager.GetString("XA_Directory_Is_From", resourceCulture); + return ResourceManager.GetString("APT2264", resourceCulture); } } - + /// - /// Looks up a localized string similar to Could not find an 'AndroidResource' for 'anim'. + /// Looks up a localized string similar to This could be caused by the project having non-ASCII characters in its filename or path. See https://learn.microsoft.com/xamarin/android/errors-and-warnings/apt2265 for details.. /// - public static string XA8000 { + public static string APT2265 { get { - return ResourceManager.GetString("XA8000", resourceCulture); + return ResourceManager.GetString("APT2265", resourceCulture); } } - + + /// + /// Looks up a localized string similar to Directory '{0}' is from '{1}'.. + /// + public static string XA_Directory_Is_From { + get { + return ResourceManager.GetString("XA_Directory_Is_From", resourceCulture); + } + } + /// - /// Looks up a localized string similar to + /// Looks up a localized string similar to /// This code was generated by a tool. /// It was generated from {0} /// Changes to this file may cause incorrect behavior and will be lost if @@ -138,7 +147,7 @@ public static string XA_Manifest_AutoGenerated_Header { return ResourceManager.GetString("XA_Manifest_AutoGenerated_Header", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not determine API level for $(TargetFrameworkVersion) of '{0}'.. /// @@ -147,7 +156,7 @@ public static string XA0000_API_for_TargetFrameworkVersion { return ResourceManager.GetString("XA0000_API_for_TargetFrameworkVersion", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not determine $(AndroidApiLevel) or $(TargetFrameworkVersion); should not be reached.. /// @@ -156,7 +165,7 @@ public static string XA0000_API_or_TargetFrameworkVersion_Fail { return ResourceManager.GetString("XA0000_API_or_TargetFrameworkVersion_Fail", resourceCulture); } } - + /// /// Looks up a localized string similar to Unhandled exception: {0}. /// @@ -165,7 +174,7 @@ public static string XA0000_Exception { return ResourceManager.GetString("XA0000_Exception", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not determine $(TargetFrameworkVersion) for API level '{0}.'. /// @@ -174,7 +183,7 @@ public static string XA0000_TargetFrameworkVersion_for_API { return ResourceManager.GetString("XA0000_TargetFrameworkVersion_for_API", resourceCulture); } } - + /// /// Looks up a localized string similar to Unsupported or invalid $(TargetFrameworkVersion) value of '{0}'. Please update your Project Options.. /// @@ -183,7 +192,7 @@ public static string XA0001 { return ResourceManager.GetString("XA0001", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not find mono.android.jar. /// @@ -192,7 +201,7 @@ public static string XA0002 { return ResourceManager.GetString("XA0002", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid `android:versionCode` value `{0}` in `AndroidManifest.xml`. It must be an integer value.. /// @@ -201,7 +210,7 @@ public static string XA0003 { return ResourceManager.GetString("XA0003", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid `android:versionCode` value `{0}` in `AndroidManifest.xml`. The value must be in the range of 0 to {1}.. /// @@ -210,7 +219,7 @@ public static string XA0004 { return ResourceManager.GetString("XA0004", resourceCulture); } } - + /// /// Looks up a localized string similar to Building with JDK version `{0}` is not supported. Please install JDK version `{1}`. See https://aka.ms/xamarin/jdk9-errors. /// @@ -219,7 +228,7 @@ public static string XA0030 { return ResourceManager.GetString("XA0030", resourceCulture); } } - + /// /// Looks up a localized string similar to Java SDK {0} or above is required when using {1}. ///Download the latest JDK at: https://aka.ms/msopenjdk @@ -230,7 +239,7 @@ public static string XA0031 { return ResourceManager.GetString("XA0031", resourceCulture); } } - + /// /// Looks up a localized string similar to Java SDK {0} or above is required when using .NET 6 or higher. Download the latest JDK at: https://aka.ms/msopenjdk. /// @@ -239,7 +248,7 @@ public static string XA0031_NET { return ResourceManager.GetString("XA0031_NET", resourceCulture); } } - + /// /// Looks up a localized string similar to Java SDK {0} or above is required when using Android SDK Build-Tools {1}.. /// @@ -248,7 +257,7 @@ public static string XA0032 { return ResourceManager.GetString("XA0032", resourceCulture); } } - + /// /// Looks up a localized string similar to Failed to get the Java SDK version because the returned value does not appear to contain a valid version number. `{0} -version` returned: ```{1}```. /// @@ -257,7 +266,7 @@ public static string XA0033 { return ResourceManager.GetString("XA0033", resourceCulture); } } - + /// /// Looks up a localized string similar to Failed to get the Java SDK version. Please ensure you have Java {0} or above installed.. /// @@ -266,7 +275,7 @@ public static string XA0034 { return ResourceManager.GetString("XA0034", resourceCulture); } } - + /// /// Looks up a localized string similar to Unable to determine the Android ABI from the value '{0}'. Edit the project file in a text editor and set the 'RuntimeIdentifiers' MSBuild property to contain only valid identifiers for the Android platform.. /// @@ -275,7 +284,7 @@ public static string XA0035 { return ResourceManager.GetString("XA0035", resourceCulture); } } - + /// /// Looks up a localized string similar to The 'AndroidSupportedAbis' MSBuild property is no longer supported. Edit the project file in a text editor, remove any uses of 'AndroidSupportedAbis', and use the 'RuntimeIdentifiers' MSBuild property instead.. /// @@ -284,7 +293,7 @@ public static string XA0036 { return ResourceManager.GetString("XA0036", resourceCulture); } } - + /// /// Looks up a localized string similar to EmbeddedNativeLibrary '{0}' is invalid in Android Application projects. Please use AndroidNativeLibrary instead.. /// @@ -293,7 +302,7 @@ public static string XA0100 { return ResourceManager.GetString("XA0100", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid value for `$(AndroidSequencePointsMode)`: {0}. /// @@ -302,7 +311,7 @@ public static string XA0104 { return ResourceManager.GetString("XA0104", resourceCulture); } } - + /// /// Looks up a localized string similar to The $(TargetFrameworkVersion) for {0} ({1}) is greater than the $(TargetFrameworkVersion) for the application project ({2}). Please increase the $(TargetFrameworkVersion) for the application project.. /// @@ -311,7 +320,7 @@ public static string XA0105 { return ResourceManager.GetString("XA0105", resourceCulture); } } - + /// /// Looks up a localized string similar to {0} is a Reference Assembly.. /// @@ -320,7 +329,7 @@ public static string XA0107 { return ResourceManager.GetString("XA0107", resourceCulture); } } - + /// /// Looks up a localized string similar to Ignoring Reference Assembly `{0}`.. /// @@ -329,7 +338,7 @@ public static string XA0107_Ignoring { return ResourceManager.GetString("XA0107_Ignoring", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not get version from '{0}'. Defaulting to 1.0. /// @@ -338,7 +347,7 @@ public static string XA0108 { return ResourceManager.GetString("XA0108", resourceCulture); } } - + /// /// Looks up a localized string similar to Unsupported version of AAPT2 found at path '{0}'. Open the project file in a text editor and remove the 'Aapt2ToolPath' MSBuild property or ensure it is set to a valid location.. /// @@ -347,7 +356,7 @@ public static string XA0111 { return ResourceManager.GetString("XA0111", resourceCulture); } } - + /// /// Looks up a localized string similar to AAPT2 was not found at path '{0}'. Open the project file in a text editor and remove the 'Aapt2ToolPath' MSBuild property or ensure it is set to a valid location.. /// @@ -356,7 +365,7 @@ public static string XA0112 { return ResourceManager.GetString("XA0112", resourceCulture); } } - + /// /// Looks up a localized string similar to Google Play requires that new applications and updates must use a TargetFrameworkVersion of {0} (API level {1}) or above. You are currently targeting {2} (API level {3}).. /// @@ -365,7 +374,7 @@ public static string XA0113 { return ResourceManager.GetString("XA0113", resourceCulture); } } - + /// /// Looks up a localized string similar to Unable to find `EmbeddedResource` named `{0}`.. /// @@ -374,7 +383,7 @@ public static string XA0116 { return ResourceManager.GetString("XA0116", resourceCulture); } } - + /// /// Looks up a localized string similar to The TargetFrameworkVersion {0} is deprecated. Please update it to be v5.0 or higher.. /// @@ -383,7 +392,7 @@ public static string XA0117 { return ResourceManager.GetString("XA0117", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not parse '{0}'. /// @@ -392,7 +401,7 @@ public static string XA0118_Parse { return ResourceManager.GetString("XA0118_Parse", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not resolve `target` in lock file for '{0}'. /// @@ -401,7 +410,7 @@ public static string XA0118_Target { return ResourceManager.GetString("XA0118_Target", resourceCulture); } } - + /// /// Looks up a localized string similar to Using Fast Deployment and Android App Bundles at the same time is not currently supported. Use Fast Deployment for Debug configurations and Android App Bundles for Release configurations.. /// @@ -410,7 +419,7 @@ public static string XA0119_AAB { return ResourceManager.GetString("XA0119_AAB", resourceCulture); } } - + /// /// Looks up a localized string similar to Using fast deployment and AOT at the same time is not recommended. Use fast deployment for Debug configurations and AOT for Release configurations.. /// @@ -419,7 +428,7 @@ public static string XA0119_AOT { return ResourceManager.GetString("XA0119_AOT", resourceCulture); } } - + /// /// Looks up a localized string similar to Disabling the interpreter; using the interpreter and AOT at the same time is not supported. Use the interpreter for hot reload support in Debug configurations and AOT for Release configurations.. /// @@ -428,7 +437,7 @@ public static string XA0119_Interpreter { return ResourceManager.GetString("XA0119_Interpreter", resourceCulture); } } - + /// /// Looks up a localized string similar to Using fast deployment and the linker at the same time is not recommended. Use fast deployment for Debug configurations and the linker for Release configurations.. /// @@ -437,7 +446,7 @@ public static string XA0119_LinkMode { return ResourceManager.GetString("XA0119_LinkMode", resourceCulture); } } - + /// /// Looks up a localized string similar to Using fast deployment and a code shrinker at the same time is not recommended. Use fast deployment for Debug configurations and a code shrinker for Release configurations.. /// @@ -446,7 +455,7 @@ public static string XA0119_LinkTool { return ResourceManager.GetString("XA0119_LinkTool", resourceCulture); } } - + /// /// Looks up a localized string similar to Assembly '{0}' is using '[assembly: {1}]', which is no longer supported. Use a newer version of this NuGet package or notify the library author.. /// @@ -455,7 +464,7 @@ public static string XA0121 { return ResourceManager.GetString("XA0121", resourceCulture); } } - + /// /// Looks up a localized string similar to Assembly '{0}' is using a deprecated attribute '[assembly: {1}]'. Use a newer version of this NuGet package or notify the library author.. /// @@ -464,7 +473,7 @@ public static string XA0122 { return ResourceManager.GetString("XA0122", resourceCulture); } } - + /// /// Looks up a localized string similar to Removing {0} from {1}. Lint {2} does not support this check.. /// @@ -473,7 +482,7 @@ public static string XA0123 { return ResourceManager.GetString("XA0123", resourceCulture); } } - + /// /// Looks up a localized string similar to '{0}' is using a deprecated debug information level. ///Set the debugging information to Portable in the Visual Studio project property pages or edit the project file in a text editor and set the 'DebugType' MSBuild property to 'portable' to use the newer, cross-platform debug information level. @@ -484,7 +493,7 @@ public static string XA0125 { return ResourceManager.GetString("XA0125", resourceCulture); } } - + /// /// Looks up a localized string similar to There was a problem parsing {0}. This is likely due to incomplete or invalid XML. Exception: {1}. /// @@ -493,7 +502,7 @@ public static string XA1000 { return ResourceManager.GetString("XA1000", resourceCulture); } } - + /// /// Looks up a localized string similar to AndroidResgen: Warning while updating resource XML '{0}': {1}. /// @@ -502,7 +511,7 @@ public static string XA1001 { return ResourceManager.GetString("XA1001", resourceCulture); } } - + /// /// Looks up a localized string similar to The closest match found for '{0}' is '{1}', but the capitalization does not match. Please correct the capitalization.. /// @@ -511,7 +520,7 @@ public static string XA1002 { return ResourceManager.GetString("XA1002", resourceCulture); } } - + /// /// Looks up a localized string similar to Attempting basic type name matching for element with ID '{0}' and type '{1}'. /// @@ -520,7 +529,7 @@ public static string XA1005 { return ResourceManager.GetString("XA1005", resourceCulture); } } - + /// /// Looks up a localized string similar to If basic type name matching fails, please add a `xamarin:managedType` attribute to the element to specify the fully qualified managed type name of the element.. /// @@ -529,7 +538,7 @@ public static string XA1005_Instructions { return ResourceManager.GetString("XA1005_Instructions", resourceCulture); } } - + /// /// Looks up a localized string similar to The TargetFrameworkVersion (Android API level {0}) is higher than the targetSdkVersion ({1}). Please increase the `android:targetSdkVersion` in the `AndroidManifest.xml` so that the API levels match.. /// @@ -538,7 +547,7 @@ public static string XA1006 { return ResourceManager.GetString("XA1006", resourceCulture); } } - + /// /// Looks up a localized string similar to The minSdkVersion ({0}) is greater than the targetSdkVersion. Please change the value such that the minSdkVersion is less than or equal to the targetSdkVersion ({1}).. /// @@ -547,7 +556,7 @@ public static string XA1007 { return ResourceManager.GetString("XA1007", resourceCulture); } } - + /// /// Looks up a localized string similar to The TargetFrameworkVersion (Android API level {0}) is lower than the targetSdkVersion ({1}). Please increase the `$(TargetFrameworkVersion)` or decrease the `android:targetSdkVersion` in the `AndroidManifest.xml` so that the API levels match.. /// @@ -556,7 +565,7 @@ public static string XA1008 { return ResourceManager.GetString("XA1008", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid `$(AndroidManifestPlaceholders)` value for Android manifest placeholders. Please use `key1=value1;key2=value2` format. The specified value was: `{0}`. /// @@ -565,7 +574,7 @@ public static string XA1010 { return ResourceManager.GetString("XA1010", resourceCulture); } } - + /// /// Looks up a localized string similar to Using ProGuard with the D8 DEX compiler is no longer supported. Please set the code shrinker to 'r8' in the Visual Studio project property pages or edit the project file in a text editor and set the 'AndroidLinkTool' MSBuild property to 'r8'.. /// @@ -574,7 +583,7 @@ public static string XA1011 { return ResourceManager.GetString("XA1011", resourceCulture); } } - + /// /// Looks up a localized string similar to Included layout root element override ID '{0}' is not valid.. /// @@ -583,7 +592,7 @@ public static string XA1012 { return ResourceManager.GetString("XA1012", resourceCulture); } } - + /// /// Looks up a localized string similar to Failed to parse ID of node '{0}' in the layout file '{1}'.. /// @@ -592,7 +601,7 @@ public static string XA1013 { return ResourceManager.GetString("XA1013", resourceCulture); } } - + /// /// Looks up a localized string similar to JAR library references with identical file names but different contents were found: {0}. Please remove any conflicting libraries from EmbeddedJar, InputJar and AndroidJavaLibrary.. /// @@ -601,7 +610,7 @@ public static string XA1014 { return ResourceManager.GetString("XA1014", resourceCulture); } } - + /// /// Looks up a localized string similar to More than one Android Wear project is specified as the paired project. It can be at most one.. /// @@ -610,7 +619,7 @@ public static string XA1015 { return ResourceManager.GetString("XA1015", resourceCulture); } } - + /// /// Looks up a localized string similar to Target Wear application's project '{0}' does not specify required 'AndroidManifest' project property.. /// @@ -619,7 +628,7 @@ public static string XA1016 { return ResourceManager.GetString("XA1016", resourceCulture); } } - + /// /// Looks up a localized string similar to Target Wear application's AndroidManifest.xml does not specify required 'package' attribute.. /// @@ -628,7 +637,7 @@ public static string XA1017 { return ResourceManager.GetString("XA1017", resourceCulture); } } - + /// /// Looks up a localized string similar to Specified AndroidManifest file does not exist: {0}.. /// @@ -637,7 +646,7 @@ public static string XA1018 { return ResourceManager.GetString("XA1018", resourceCulture); } } - + /// /// Looks up a localized string similar to `LibraryProjectProperties` file `{0}` is located in a parent directory of the bindings project's intermediate output directory. Please adjust the path to use the original `project.properties` file directly from the Android library project directory.. /// @@ -646,7 +655,7 @@ public static string XA1019 { return ResourceManager.GetString("XA1019", resourceCulture); } } - + /// /// Looks up a localized string similar to At least one Java library is required for binding. Check that a Java library is included in the project and has the appropriate build action: 'LibraryProjectZip' (for AAR or ZIP), 'EmbeddedJar', 'InputJar' (for JAR), or 'LibraryProjectProperties' (project.properties).. /// @@ -655,7 +664,7 @@ public static string XA1020 { return ResourceManager.GetString("XA1020", resourceCulture); } } - + /// /// Looks up a localized string similar to Specified source Java library not found: {0}. /// @@ -664,7 +673,7 @@ public static string XA1021 { return ResourceManager.GetString("XA1021", resourceCulture); } } - + /// /// Looks up a localized string similar to Specified reference Java library not found: {0}. /// @@ -673,7 +682,7 @@ public static string XA1022 { return ResourceManager.GetString("XA1022", resourceCulture); } } - + /// /// Looks up a localized string similar to Using the DX DEX Compiler is not supported. Please set the DEX compiler to 'd8' in the Visual Studio project property pages or edit the project file in a text editor and set the 'AndroidDexTool' MSBuild property to 'd8'.. /// @@ -682,16 +691,16 @@ public static string XA1023 { return ResourceManager.GetString("XA1023", resourceCulture); } } - + /// - /// Looks up a localized string similar to Ignoring configuration file '{0}'. .NET configuration files are not supported in Xamarin.Android projects that target .NET 6 or higher.. + /// Looks up a localized string similar to Ignoring configuration file '{0}'. .NET configuration files are not supported in .NET Android projects that target .NET 6 or higher.. /// public static string XA1024 { get { return ResourceManager.GetString("XA1024", resourceCulture); } } - + /// /// Looks up a localized string similar to The experimental 'Hybrid' value for the 'AndroidAotMode' MSBuild property is not currently compatible with the armeabi-v7a target ABI. To continue using the experimental 'Hybrid' value for 'AndroidAotMode', deselect the armeabi-v7a target ABI in the Visual Studio project property pages or edit the project file in a text editor and remove 'armeabi-v7a' from the 'AndroidSupportedAbis' MSBuild property.. /// @@ -700,7 +709,7 @@ public static string XA1025 { return ResourceManager.GetString("XA1025", resourceCulture); } } - + /// /// Looks up a localized string similar to Using AAPT is deprecated in favor of AAPT2. Please enable 'Use incremental Android packaging system (aapt2)' in the Visual Studio project property pages or edit the project file in a text editor and set the 'AndroidUseAapt2' MSBuild property to 'true'.. /// @@ -709,16 +718,16 @@ public static string XA1026 { return ResourceManager.GetString("XA1026", resourceCulture); } } - + /// - /// Looks up a localized string similar to Using AAPT is not supported in Xamarin.Android projects that target .NET 6 or higher. Please enable 'Use incremental Android packaging system (aapt2)' in the Visual Studio project property pages or edit the project file in a text editor and set the 'AndroidUseAapt2' MSBuild property to 'true'.. + /// Looks up a localized string similar to Using AAPT is not supported in .NET Android projects that target .NET 6 or higher. Please enable 'Use incremental Android packaging system (aapt2)' in the Visual Studio project property pages or edit the project file in a text editor and set the 'AndroidUseAapt2' MSBuild property to 'true'.. /// public static string XA1026_dotnet { get { return ResourceManager.GetString("XA1026_dotnet", resourceCulture); } } - + /// /// Looks up a localized string similar to The 'EnableProguard' MSBuild property is set to 'true' and the 'AndroidLinkTool' MSBuild property is empty, so 'AndroidLinkTool' will default to 'proguard'.. /// @@ -727,7 +736,7 @@ public static string XA1027 { return ResourceManager.GetString("XA1027", resourceCulture); } } - + /// /// Looks up a localized string similar to The 'AndroidEnableProguard' MSBuild property is set to 'true' and the 'AndroidLinkTool' MSBuild property is empty, so 'AndroidLinkTool' will default to 'proguard'.. /// @@ -736,7 +745,91 @@ public static string XA1028 { return ResourceManager.GetString("XA1028", resourceCulture); } } - + + /// + /// Looks up a localized string similar to The 'AotAssemblies' MSBuild property is deprecated. Edit the project file in a text editor to remove this property, and use the 'RunAOTCompilation' MSBuild property instead.. + /// + public static string XA1029 { + get { + return ResourceManager.GetString("XA1029", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The 'RunAOTCompilation' MSBuild property is only supported when trimming is enabled. Edit the project file in a text editor to set 'PublishTrimmed' to 'true' for this build configuration.. + /// + public static string XA1030 { + get { + return ResourceManager.GetString("XA1030", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The 'AndroidHttpClientHandlerType' property value '{0}' must derive from '{1}'. + ///Please change the value to an assembly-qualifed type name which inherits from '{1}' or remove the property completely.. + /// + public static string XA1031 { + get { + return ResourceManager.GetString("XA1031", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The 'AndroidHttpClientHandlerType' property value '{0}' must not derive from 'System.Net.Htt.HttpClientHandler'. + ///Please change the value to an assembly-qualifed type name which inherits from 'System.Net.Http.HttpMessageHandler' or remove the property completely.. + /// + public static string XA1031_HCH { + get { + return ResourceManager.GetString("XA1031_HCH", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to resolve '{0}' from '{1}'. Please check your `AndroidHttpClientHandlerType` setting.. + /// + public static string XA1032 { + get { + return ResourceManager.GetString("XA1032", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Could not resolve '{0}'. Please check your `AndroidHttpClientHandlerType` setting.. + /// + public static string XA1033 { + get { + return ResourceManager.GetString("XA1033", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Your project references '{0}' which uses the `_Microsoft.Android.Resource.Designer` assembly, but you do not have this feature enabled. Please set the `AndroidUseDesignerAssembly` MSBuild property to `true` in your project file.. + /// + public static string XA1034 { + get { + return ResourceManager.GetString("XA1034", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The 'BundleAssemblies' property is deprecated and it has no effect on the application build. Equivalent functionality is implemented by the 'AndroidUseAssemblyStore' and 'AndroidEnableAssemblyCompression' properties.. + /// + public static string XA1035 { + get { + return ResourceManager.GetString("XA1035", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AndroidManifest.xml //uses-sdk/@android:minSdkVersion '{0}' does not match the $(SupportedOSPlatformVersion) value '{1}' in the project file (if there is no $(SupportedOSPlatformVersion) value in the project file, then a default value has been assumed). + ///Either change the value in the AndroidManifest.xml to match the $(SupportedOSPlatformVersion) value, or remove the value in the AndroidManifest.xml (and add a $(SupportedOSPlatformVersion) value to the project file if it doesn't already exist).. + /// + public static string XA1036 { + get { + return ResourceManager.GetString("XA1036", resourceCulture); + } + } + /// /// Looks up a localized string similar to The '{0}' MSBuild property is deprecated and will be removed in .NET {1}. See https://aka.ms/net-android-deprecations for more details.. /// @@ -747,14 +840,14 @@ public static string XA1037 { } /// - /// Looks up a localized string similar to Use of AppDomain.CreateDomain() detected in assembly: {0}. .NET 6 and higher will only support a single AppDomain, so this API will no longer be available in Xamarin.Android once .NET 6 is released.. + /// Looks up a localized string similar to Use of AppDomain.CreateDomain() detected in assembly: {0}. .NET 6 and higher will only support a single AppDomain, so this API will no longer be available in .NET Android once .NET 6 is released.. /// public static string XA2000 { get { return ResourceManager.GetString("XA2000", resourceCulture); } } - + /// /// Looks up a localized string similar to Support for the 'MONO_GC_PARAMS=bridge-implementation=old' value will be removed in .NET 7.. /// @@ -763,7 +856,7 @@ public static string XA2000_gcParams_bridgeImpl { return ResourceManager.GetString("XA2000_gcParams_bridgeImpl", resourceCulture); } } - + /// /// Looks up a localized string similar to Source file '{0}' could not be found.. /// @@ -772,7 +865,7 @@ public static string XA2001 { return ResourceManager.GetString("XA2001", resourceCulture); } } - + /// /// Looks up a localized string similar to Can not resolve reference: `{0}`, referenced by {1}. Perhaps it doesn't exist in the Mono for Android profile?. /// @@ -781,7 +874,7 @@ public static string XA2002_Framework { return ResourceManager.GetString("XA2002_Framework", resourceCulture); } } - + /// /// Looks up a localized string similar to Can not resolve reference: `{0}`, referenced by {1}. Please add a NuGet package or assembly reference for `{0}`, or remove the reference to `{2}`.. /// @@ -790,7 +883,7 @@ public static string XA2002_NuGet { return ResourceManager.GetString("XA2002_NuGet", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not resolve reference to '{0}' (defined in assembly '{1}') with scope '{2}'. When the scope is different from the defining assembly, it usually means that the type is forwarded.. /// @@ -799,7 +892,7 @@ public static string XA2006 { return ResourceManager.GetString("XA2006", resourceCulture); } } - + /// /// Looks up a localized string similar to Exception while loading assemblies: {0}. /// @@ -808,7 +901,7 @@ public static string XA2007 { return ResourceManager.GetString("XA2007", resourceCulture); } } - + /// /// Looks up a localized string similar to In referenced assembly {0}, Java.Interop.DoNotPackageAttribute requires non-null file name.. /// @@ -817,25 +910,7 @@ public static string XA2008 { return ResourceManager.GetString("XA2008", resourceCulture); } } - - /// - /// Looks up a localized string similar to This is probably caused by the project exceeding the Max Path length. Please move your entire project closer to the Root of the drive.. - /// - public static string APT2264 { - get { - return ResourceManager.GetString("APT2264", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to This could be caused by the project having non-ASCII characters in it path. - /// - public static string APT2265 { - get { - return ResourceManager.GetString("APT2265", resourceCulture); - } - } - + /// /// Looks up a localized string similar to Could not AOT the assembly: {0}. /// @@ -844,7 +919,7 @@ public static string XA3001 { return ResourceManager.GetString("XA3001", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid AOT mode: {0}. /// @@ -853,7 +928,7 @@ public static string XA3002 { return ResourceManager.GetString("XA3002", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not strip IL of assembly: {0}. /// @@ -862,7 +937,7 @@ public static string XA3003 { return ResourceManager.GetString("XA3003", resourceCulture); } } - + /// /// Looks up a localized string similar to Android NDK r10d is buggy and provides an incompatible x86_64 libm.so. See https://code.google.com/p/android/issues/detail?id=161422.. /// @@ -871,7 +946,7 @@ public static string XA3004 { return ResourceManager.GetString("XA3004", resourceCulture); } } - + /// /// Looks up a localized string similar to The detected Android NDK version is incompatible with the targeted LLVM configuration. Please upgrade to NDK r10d or newer.. /// @@ -880,25 +955,25 @@ public static string XA3005 { return ResourceManager.GetString("XA3005", resourceCulture); } } - + /// - /// Looks up a localized string similar to Could not compile native assembly file: {0}. + /// Looks up a localized string similar to Could not compile native assembly file: {0}{1}. /// public static string XA3006 { get { return ResourceManager.GetString("XA3006", resourceCulture); } } - + /// - /// Looks up a localized string similar to Could not link native shared library: {0}. + /// Looks up a localized string similar to Could not link native shared library: {0}{1}. /// public static string XA3007 { get { return ResourceManager.GetString("XA3007", resourceCulture); } } - + /// /// Looks up a localized string similar to Failed to generate Java type for class: {0} due to {1}. /// @@ -907,7 +982,7 @@ public static string XA4209 { return ResourceManager.GetString("XA4209", resourceCulture); } } - + /// /// Looks up a localized string similar to Please add a reference to Mono.Android.Export.dll when using ExportAttribute or ExportFieldAttribute.. /// @@ -916,7 +991,7 @@ public static string XA4210 { return ResourceManager.GetString("XA4210", resourceCulture); } } - + /// /// Looks up a localized string similar to AndroidManifest.xml //uses-sdk/@android:targetSdkVersion '{0}' is less than $(TargetFrameworkVersion) '{1}'. Using API-{2} for ACW compilation.. /// @@ -925,7 +1000,7 @@ public static string XA4211 { return ResourceManager.GetString("XA4211", resourceCulture); } } - + /// /// Looks up a localized string similar to The type '{0}' must provide a public default constructor. /// @@ -934,7 +1009,7 @@ public static string XA4213 { return ResourceManager.GetString("XA4213", resourceCulture); } } - + /// /// Looks up a localized string similar to The managed type `{0}` exists in multiple assemblies: {1}. Please refactor the managed type names in these assemblies so that they are not identical.. /// @@ -943,7 +1018,7 @@ public static string XA4214 { return ResourceManager.GetString("XA4214", resourceCulture); } } - + /// /// Looks up a localized string similar to References to the type `{0}` will refer to `{0}, {1}`.. /// @@ -952,7 +1027,7 @@ public static string XA4214_Result { return ResourceManager.GetString("XA4214_Result", resourceCulture); } } - + /// /// Looks up a localized string similar to The Java type `{0}` is generated by more than one managed type. Please change the [Register] attribute so that the same Java type is not emitted.. /// @@ -961,7 +1036,7 @@ public static string XA4215 { return ResourceManager.GetString("XA4215", resourceCulture); } } - + /// /// Looks up a localized string similar to `{0}` generated by: {1}. /// @@ -970,25 +1045,25 @@ public static string XA4215_Details { return ResourceManager.GetString("XA4215_Details", resourceCulture); } } - + /// - /// Looks up a localized string similar to The deployment target '{1}' is not supported (the minimum is '{2}'). Please increase (or remove) the //uses-sdk/@android:minSdkVersion value in your AndroidManifest.xml.. + /// Looks up a localized string similar to The deployment target '{0}' is not supported (the minimum is '{1}'). Please increase (or remove) the //uses-sdk/@android:minSdkVersion value in your AndroidManifest.xml.. /// public static string XA4216_MinSdkVersion { get { return ResourceManager.GetString("XA4216_MinSdkVersion", resourceCulture); } } - + /// - /// Looks up a localized string similar to The deployment target '{1}' is not supported (the minimum is '{2}'). Please increase the $(SupportedOSPlatformVersion) property value in your project file.. + /// Looks up a localized string similar to The deployment target '{0}' is not supported (the minimum is '{1}'). Please increase the $(SupportedOSPlatformVersion) property value in your project file.. /// public static string XA4216_SupportedOSPlatformVersion { get { return ResourceManager.GetString("XA4216_SupportedOSPlatformVersion", resourceCulture); } } - + /// /// Looks up a localized string similar to AndroidManifest.xml //uses-sdk/@android:targetSdkVersion '{0}' is less than API-{1}, this configuration is not supported.. /// @@ -997,7 +1072,7 @@ public static string XA4216_TargetSdkVersion { return ResourceManager.GetString("XA4216_TargetSdkVersion", resourceCulture); } } - + /// /// Looks up a localized string similar to Unable to find //manifest/application/uses-library at path: {0}. /// @@ -1006,7 +1081,7 @@ public static string XA4218 { return ResourceManager.GetString("XA4218", resourceCulture); } } - + /// /// Looks up a localized string similar to Cannot find binding generator for language {0} or {1}.. /// @@ -1015,7 +1090,7 @@ public static string XA4219 { return ResourceManager.GetString("XA4219", resourceCulture); } } - + /// /// Looks up a localized string similar to Partial class item '{0}' does not have an associated binding for layout '{1}'.. /// @@ -1024,7 +1099,7 @@ public static string XA4220 { return ResourceManager.GetString("XA4220", resourceCulture); } } - + /// /// Looks up a localized string similar to No layout binding source files were generated.. /// @@ -1033,7 +1108,7 @@ public static string XA4221 { return ResourceManager.GetString("XA4221", resourceCulture); } } - + /// /// Looks up a localized string similar to No widgets found for layout ({0}).. /// @@ -1042,7 +1117,7 @@ public static string XA4222 { return ResourceManager.GetString("XA4222", resourceCulture); } } - + /// /// Looks up a localized string similar to Malformed full class name '{0}'. Missing namespace.. /// @@ -1051,7 +1126,7 @@ public static string XA4223 { return ResourceManager.GetString("XA4223", resourceCulture); } } - + /// /// Looks up a localized string similar to Malformed full class name '{0}'. Missing class name.. /// @@ -1060,7 +1135,7 @@ public static string XA4224 { return ResourceManager.GetString("XA4224", resourceCulture); } } - + /// /// Looks up a localized string similar to Widget '{0}' in layout '{1}' has multiple instances with different types. The property type will be set to: {2}. /// @@ -1069,7 +1144,7 @@ public static string XA4225 { return ResourceManager.GetString("XA4225", resourceCulture); } } - + /// /// Looks up a localized string similar to Resource item '{0}' does not have the required metadata item '{1}'.. /// @@ -1078,7 +1153,7 @@ public static string XA4226 { return ResourceManager.GetString("XA4226", resourceCulture); } } - + /// /// Looks up a localized string similar to Unable to find specified //activity-alias/@android:targetActivity: '{0}'. /// @@ -1087,7 +1162,7 @@ public static string XA4228 { return ResourceManager.GetString("XA4228", resourceCulture); } } - + /// /// Looks up a localized string similar to Unrecognized `TransformFile` root element: {0}.. /// @@ -1096,7 +1171,7 @@ public static string XA4229 { return ResourceManager.GetString("XA4229", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing XML: {0}. /// @@ -1105,25 +1180,25 @@ public static string XA4230 { return ResourceManager.GetString("XA4230", resourceCulture); } } - + /// - /// Looks up a localized string similar to The Android class parser value '{0}' is deprecated and will be removed in a future version of Xamarin.Android. Update the project properties to use 'class-parse'.. + /// Looks up a localized string similar to The Android class parser value '{0}' is deprecated and will be removed in a future version of .NET Android. Update the project properties to use 'class-parse'.. /// public static string XA4231 { get { return ResourceManager.GetString("XA4231", resourceCulture); } } - + /// - /// Looks up a localized string similar to The Android code generation target '{0}' is deprecated and will be removed in a future version of Xamarin.Android. Update the project properties to use 'XAJavaInterop1'.. + /// Looks up a localized string similar to The Android code generation target '{0}' is deprecated and will be removed in a future version of .NET Android. Update the project properties to use 'XAJavaInterop1'.. /// public static string XA4232 { get { return ResourceManager.GetString("XA4232", resourceCulture); } } - + /// /// Looks up a localized string similar to The <AndroidNamespaceReplacement> for '{0}' does not specify a 'Replacement' attribute.. /// @@ -1163,8 +1238,8 @@ public static string XA4236 { } /// - /// Looks up a localized string similar to Cannot download POM file for Maven artifact '{0}:{1}'. - ///- {2}: {3}. + /// Looks up a localized string similar to Cannot download POM file for Maven artifact '{0}'. + ///- {1}. /// public static string XA4237 { get { @@ -1199,7 +1274,7 @@ public static string XA4300 { return ResourceManager.GetString("XA4300", resourceCulture); } } - + /// /// Looks up a localized string similar to APK already contains the item {0}; ignoring.. /// @@ -1208,7 +1283,7 @@ public static string XA4301 { return ResourceManager.GetString("XA4301", resourceCulture); } } - + /// /// Looks up a localized string similar to Cannot determine ABI of native library '{0}'. Move this file to a directory with a valid Android ABI name such as 'libs/armeabi-v7a/'.. /// @@ -1217,7 +1292,7 @@ public static string XA4301_ABI { return ResourceManager.GetString("XA4301_ABI", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not determine ABI of some native libraries. Ignoring those: {0}. /// @@ -1226,7 +1301,7 @@ public static string XA4301_ABI_Ignoring { return ResourceManager.GetString("XA4301_ABI_Ignoring", resourceCulture); } } - + /// /// Looks up a localized string similar to Cannot determine ABI of native library '{0}'. Remove the '{1}' NuGet package, or notify the library author.. /// @@ -1235,7 +1310,7 @@ public static string XA4301_ABI_NuGet { return ResourceManager.GetString("XA4301_ABI_NuGet", resourceCulture); } } - + /// /// Looks up a localized string similar to Unhandled exception merging `AndroidManifest.xml`: {0}. /// @@ -1244,7 +1319,7 @@ public static string XA4302 { return ResourceManager.GetString("XA4302", resourceCulture); } } - + /// /// Looks up a localized string similar to Error extracting resources from "{0}": {1}. /// @@ -1253,7 +1328,7 @@ public static string XA4303 { return ResourceManager.GetString("XA4303", resourceCulture); } } - + /// /// Looks up a localized string similar to ProGuard configuration file '{0}' was not found.. /// @@ -1262,7 +1337,7 @@ public static string XA4304 { return ResourceManager.GetString("XA4304", resourceCulture); } } - + /// /// Looks up a localized string similar to Multidex is enabled, but `$(_AndroidMainDexListFile)` is empty.. /// @@ -1271,7 +1346,7 @@ public static string XA4305 { return ResourceManager.GetString("XA4305", resourceCulture); } } - + /// /// Looks up a localized string similar to Multidex is enabled, but the `$(_AndroidMainDexListFile)` file '{0}' does not exist.. /// @@ -1280,7 +1355,7 @@ public static string XA4305_File_Missing { return ResourceManager.GetString("XA4305_File_Missing", resourceCulture); } } - + /// /// Looks up a localized string similar to R8 does not support `@(MultiDexMainDexList)` files when android:minSdkVersion >= 21. /// @@ -1289,7 +1364,7 @@ public static string XA4306 { return ResourceManager.GetString("XA4306", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid ProGuard configuration file. {0}. /// @@ -1298,7 +1373,7 @@ public static string XA4307 { return ResourceManager.GetString("XA4307", resourceCulture); } } - + /// /// Looks up a localized string similar to Failed to generate type maps. /// @@ -1307,7 +1382,7 @@ public static string XA4308 { return ResourceManager.GetString("XA4308", resourceCulture); } } - + /// /// Looks up a localized string similar to 'MultiDexMainDexList' file '{0}' does not exist.. /// @@ -1316,7 +1391,7 @@ public static string XA4309 { return ResourceManager.GetString("XA4309", resourceCulture); } } - + /// /// Looks up a localized string similar to `{0}` file `{1}` could not be found.. /// @@ -1325,7 +1400,7 @@ public static string XA4310 { return ResourceManager.GetString("XA4310", resourceCulture); } } - + /// /// Looks up a localized string similar to The application won't contain the paired Wear package because the Wear application package APK is not created yet. If building on the command line, be sure to build the "SignAndroidPackage" target.. /// @@ -1334,16 +1409,16 @@ public static string XA4311 { return ResourceManager.GetString("XA4311", resourceCulture); } } - + /// - /// Looks up a localized string similar to Referencing the Android Wear application project '{0}' from an Android application project is deprecated and will no longer be supported in a future version of Xamarin.Android. Remove the Android Wear application project reference from the Android application project and distribute the Wear application as a standalone application instead.. + /// Looks up a localized string similar to Referencing the Android Wear application project '{0}' from an Android application project is deprecated and will no longer be supported in a future version of .NET Android. Remove the Android Wear application project reference from the Android application project and distribute the Wear application as a standalone application instead.. /// public static string XA4312 { get { return ResourceManager.GetString("XA4312", resourceCulture); } } - + /// /// Looks up a localized string similar to The built-in '{0}' reference has been deprecated. ///Remove the '{0}' reference from your project and add the '{1}' NuGet package instead. @@ -1354,7 +1429,7 @@ public static string XA4313 { return ResourceManager.GetString("XA4313", resourceCulture); } } - + /// /// Looks up a localized string similar to `{0}` is empty. A value for `{0}` should be provided.. /// @@ -1363,7 +1438,7 @@ public static string XA4314 { return ResourceManager.GetString("XA4314", resourceCulture); } } - + /// /// Looks up a localized string similar to Missing Android NDK toolchains directory '{0}'. Please install the Android NDK.. /// @@ -1372,7 +1447,7 @@ public static string XA5101 { return ResourceManager.GetString("XA5101", resourceCulture); } } - + /// /// Looks up a localized string similar to C compiler for target {0} was not found. Tried paths: "{1}". /// @@ -1381,7 +1456,7 @@ public static string XA5101_C_Compiler { return ResourceManager.GetString("XA5101_C_Compiler", resourceCulture); } } - + /// /// Looks up a localized string similar to Toolchain directory for target {0} was not found.. /// @@ -1390,7 +1465,7 @@ public static string XA5101_Toolchain { return ResourceManager.GetString("XA5101_Toolchain", resourceCulture); } } - + /// /// Looks up a localized string similar to Conversion from assembly to native code failed. Exit code {0}. /// @@ -1399,7 +1474,7 @@ public static string XA5102 { return ResourceManager.GetString("XA5102", resourceCulture); } } - + /// /// Looks up a localized string similar to NDK C compiler exited with an error. Exit code {0}. /// @@ -1408,7 +1483,7 @@ public static string XA5103 { return ResourceManager.GetString("XA5103", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not locate the Android NDK. Please make sure the Android NDK is installed in the Android SDK Manager, or if using a custom NDK path, please ensure the $(AndroidNdkDirectory) MSBuild property is set to the custom path.. /// @@ -1417,7 +1492,7 @@ public static string XA5104 { return ResourceManager.GetString("XA5104", resourceCulture); } } - + /// /// Looks up a localized string similar to Toolchain utility '{0}' for target {1} was not found. Tried in path: "{2}". /// @@ -1426,7 +1501,7 @@ public static string XA5105 { return ResourceManager.GetString("XA5105", resourceCulture); } } - + /// /// Looks up a localized string similar to NDK linker exited with an error. Exit code {0}. /// @@ -1435,7 +1510,7 @@ public static string XA5201 { return ResourceManager.GetString("XA5201", resourceCulture); } } - + /// /// Looks up a localized string similar to Cannot find `{0}`. Please install the Android SDK Build-Tools package with the `{1}{2}tools{2}{3}` program.. /// @@ -1444,7 +1519,7 @@ public static string XA5205 { return ResourceManager.GetString("XA5205", resourceCulture); } } - + /// /// Looks up a localized string similar to Cannot find `{0}` in the Android SDK. Please set its path via /p:LintToolPath.. /// @@ -1453,34 +1528,36 @@ public static string XA5205_Lint { return ResourceManager.GetString("XA5205_Lint", resourceCulture); } } - + /// - /// Looks up a localized string similar to Could not find android.jar for API level {0}. This means the Android SDK platform for API level {0} is not installed. Either install it in the Android SDK Manager ({2}), or change the Xamarin.Android project to target an API version that is installed. ({1} missing.). + /// Looks up a localized string similar to Could not find android.jar for API level {0}. This means the Android SDK platform for API level {0} is not installed; it was expected to be in `{1}`. + ///{2} + ///See https://aka.ms/xa5207 for more details.. /// public static string XA5207 { get { return ResourceManager.GetString("XA5207", resourceCulture); } } - + /// - /// Looks up a localized string similar to Tools > Android > Android SDK Manager.... + /// Looks up a localized string similar to You can install the missing API level by running `dotnet build -t:InstallAndroidDependencies -f {0} "-p:AndroidSdkDirectory={1}"`, or change the project to target an API version that is installed.. /// - public static string XA5207_SDK_Manager_Windows { + public static string XA5207_SDK_Manager_CLI { get { - return ResourceManager.GetString("XA5207_SDK_Manager_Windows", resourceCulture); + return ResourceManager.GetString("XA5207_SDK_Manager_CLI", resourceCulture); } } - + /// - /// Looks up a localized string similar to Tools > Open Android SDK Manager.... + /// Looks up a localized string similar to Either install it in the Android SDK Manager (Tools > Android > Android SDK Manager...), or change the .NET Android project to target an API version that is installed.. /// - public static string XA5207_SDK_Manager_CLI { + public static string XA5207_SDK_Manager_Windows { get { - return ResourceManager.GetString("XA5207_SDK_Manager_CLI", resourceCulture); + return ResourceManager.GetString("XA5207_SDK_Manager_Windows", resourceCulture); } } - + /// /// Looks up a localized string similar to Embedded Wear app package name differs from handheld app package name ({0} != {1}).. /// @@ -1489,7 +1566,7 @@ public static string XA5211 { return ResourceManager.GetString("XA5211", resourceCulture); } } - + /// /// Looks up a localized string similar to java.lang.OutOfMemoryError. Consider increasing the value of $(JavaMaximumHeapSize). Java ran out of memory while executing '{0} {1}'. /// @@ -1498,7 +1575,7 @@ public static string XA5213 { return ResourceManager.GetString("XA5213", resourceCulture); } } - + /// /// Looks up a localized string similar to No Android platforms installed at '{0}'. Please install an SDK Platform with the `{1}{2}tools{2}{3}` program.. /// @@ -1507,25 +1584,27 @@ public static string XA5300_Android_Platforms { return ResourceManager.GetString("XA5300_Android_Platforms", resourceCulture); } } - + /// - /// Looks up a localized string similar to The Android SDK directory could not be found. Check that the Android SDK Manager in Visual Studio shows a valid installation. To use a custom SDK path for a command line build, set the 'AndroidSdkDirectory' MSBuild property to the custom path.. + /// Looks up a localized string similar to The Android SDK directory could not be found. Install the Android SDK by following the instructions at: https://aka.ms/dotnet-android-install-sdk + ///To use a custom SDK path for a command line build, set the 'AndroidSdkDirectory' MSBuild property to the custom path.. /// public static string XA5300_Android_SDK { get { return ResourceManager.GetString("XA5300_Android_SDK", resourceCulture); } } - + /// - /// Looks up a localized string similar to The Java SDK directory could not be found. Ensure that the Android section of the Visual Studio options has a valid Java SDK directory configured. To use a custom SDK path for a command line build, set the 'JavaSdkDirectory' MSBuild property to the custom path.. + /// Looks up a localized string similar to The Java SDK directory could not be found. Install the Java SDK by following the instructions at: https://aka.ms/dotnet-android-install-sdk + ///To use a custom JDK path for a command line build, set the 'JavaSdkDirectory' MSBuild property to the custom path.. /// public static string XA5300_Java_SDK { get { return ResourceManager.GetString("XA5300_Java_SDK", resourceCulture); } } - + /// /// Looks up a localized string similar to Failed to generate Java type for class: {0} due to MAX_PATH: {1}. /// @@ -1534,7 +1613,7 @@ public static string XA5301 { return ResourceManager.GetString("XA5301", resourceCulture); } } - + /// /// Looks up a localized string similar to Two processes may be building this project at once. Lock file exists at path: {0}. /// @@ -1543,61 +1622,13 @@ public static string XA5302 { return ResourceManager.GetString("XA5302", resourceCulture); } } - - /// - /// Looks up a localized string similar to The 'AndroidHttpClientHandlerType' property value '{0}' must derive from '{1}'. - ///Please change the value to an assembly-qualifed type name which inherits from '{1}' or remove the property completely. - /// - public static string XA1031 { - get { - return ResourceManager.GetString("XA1031", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The 'AndroidHttpClientHandlerType' property value '{0}' must not derive from 'System.Net.Htt.HttpClientHandler'. - ///Please change the value to an assembly-qualifed type name which inherits from 'System.Net.Http.HttpMessageHandler' or remove the property completely. - /// - public static string XA1031_HCH { - get { - return ResourceManager.GetString("XA1031_HCH", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Two processes may be building this project at once. Lock file exists at path: {0}. - /// - public static string XA1032 { - get { - return ResourceManager.GetString("XA1032", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Two processes may be building this project at once. Lock file exists at path: {0}. - /// - public static string XA1033 { - get { - return ResourceManager.GetString("XA1033", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Your project references '{0}' which uses the `_Microsoft.Android.Resource.Designer` assembly, but you do not have this feature enabled. Please set the `AndroidUseDesignerAssembly` MSBuild property to `true` in your project file. - /// - public static string XA1034 { - get { - return ResourceManager.GetString("XA1034", resourceCulture); - } - } - + /// - /// Looks up a localized string similar to AndroidManifest.xml //uses-sdk/@android:minSdkVersion '{0}' does not match the $(SupportedOSPlatformVersion) value '{1}' in the project file (if there is no $(SupportedOSPlatformVersion) value in the project file, then a default value has been assumed). - ///Either change the value in the AndroidManifest.xml to match the $(SupportedOSPlatformVersion) value, or remove the value in the AndroidManifest.xml (and add a $(SupportedOSPlatformVersion) value to the project file if it doesn't already exist).. + /// Looks up a localized string similar to Could not find Android Resource '{0}'. Please update @(AndroidResource) to add the missing resource.. /// - public static string XA1036 { + public static string XA8000 { get { - return ResourceManager.GetString("XA1036", resourceCulture); + return ResourceManager.GetString("XA8000", resourceCulture); } } diff --git a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx index f473cd0f265..b2abaf6d1a3 100644 --- a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx +++ b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx @@ -991,13 +991,11 @@ To use a custom JDK path for a command line build, set the 'JavaSdkDirectory' MS {5} - The HttpClient provided download exception message - Cannot download POM file for Maven artifact '{0}:{1}'. -- {2}: {3} + Cannot download POM file for Maven artifact '{0}'. +- {1} The following are literal names and should not be translated: POM, Maven -{0} - Maven artifact group id -{1} - Maven artifact id -{2} - The .pom filename we tried to download -{3} - The HttpClient reported download exception message +{0} - Maven artifact id +{1} - The HttpClient reported download exception message diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GetMicrosoftNuGetPackagesMap.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GetMicrosoftNuGetPackagesMap.cs index 253549158d5..df08a6edeb3 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GetMicrosoftNuGetPackagesMap.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GetMicrosoftNuGetPackagesMap.cs @@ -5,6 +5,9 @@ using Microsoft.Build.Framework; using Microsoft.Android.Build.Tasks; using System.Net.Http; +using System.Diagnostics.CodeAnalysis; +using System.Collections.Generic; +using System.Linq; namespace Xamarin.Android.Tasks; @@ -21,26 +24,88 @@ public class GetMicrosoftNuGetPackagesMap : AndroidAsyncTask [Output] public string? ResolvedPackageMap { get; set; } - public async override System.Threading.Tasks.Task RunTaskAsync () + public override async System.Threading.Tasks.Task RunTaskAsync () { - // TODO: We should check the age of the existing file and only download if it's too old - var outfile = Path.Combine (MavenCacheDirectory, "microsoft-packages.json"); + Directory.CreateDirectory (MavenCacheDirectory); - if (File.Exists (outfile)) { - ResolvedPackageMap = outfile; - return; + // We're going to store the resolved package map in the cache directory as + // "microsoft-packages-{YYYYMMDD}.json". If the file is older than today, + // we'll try to download a new one. + var all_files = PackagesFile.FindAll (MavenCacheDirectory); + + if (!all_files.Any (x => x.IsToday)) { + // No file for today, download a new one + try { + var http = new HttpClient (); + var json = await http.GetStringAsync ("https://aka.ms/ms-nuget-packages"); + var outfile = Path.Combine (MavenCacheDirectory, $"microsoft-packages-{DateTime.Today:yyyyMMdd}.json"); + + File.WriteAllText (outfile, json); + + if (PackagesFile.TryParse (outfile, out var packagesFile)) + all_files.Insert (0, packagesFile); // Sorted so this one is first + + } catch (Exception ex) { + Log.LogMessage ("Could not download microsoft-packages.json: {0}", ex.Message); + } } - // File missing, download new one - try { - var http = new HttpClient (); - var json = await http.GetStringAsync ("https://aka.ms/ms-nuget-packages"); + // Delete all files but the latest + foreach (var file in all_files.Skip (1)) { + try { + File.Delete (Path.Combine (MavenCacheDirectory, file.FileName)); + } catch { + // Ignore exceptions + } + } + + ResolvedPackageMap = all_files.FirstOrDefault ()?.FileName; + } +} + +class PackagesFile +{ + public string FileName { get; } + public DateTime DownloadDate { get; } + public bool IsToday => DownloadDate == DateTime.Today; + + PackagesFile (string filename, DateTime downloadDate) + { + FileName = filename; + DownloadDate = downloadDate; + } + + public static List FindAll (string directory) + { + var files = new List (); - File.WriteAllText (outfile, json); - ResolvedPackageMap = outfile; - } catch (Exception ex) { - Log.LogMessage ("Could not download microsoft-packages.json: {0}", ex); + foreach (var file in Directory.GetFiles (directory, "microsoft-packages-*.json")) { + if (TryParse (file, out var packagesFile)) + files.Add (packagesFile); } + + files.OrderByDescending (x => x.DownloadDate); + + return files; + } + + public static bool TryParse (string filepath, [NotNullWhen (true)]out PackagesFile? file) + { + file = default; + + var filename = Path.GetFileNameWithoutExtension (filepath); + + if (!filename.StartsWith ("microsoft-packages-", StringComparison.OrdinalIgnoreCase)) + return false; + + var date = filename.Substring ("microsoft-packages-".Length); + + if (!DateTime.TryParseExact (date, "yyyyMMdd", null, System.Globalization.DateTimeStyles.None, out var downloadDate)) + return false; + + file = new PackagesFile (filepath, downloadDate); + + return true; } } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs b/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs index 19bb29d87da..2113ca6af6b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs @@ -5,10 +5,9 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; -using System.Runtime.InteropServices.ComTypes; using System.Text.RegularExpressions; -using Java.Interop.Maven; -using Java.Interop.Maven.Models; +using Java.Interop.Tools.Maven; +using Java.Interop.Tools.Maven.Models; using Microsoft.Android.Build.Tasks; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; @@ -172,7 +171,7 @@ public void AddAndroidLibraries (ITaskItem []? tasks) if (!id.HasValue () || !version.HasValue ()) continue; - if (version != null && MavenExtensions.TryParseArtifact (id, version, log, out var art)) { + if (version != null && MavenExtensions.TryParseArtifactWithVersion (id, version, log, out var art)) { log.LogMessage ("Found Java dependency '{0}:{1}' version '{2}' from AndroidLibrary '{3}'", art.GroupId, art.Id, art.Version, task.ItemSpec); artifacts.Add (art); } @@ -222,7 +221,7 @@ public void AddIgnoredDependencies (ITaskItem []? tasks) if (version is null) continue; - if (version != null && MavenExtensions.TryParseArtifact (id, version, log, out var art)) { + if (version != null && MavenExtensions.TryParseArtifactWithVersion (id, version, log, out var art)) { log.LogMessage ("Ignoring Java dependency '{0}:{1}' version '{2}'", art.GroupId, art.Id, art.Version); artifacts.Add (art); } @@ -267,7 +266,7 @@ bool TryParseJavaArtifactAndVersion (string type, ITaskItem task) return true; } - if (MavenExtensions.TryParseArtifact (id, version, log, out var art)) { + if (MavenExtensions.TryParseArtifactWithVersion (id, version, log, out var art)) { log.LogMessage ("Found Java dependency '{0}:{1}' version '{2}' from {3} '{4}' (JavaArtifact)", art.GroupId, art.Id, art.Version, type, item_name); artifacts.Add (art); } @@ -307,27 +306,6 @@ public MSBuildLoggingPomResolver (TaskLoggingHelper logger) this.logger = logger; } - Artifact? Register (string filename) - { - if (!File.Exists (filename)) { - logger.LogError ("Requested POM file '{0}' does not exist.", filename); - return null; - } - - try { - using (var file = File.OpenRead (filename)) { - var project = Project.Parse (file); - poms.Add (project.ToString (), project); - - logger.LogDebugMessage ("Registered POM for artifact '{0}' from '{1}'", project, filename); - return Artifact.Parse (project.ToString ()); - } - } catch (Exception ex) { - logger.LogError ("Failed to register POM file '{0}': '{1}'", filename, ex); - return null; - } - } - public Artifact? RegisterFromAndroidLibrary (ITaskItem item) { var pom_file = item.GetMetadata ("Manifest"); @@ -343,7 +321,7 @@ public MSBuildLoggingPomResolver (TaskLoggingHelper logger) Artifact? RegisterFromTaskItem (ITaskItem item, string itemName, string filename) { - item.TryParseJavaArtifactAndVersion (itemName, logger, out var artifact); + item.TryParseJavaArtifactAndJavaVersion (itemName, logger, out var artifact); if (!File.Exists (filename)) { logger.LogError ("Requested POM file '{0}' does not exist.", filename); @@ -362,7 +340,8 @@ public MSBuildLoggingPomResolver (TaskLoggingHelper logger) artifact?.Version ?? registered_artifact.Version ); - poms.Add (final_artifact.ToString (), project); + // Use index instead of Add to handle duplicates + poms [final_artifact.ToString ()] = project; logger.LogDebugMessage ("Registered POM for artifact '{0}' from '{1}'", final_artifact, filename); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs b/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs index 4ad90bbb275..2197c573f08 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs @@ -2,9 +2,13 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; -using MavenNet; -using MavenNet.Models; +using System.Security.Cryptography; +using System.Text; +using Java.Interop.Tools.Maven; +using Java.Interop.Tools.Maven.Models; +using Java.Interop.Tools.Maven.Repositories; using Microsoft.Android.Build.Tasks; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; @@ -32,11 +36,18 @@ public class MavenDownload : AndroidAsyncTask [Output] public ITaskItem []? ResolvedAndroidMavenLibraries { get; set; } + /// + /// The set of additional parent and imported POM files needed to verify these Maven libraries. + /// + [Output] + public ITaskItem []? AndroidAdditionalJavaManifest { get; set; } + public async override System.Threading.Tasks.Task RunTaskAsync () { var resolved = new List (); + var additional_poms = new List (); - // Note each called function is responsible for raising any errors it encounters to the user + // Note each called function is responsible for reporting any errors it encounters to the user foreach (var library in AndroidMavenLibraries.OrEmpty ()) { // Validate artifact @@ -45,14 +56,12 @@ public async override System.Threading.Tasks.Task RunTaskAsync () if (version is null) continue; - - var artifact = MavenExtensions.ParseArtifact (id, version, Log); - - if (artifact is null) + + if (!MavenExtensions.TryParseArtifactWithVersion (id, version, Log, out var artifact)) continue; // Check for repository files - if (await GetRepositoryArtifactOrDefault (artifact, library, Log) is TaskItem result) { + if (await GetRepositoryArtifactOrDefault (artifact, library, additional_poms) is TaskItem result) { library.CopyMetadataTo (result); resolved.Add (result); continue; @@ -60,9 +69,10 @@ public async override System.Threading.Tasks.Task RunTaskAsync () } ResolvedAndroidMavenLibraries = resolved.ToArray (); + AndroidAdditionalJavaManifest = additional_poms.ToArray (); } - async System.Threading.Tasks.Task GetRepositoryArtifactOrDefault (Artifact artifact, ITaskItem item, TaskLoggingHelper log) + async System.Threading.Tasks.Task GetRepositoryArtifactOrDefault (Artifact artifact, ITaskItem item, List additionalPoms) { // Handles a Repository="Central|Google|" entry, like: // TryGetParentPom (ITaskItem item, TaskLoggingHelper log) - { - var child_pom_file = item.GetRequiredMetadata ("AndroidMavenLibrary", "ArtifactPom", Log); + // Resolve and download POM, and any parent or imported POMs + try { + var resolver = new LoggingPomResolver (repository); + var project = ResolvedProject.FromArtifact (artifact, resolver); - // Shouldn't be possible because we just created this items - if (child_pom_file is null) - return null; + // Set the POM file path for _this_ artifact + var primary_pom = resolver.ResolvedPoms [artifact.ToString ()]; + result.SetMetadata ("Manifest", primary_pom); - // No parent POM needed - if (!(MavenExtensions.CheckForNeededParentPom (child_pom_file) is Artifact artifact)) - return null; + Log.LogMessage ("Found POM file '{0}' for Java artifact '{1}'.", primary_pom, artifact); - // Initialize repo (parent will be in same repository as child) - var repository = GetRepository (item); + // Create TaskItems for any other POMs we resolved + foreach (var kv in resolver.ResolvedPoms.Where (k => k.Key != artifact.ToString ())) { - if (repository is null) - return null; + var pom_item = new TaskItem (kv.Value); + var pom_artifact = Artifact.Parse (kv.Key); - artifact.Repository = repository; + pom_item.SetMetadata ("JavaArtifact", $"{pom_artifact.GroupId}:{pom_artifact.Id}"); + pom_item.SetMetadata ("JavaVersion", pom_artifact.Version); - // Download POM - var pom_file = await MavenExtensions.DownloadPom (artifact, MavenCacheDirectory, Log, CancellationToken); + additionalPoms.Add (pom_item); - if (pom_file is null) + Log.LogMessage ("Found POM file '{0}' for Java artifact '{1}'.", kv.Value, pom_artifact); + } + } catch (Exception ex) { + Log.LogCodedError ("XA4237", Properties.Resources.XA4237, artifact, ex.Unwrap ().Message); return null; - - var result = new TaskItem ($"{artifact.GroupId}:{artifact.Id}"); - - result.SetMetadata ("Version", artifact.Versions.FirstOrDefault ()); - result.SetMetadata ("ArtifactPom", pom_file); - - // Copy repository data - item.CopyMetadataTo (result); + } return result; } - MavenRepository? GetRepository (ITaskItem item) + CachedMavenRepository? GetRepository (ITaskItem item) { var type = item.GetMetadataOrDefault ("Repository", "Central"); var repo = type.ToLowerInvariant () switch { - "central" => MavenRepository.FromMavenCentral (), - "google" => MavenRepository.FromGoogle (), - _ => (MavenRepository?) null + "central" => MavenRepository.Central, + "google" => MavenRepository.Google, + _ => null }; - if (repo is null && type.StartsWith ("http", StringComparison.OrdinalIgnoreCase)) - repo = MavenRepository.FromUrl (type); + if (repo is null && type.StartsWith ("http", StringComparison.OrdinalIgnoreCase)) { + using var hasher = SHA256.Create (); + var hash = hasher.ComputeHash (Encoding.UTF8.GetBytes (type)); + var cache_name = Convert.ToBase64String (hash); + + repo = new MavenRepository (type, cache_name); + } if (repo is null) Log.LogCodedError ("XA4239", Properties.Resources.XA4239, type); - return repo; + return repo is not null ? new CachedMavenRepository (MavenCacheDirectory, repo) : null; + } +} + +// This wrapper around CachedMavenRepository is used to log the POMs that are resolved. +// We need these on-disk file locations so we can pass them as items. +class LoggingPomResolver : IPomResolver +{ + readonly CachedMavenRepository repository; + + public Dictionary ResolvedPoms { get; } = new Dictionary (); + + public LoggingPomResolver (CachedMavenRepository repository) + { + this.repository = repository; + } + + public Project ResolveRawProject (Artifact artifact) + { + if (repository.TryGetFilePath (artifact, $"{artifact.Id}-{artifact.Version}.pom", out var path)) { + using (var stream = File.OpenRead (path)) { + var pom = Project.Parse (stream) ?? throw new InvalidOperationException ($"Could not deserialize POM for {artifact}"); + + // Use index instead of Add to handle duplicates + ResolvedPoms [artifact.ToString ()] = path; + + return pom; + } + } + + throw new InvalidOperationException ($"No POM found for {artifact}"); } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs index d4e24312561..f5b1d239f27 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BindingBuildTest.cs @@ -791,5 +791,103 @@ public void AndroidMavenLibrary () FileAssert.Exists (cs_file); } } + + [Test] + public void AndroidMavenLibrary_FailsDueToUnverifiedDependency () + { + // Test that triggers Java dependency verification + // + var item = new BuildItem ("AndroidMavenLibrary", "androidx.core:core"); + item.Metadata.Add ("Version", "1.9.0"); + item.Metadata.Add ("Repository", "Google"); + + var proj = new XamarinAndroidBindingProject { + Jars = { item } + }; + + using (var b = CreateDllBuilder ()) { + b.ThrowOnBuildFailure = false; + Assert.IsFalse (b.Build (proj), "Build should have failed."); + + // Ensure an error was raised + StringAssertEx.Contains ("error : Java dependency 'androidx.annotation:annotation' version '1.2.0' is not satisfied.", b.LastBuildOutput); + } + } + + [Test] + public void AndroidMavenLibrary_IgnoreDependencyVerification () + { + // Test that ignores Java dependency verification + // + var item = new BuildItem ("AndroidMavenLibrary", "androidx.core:core"); + item.Metadata.Add ("Version", "1.9.0"); + item.Metadata.Add ("Repository", "Google"); + item.Metadata.Add ("VerifyDependencies", "false"); + item.Metadata.Add ("Bind", "false"); + + var proj = new XamarinAndroidBindingProject { + Jars = { item } + }; + + using (var b = CreateDllBuilder ()) { + Assert.IsTrue (b.Build (proj), "Build should have succeeded."); + } + } + + [Test] + public void AndroidMavenLibrary_AllDependenciesAreVerified () + { + // Test that triggers Java dependency verification and that + // all dependencies are verified via various supported mechanisms + + // + var item = new BuildItem ("AndroidMavenLibrary", "androidx.core:core"); + item.Metadata.Add ("Version", "1.9.0"); + item.Metadata.Add ("Repository", "Google"); + item.Metadata.Add ("Bind", "false"); + + // Dependency fulfilled by + var annotations_nuget = new Package { + Id = "Xamarin.AndroidX.Annotation", + Version = "1.7.0.3" + }; + + // Dependency fulfilled by + var annotations_experimental_androidlib = new BuildItem ("AndroidMavenLibrary", "androidx.annotation:annotation-experimental"); + annotations_experimental_androidlib.Metadata.Add ("Version", "1.3.0"); + annotations_experimental_androidlib.Metadata.Add ("Repository", "Google"); + annotations_experimental_androidlib.Metadata.Add ("Bind", "false"); + annotations_experimental_androidlib.Metadata.Add ("VerifyDependencies", "false"); + + // Dependency fulfilled by + var collection = new XamarinAndroidBindingProject (); + + // Dependencies ignored by + var concurrent = new BuildItem ("AndroidIgnoredJavaDependency", "androidx.concurrent:concurrent-futures"); + concurrent.Metadata.Add ("Version", "1.1.0"); + + var lifecycle = new BuildItem ("AndroidIgnoredJavaDependency", "androidx.lifecycle:lifecycle-runtime"); + lifecycle.Metadata.Add ("Version", "2.6.2"); + + var parcelable = new BuildItem ("AndroidIgnoredJavaDependency", "androidx.versionedparcelable:versionedparcelable"); + parcelable.Metadata.Add ("Version", "1.2.0"); + + var proj = new XamarinAndroidBindingProject { + Jars = { item, annotations_experimental_androidlib }, + PackageReferences = { annotations_nuget }, + OtherBuildItems = { concurrent, lifecycle, parcelable }, + }; + + proj.AddReference (collection); + var collection_proj = proj.References.First (); + collection_proj.Metadata.Add ("JavaArtifact", "androidx.collection:collection"); + collection_proj.Metadata.Add ("JavaVersion", "1.3.0"); + + using var a = CreateDllBuilder (); + using var b = CreateDllBuilder (); + + Assert.IsTrue (a.Build (proj), "ProjectReference build should have succeeded."); + Assert.IsTrue (b.Build (proj), "Build should have succeeded."); + } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetMicrosoftNuGetPackagesMapTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetMicrosoftNuGetPackagesMapTests.cs new file mode 100644 index 00000000000..c07a33bdc1c --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetMicrosoftNuGetPackagesMapTests.cs @@ -0,0 +1,158 @@ +#nullable enable + +using System; +using System.IO; +using System.Threading.Tasks; +using NUnit.Framework; +using Xamarin.Android.Tasks; + +namespace Xamarin.Android.Build.Tests +{ + public class GetMicrosoftNuGetPackagesMapTests + { + [Test] + public async Task NoCachedFile () + { + var engine = new MockBuildEngine (TestContext.Out, []); + var temp_cache_dir = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ()); + var today_file = Path.Combine (temp_cache_dir, $"microsoft-packages-{DateTime.Today:yyyyMMdd}.json"); + + try { + var task = new GetMicrosoftNuGetPackagesMap { + BuildEngine = engine, + MavenCacheDirectory = temp_cache_dir, + }; + + await task.RunTaskAsync (); + + Assert.AreEqual (0, engine.Errors.Count); + Assert.AreEqual (today_file, task.ResolvedPackageMap); + Assert.IsTrue (File.Exists (today_file)); + + } finally { + MavenDownloadTests.DeleteTempDirectory (temp_cache_dir); + } + } + + [Test] + public async Task CachedTodayFile () + { + // If a file already exists for today, it should be used and nothing new should be downloaded + var engine = new MockBuildEngine (TestContext.Out, []); + var temp_cache_dir = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ()); + var today_file = Path.Combine (temp_cache_dir, $"microsoft-packages-{DateTime.Today:yyyyMMdd}.json"); + + try { + Directory.CreateDirectory (temp_cache_dir); + File.WriteAllText (today_file, "dummy file"); + + var task = new GetMicrosoftNuGetPackagesMap { + BuildEngine = engine, + MavenCacheDirectory = temp_cache_dir, + }; + + await task.RunTaskAsync (); + + Assert.AreEqual (0, engine.Errors.Count); + Assert.AreEqual (today_file, task.ResolvedPackageMap); + Assert.IsTrue (File.Exists (today_file)); + + // Ensure file didn't change + var text = File.ReadAllText (today_file); + Assert.AreEqual ("dummy file", text); + + } finally { + MavenDownloadTests.DeleteTempDirectory (temp_cache_dir); + } + } + + [Test] + public async Task CachedYesterdayFile () + { + // If a file only exists for yesterday, a new one should be downloaded and the old one should be deleted + var engine = new MockBuildEngine (TestContext.Out, []); + var temp_cache_dir = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ()); + var yesterday_file = Path.Combine (temp_cache_dir, $"microsoft-packages-{DateTime.Today.AddDays (-1):yyyyMMdd}.json"); + var today_file = Path.Combine (temp_cache_dir, $"microsoft-packages-{DateTime.Today:yyyyMMdd}.json"); + + try { + Directory.CreateDirectory (temp_cache_dir); + File.WriteAllText (yesterday_file, "dummy file"); + + var task = new GetMicrosoftNuGetPackagesMap { + BuildEngine = engine, + MavenCacheDirectory = temp_cache_dir, + }; + + await task.RunTaskAsync (); + + Assert.AreEqual (0, engine.Errors.Count); + Assert.AreEqual (today_file, task.ResolvedPackageMap); + Assert.IsFalse (File.Exists (yesterday_file)); + + } finally { + MavenDownloadTests.DeleteTempDirectory (temp_cache_dir); + } + } + + [Test] + public async Task MalformedFileName () + { + // Make sure a malformed file name doesn't cause an exception, a new file should be downloaded and returned + var engine = new MockBuildEngine (TestContext.Out, []); + var temp_cache_dir = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ()); + var malformed_file = Path.Combine (temp_cache_dir, $"microsoft-packages-dummy.json"); + var today_file = Path.Combine (temp_cache_dir, $"microsoft-packages-{DateTime.Today:yyyyMMdd}.json"); + + try { + Directory.CreateDirectory (temp_cache_dir); + File.WriteAllText (malformed_file, "dummy file"); + + var task = new GetMicrosoftNuGetPackagesMap { + BuildEngine = engine, + MavenCacheDirectory = temp_cache_dir, + }; + + await task.RunTaskAsync (); + + Assert.AreEqual (0, engine.Errors.Count); + Assert.AreEqual (today_file, task.ResolvedPackageMap); + Assert.IsTrue (File.Exists (today_file)); + + } finally { + MavenDownloadTests.DeleteTempDirectory (temp_cache_dir); + } + } + + // This test can only be run manually, since it requires changing the URL to a non-existent one. + // But I wanted to ensure I had tested this scenario. + //[Test] + public async Task CachedYesterdayFile_NewFileFails () + { + // If a file only exists for yesterday, but we fail to download a new file today, return + // the old file and don't delete it + var engine = new MockBuildEngine (TestContext.Out, []); + var temp_cache_dir = Path.Combine (Path.GetTempPath (), Guid.NewGuid ().ToString ()); + var yesterday_file = Path.Combine (temp_cache_dir, $"microsoft-packages-{DateTime.Today.AddDays (-1):yyyyMMdd}.json"); + + try { + Directory.CreateDirectory (temp_cache_dir); + File.WriteAllText (yesterday_file, "dummy file"); + + var task = new GetMicrosoftNuGetPackagesMap { + BuildEngine = engine, + MavenCacheDirectory = temp_cache_dir, + }; + + await task.RunTaskAsync (); + + Assert.AreEqual (0, engine.Errors.Count); + Assert.AreEqual (yesterday_file, task.ResolvedPackageMap); + Assert.IsTrue (File.Exists (yesterday_file)); + + } finally { + MavenDownloadTests.DeleteTempDirectory (temp_cache_dir); + } + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs index e0c67b22841..ca893dec7eb 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs @@ -4,10 +4,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text.Json; using System.Xml; -using Java.Interop.Maven.Models; +using Java.Interop.Tools.Maven.Models; using Microsoft.Build.Utilities; -using Newtonsoft.Json; using NUnit.Framework; using Xamarin.Android.Tasks; @@ -347,7 +347,7 @@ TemporaryFile CreateMicrosoftNuGetPackageFinder (string javaId, string nugetId) Packages = [new MicrosoftNuGetPackageFinder.Package { JavaId = javaId, NuGetId = nugetId }] }; - return new TemporaryFile (JsonConvert.SerializeObject (package), "microsoft-packages.json"); + return new TemporaryFile (JsonSerializer.Serialize (package), "microsoft-packages.json"); } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/MavenDownloadTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/MavenDownloadTests.cs index 5c2d4535285..9fa10ea2da8 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/MavenDownloadTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/MavenDownloadTests.cs @@ -85,7 +85,7 @@ public async Task UnknownArtifact () await task.RunTaskAsync (); Assert.AreEqual (1, engine.Errors.Count); - Assert.AreEqual ($"Cannot download Maven artifact 'com.example:dummy'.{Environment.NewLine}- com.example_dummy.jar: Response status code does not indicate success: 404 (Not Found).{Environment.NewLine}- com.example_dummy.aar: Response status code does not indicate success: 404 (Not Found).", engine.Errors [0].Message?.ReplaceLineEndings ()); + Assert.AreEqual ($"Cannot download Maven artifact 'com.example:dummy'.{Environment.NewLine}- dummy-1.0.0.jar: Response status code does not indicate success: 404 (Not Found).{Environment.NewLine}- dummy-1.0.0.aar: Response status code does not indicate success: 404 (Not Found).", engine.Errors [0].Message?.ReplaceLineEndings ()); } [Test] @@ -102,7 +102,7 @@ public async Task UnknownPom () }; // Create the dummy jar so we bypass that step and try to download the dummy pom - var dummy_jar = Path.Combine (temp_cache_dir, "central", "com.example", "dummy", "1.0.0", "com.example_dummy.jar"); + var dummy_jar = Path.Combine (temp_cache_dir, "central", "com.example", "dummy", "1.0.0", "dummy-1.0.0.jar"); Directory.CreateDirectory (Path.GetDirectoryName (dummy_jar)!); using (File.Create (dummy_jar)) { } @@ -110,7 +110,7 @@ public async Task UnknownPom () await task.RunTaskAsync (); Assert.AreEqual (1, engine.Errors.Count); - Assert.AreEqual ($"Cannot download POM file for Maven artifact 'com.example:dummy'.{Environment.NewLine}- com.example_dummy.pom: Response status code does not indicate success: 404 (Not Found).", engine.Errors [0].Message?.ReplaceLineEndings ()); + Assert.AreEqual ($"Cannot download POM file for Maven artifact 'com.example:dummy:1.0.0'.{Environment.NewLine}- Response status code does not indicate success: 404 (Not Found).", engine.Errors [0].Message?.ReplaceLineEndings ()); } finally { DeleteTempDirectory (temp_cache_dir); } @@ -136,12 +136,9 @@ public async Task MavenCentralSuccess () var output_item = task.ResolvedAndroidMavenLibraries! [0]; - Assert.AreEqual ("com.google.auto.value:auto-value-annotations", output_item.GetMetadata ("ArtifactSpec")); - Assert.AreEqual (Path.Combine (temp_cache_dir, "central", "com.google.auto.value", "auto-value-annotations", "1.10.4", "com.google.auto.value_auto-value-annotations.jar"), output_item.GetMetadata ("ArtifactFile")); - Assert.AreEqual (Path.Combine (temp_cache_dir, "central", "com.google.auto.value", "auto-value-annotations", "1.10.4", "com.google.auto.value_auto-value-annotations.pom"), output_item.GetMetadata ("ArtifactPom")); - - Assert.True (File.Exists (output_item.GetMetadata ("ArtifactFile"))); - Assert.True (File.Exists (output_item.GetMetadata ("ArtifactPom"))); + Assert.AreEqual ("com.google.auto.value:auto-value-annotations", output_item.GetMetadata ("JavaArtifact")); + Assert.AreEqual ("1.10.4", output_item.GetMetadata ("JavaVersion")); + Assert.AreEqual (Path.Combine (temp_cache_dir, "central", "com.google.auto.value", "auto-value-annotations", "1.10.4", "auto-value-annotations-1.10.4.pom"), output_item.GetMetadata ("Manifest")); } finally { DeleteTempDirectory (temp_cache_dir); } @@ -167,12 +164,9 @@ public async Task MavenGoogleSuccess () var output_item = task.ResolvedAndroidMavenLibraries! [0]; - Assert.AreEqual ("androidx.core:core", output_item.GetMetadata ("ArtifactSpec")); - Assert.AreEqual (Path.Combine (temp_cache_dir, "google", "androidx.core", "core", "1.12.0", "androidx.core_core.aar"), output_item.GetMetadata ("ArtifactFile")); - Assert.AreEqual (Path.Combine (temp_cache_dir, "google", "androidx.core", "core", "1.12.0", "androidx.core_core.pom"), output_item.GetMetadata ("ArtifactPom")); - - Assert.True (File.Exists (output_item.GetMetadata ("ArtifactFile"))); - Assert.True (File.Exists (output_item.GetMetadata ("ArtifactPom"))); + Assert.AreEqual ("androidx.core:core", output_item.GetMetadata ("JavaArtifact")); + Assert.AreEqual ("1.12.0", output_item.GetMetadata ("JavaVersion")); + Assert.AreEqual (Path.Combine (temp_cache_dir, "google", "androidx.core", "core", "1.12.0", "core-1.12.0.pom"), output_item.GetMetadata ("Manifest")); } finally { DeleteTempDirectory (temp_cache_dir); } @@ -190,7 +184,7 @@ ITaskItem CreateMavenTaskItem (string name, string? version, string? repository return item; } - void DeleteTempDirectory (string dir) + public static void DeleteTempDirectory (string dir) { try { Directory.Delete (dir, true); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs index 85a0d5e628f..d2cef8dd167 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs @@ -4,14 +4,10 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; -using System.Security.Cryptography; -using System.Text; using System.Threading; using System.Threading.Tasks; -using System.Xml; -using System.Xml.Serialization; -using MavenNet; -using MavenNet.Models; +using Java.Interop.Tools.Maven.Models; +using Java.Interop.Tools.Maven.Repositories; using Microsoft.Android.Build.Tasks; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; @@ -21,7 +17,6 @@ namespace Xamarin.Android.Tasks; static class MavenExtensions { static readonly char [] separator = [':']; - static XmlSerializer pom_serializer = new XmlSerializer (typeof (Project)); /// /// Shortcut for !string.IsNullOrWhiteSpace (s) @@ -102,21 +97,16 @@ public static T [] OrEmpty (this T []? value) return value ?? Array.Empty (); } - public static Artifact? ParseArtifact (string id, string version, TaskLoggingHelper log) + // Removes AggregateException wrapping around an exception + public static Exception Unwrap (this Exception ex) { - var parts = id.Split (separator, StringSplitOptions.RemoveEmptyEntries); - - if (parts.Length != 2 || parts.Any (string.IsNullOrWhiteSpace)) { - log.LogCodedError ("XA4235", Properties.Resources.XA4235, id); - return null; - } - - var artifact = new Artifact (parts [1], parts [0], version); + while (ex is AggregateException && ex.InnerException is not null) + ex = ex.InnerException; - return artifact; + return ex; } - public static bool TryParseArtifact (string id, string version, TaskLoggingHelper log, [NotNullWhen (true)] out Java.Interop.Maven.Models.Artifact? artifact) + public static bool TryParseArtifactWithVersion (string id, string version, TaskLoggingHelper log, [NotNullWhen (true)] out Artifact? artifact) { artifact = null; @@ -127,12 +117,12 @@ public static bool TryParseArtifact (string id, string version, TaskLoggingHelpe return false; } - artifact = new Java.Interop.Maven.Models.Artifact (parts [0], parts [1], version); + artifact = new Artifact (parts [0], parts [1], version); return true; } - public static bool TryParseJavaArtifactAndVersion (this ITaskItem task, string type, TaskLoggingHelper log, [NotNullWhen (true)] out Java.Interop.Maven.Models.Artifact? artifact) + public static bool TryParseJavaArtifactAndJavaVersion (this ITaskItem task, string type, TaskLoggingHelper log, [NotNullWhen (true)] out Artifact? artifact) { artifact = null; @@ -169,47 +159,21 @@ public static bool TryParseJavaArtifactAndVersion (this ITaskItem task, string t return false; } - if (TryParseArtifact (id, version, log, out artifact)) + if (TryParseArtifactWithVersion (id, version, log, out artifact)) return true; - } return false; } - public static Project ParsePom (string pomFile) - { - Project? result = null; - - using (var sr = File.OpenRead (pomFile)) - result = (Project) pom_serializer.Deserialize (new XmlTextReader (sr) { - Namespaces = false, - }); - - return result; - } - - public static Artifact? CheckForNeededParentPom (string pomFile) - => ParsePom (pomFile).GetParentPom (); - - public static Artifact? GetParentPom (this Project? pom) - { - if (pom?.Parent != null) - return new Artifact (pom.Parent.ArtifactId, pom.Parent.GroupId, pom.Parent.Version); - - return null; - } - // Returns artifact output path - public static async Task DownloadPayload (Artifact artifact, string cacheDir, TaskLoggingHelper log, CancellationToken cancellationToken) + public static async Task DownloadPayload (CachedMavenRepository repository, Artifact artifact, string cacheDir, TaskLoggingHelper log, CancellationToken cancellationToken) { - var version = artifact.Versions.First (); - - var output_directory = Path.Combine (cacheDir, artifact.GetRepositoryCacheName (), artifact.GroupId, artifact.Id, version); + var output_directory = Path.Combine (cacheDir, repository.Name, artifact.GroupId, artifact.Id, artifact.Version); Directory.CreateDirectory (output_directory); - var filename = $"{artifact.GroupId}_{artifact.Id}"; + var filename = $"{artifact.Id}-{artifact.Version}"; var jar_filename = Path.Combine (output_directory, Path.Combine ($"{filename}.jar")); var aar_filename = Path.Combine (output_directory, Path.Combine ($"{filename}.aar")); @@ -220,10 +184,10 @@ public static Project ParsePom (string pomFile) if (File.Exists (aar_filename)) return aar_filename; - if (await TryDownloadPayload (artifact, jar_filename, cancellationToken) is not string jar_error) + if (await TryDownloadPayload (repository, artifact, jar_filename, cancellationToken) is not string jar_error) return jar_filename; - if (await TryDownloadPayload (artifact, aar_filename, cancellationToken) is not string aar_error) + if (await TryDownloadPayload (repository, artifact, aar_filename, cancellationToken) is not string aar_error) return aar_filename; log.LogCodedError ("XA4236", Properties.Resources.XA4236, artifact.GroupId, artifact.Id, Path.GetFileName (jar_filename), jar_error, Path.GetFileName (aar_filename), aar_error); @@ -231,132 +195,27 @@ public static Project ParsePom (string pomFile) return null; } - // Returns artifact output path - public static async Task DownloadPom (Artifact artifact, string cacheDir, TaskLoggingHelper log, CancellationToken cancellationToken, bool isParent = false) + // Return value is download error message, null represents success (async methods cannot have out parameters) + static async Task TryDownloadPayload (CachedMavenRepository repository, Artifact artifact, string filename, CancellationToken cancellationToken) { - var version = artifact.Versions.First (); - var output_directory = Path.Combine (cacheDir, artifact.GetRepositoryCacheName (), artifact.GroupId, artifact.Id, version); - - Directory.CreateDirectory (output_directory); - - var filename = $"{artifact.GroupId}_{artifact.Id}"; - var pom_filename = Path.Combine (output_directory, Path.Combine ($"{filename}.pom")); - - // We don't need to redownload if we already have a cached copy - if (File.Exists (pom_filename)) - return pom_filename; - - if (await TryDownloadPayload (artifact, pom_filename, cancellationToken) is not string pom_error) - return pom_filename; - - if (!isParent) - log.LogCodedError ("XA4237", Properties.Resources.XA4237, artifact.GroupId, artifact.Id, Path.GetFileName (pom_filename), pom_error); - else - log.LogCodedError ("XA4238", Properties.Resources.XA4238, artifact.GroupId, artifact.Id, Path.GetFileName (pom_filename), pom_error); - - return null; - } + var maven_filename = $"{artifact.Id}-{artifact.Version}{Path.GetExtension (filename)}"; - // Return value indicates download success - static async Task TryDownloadPayload (Artifact artifact, string filename, CancellationToken cancellationToken) - { try { - using var src = await artifact.OpenLibraryFile (artifact.Versions.First (), Path.GetExtension (filename)); - using var sw = File.Create (filename); - - await src.CopyToAsync (sw, 81920, cancellationToken); + if ((await repository.GetFilePathAsync (artifact, maven_filename, cancellationToken)) is string path) { + return null; + } else { + // This probably(?) cannot be hit, everything should come back as an exception + return $"Could not download {maven_filename}"; + } - return null; } catch (Exception ex) { - return ex.Message; + return ex.Unwrap ().Message; } } - public static string GetRepositoryCacheName (this Artifact artifact) - { - var type = artifact.Repository; - - if (type is MavenCentralRepository) - return "central"; - - if (type is GoogleMavenRepository) - return "google"; - - if (type is UrlMavenRepository url) { - using var hasher = SHA256.Create (); - var hash = hasher.ComputeHash (Encoding.UTF8.GetBytes (url.BaseUri.ToString ())); - return Convert.ToBase64String (hash); - } - - // Should never be hit - throw new ArgumentException ($"Unexpected repository type: {type.GetType ()}"); - } - - public static void FixDependency (Project project, Project? parent, Dependency dependency) - { - // Handle Parent POM - if ((string.IsNullOrEmpty (dependency.Version) || string.IsNullOrEmpty (dependency.Scope)) && parent != null) { - var parent_dependency = parent.FindParentDependency (dependency); - - // Try to fish a version out of the parent POM - if (string.IsNullOrEmpty (dependency.Version)) - dependency.Version = ReplaceVersionProperties (parent, parent_dependency?.Version); - - // Try to fish a scope out of the parent POM - if (string.IsNullOrEmpty (dependency.Scope)) - dependency.Scope = parent_dependency?.Scope; - } + public static bool IsCompileDependency (this ResolvedDependency dependency) => string.IsNullOrWhiteSpace (dependency.Scope) || dependency.Scope.IndexOf ("compile", StringComparison.OrdinalIgnoreCase) != -1; - var version = dependency.Version; - - if (string.IsNullOrWhiteSpace (version)) - return; - - version = ReplaceVersionProperties (project, version); - - // VersionRange.Parse cannot handle single number versions that we sometimes see in Maven, like "1". - // Fix them to be "1.0". - // https://github.com/NuGet/Home/issues/10342 - if (version != null && !version.Contains (".")) - version += ".0"; - - dependency.Version = version; - } - - static string? ReplaceVersionProperties (Project project, string? version) - { - // Handle versions with Properties, like: - // - // 1.8 - // 2.8.6 - // - // - // - // com.google.code.gson - // gson - // ${gson.version} - // - // - if (string.IsNullOrWhiteSpace (version) || project?.Properties == null) - return version; - - foreach (var prop in project.Properties.Any) - version = version?.Replace ($"${{{prop.Name.LocalName}}}", prop.Value); - - return version; - } - - public static bool IsCompileDependency (this Java.Interop.Maven.Models.ResolvedDependency dependency) => string.IsNullOrWhiteSpace (dependency.Scope) || dependency.Scope.IndexOf ("compile", StringComparison.OrdinalIgnoreCase) != -1; - - public static bool IsRuntimeDependency (this Java.Interop.Maven.Models.ResolvedDependency dependency) => dependency?.Scope != null && dependency.Scope.IndexOf ("runtime", StringComparison.OrdinalIgnoreCase) != -1; - - public static bool IsOptional (this Java.Interop.Maven.Models.ResolvedDependency dependency) => dependency?.Optional != null && dependency.Optional.IndexOf ("true", StringComparison.OrdinalIgnoreCase) != -1; - - public static Dependency? FindParentDependency (this Project project, Dependency dependency) - { - return project.DependencyManagement?.Dependencies?.FirstOrDefault ( - d => d.GroupAndArtifactId () == dependency.GroupAndArtifactId () && d.Classifier != "sources"); - } + public static bool IsRuntimeDependency (this ResolvedDependency dependency) => dependency?.Scope != null && dependency.Scope.IndexOf ("runtime", StringComparison.OrdinalIgnoreCase) != -1; - public static string GroupAndArtifactId (this Dependency dependency) => $"{dependency.GroupId}.{dependency.ArtifactId}"; + public static bool IsOptional (this ResolvedDependency dependency) => dependency?.Optional != null && dependency.Optional.IndexOf ("true", StringComparison.OrdinalIgnoreCase) != -1; } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj index 7f253e10b05..525feced8bd 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj @@ -28,7 +28,6 @@ - @@ -228,7 +227,7 @@ - + + + + +``` +See the [Java Dependency Resolution documentation](../JavaDependencyVerification.md) +for more details. + +This build action was introduced in .NET 9. + ## AndroidJavaSource Files with a Build action of `AndroidJavaSource` are Java source code that diff --git a/Documentation/guides/messages/README.md b/Documentation/guides/messages/README.md index df2c6915f35..e44f87d9b9b 100644 --- a/Documentation/guides/messages/README.md +++ b/Documentation/guides/messages/README.md @@ -186,6 +186,19 @@ Either change the value in the AndroidManifest.xml to match the $(SupportedOSPla + XA4230: Error parsing XML: {exception} + [XA4231](xa4231.md): The Android class parser value 'jar2xml' is deprecated and will be removed in a future version of Xamarin.Android. Update the project properties to use 'class-parse'. + [XA4232](xa4232.md): The Android code generation target 'XamarinAndroid' is deprecated and will be removed in a future version of Xamarin.Android. Update the project properties to use 'XAJavaInterop1'. ++ [XA4234](xa4234.md): '<{item}>' item '{itemspec}' is missing required attribute '{name}'. ++ [XA4235](xa4235.md): Maven artifact specification '{artifact}' is invalid. The correct format is 'group_id:artifact_id'. ++ [XA4236](xa4236.md): Cannot download Maven artifact '{group}:{artifact}'. - {jar}: {exception} - {aar}: {exception} ++ [XA4237](xa4237.md): Cannot download POM file for Maven artifact '{artifact}'. - {exception} ++ [XA4239](xa4239.md): Unknown Maven repository: '{repository}'. ++ [XA4241](xa4241.md): Java dependency '{artifact}' is not satisfied. ++ [XA4242](xa4242.md): Java dependency '{artifact}' is not satisfied. Microsoft maintains the NuGet package '{nugetId}' that could fulfill this dependency. ++ [XA4243](xa4243.md): Attribute '{name}' is required when using '{name}' for '{element}' item '{itemspec}'. ++ [XA4244](xa4244.md): Attribute '{name}' cannot be empty for '{element}' item '{itemspec}'. ++ [XA4245](xa4245.md): Specified POM file '{file}' does not exist. ++ [XA4246](xa4246.md): Could not parse POM file '{file}'. - {exception} ++ [XA4247](xa4247.md): Could not resolve POM file for artifact '{artifact}'. ++ [XA4248](xa4248.md): Could not find NuGet package '{nugetId}' version '{version}' in lock file. Ensure NuGet Restore has run since this was added. + XA4300: Native library '{library}' will not be bundled because it has an unsupported ABI. + [XA4301](xa4301.md): Apk already contains the item `xxx`. + [XA4302](xa4302.md): Unhandled exception merging \`AndroidManifest.xml\`: {ex} From ccd9113cef30875886caea0fb021288431775909 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Thu, 22 Feb 2024 10:42:28 -1000 Subject: [PATCH 08/12] Track Java.Interop.Tools.Maven changes. --- external/xamarin-android-tools | 2 +- .../Tasks/JavaDependencyVerification.cs | 30 +++++++++---------- .../Tasks/MavenDownload.cs | 12 ++++---- .../Tasks/JavaDependencyVerificationTests.cs | 9 +++++- .../Utilities/MavenExtensions.cs | 4 --- 5 files changed, 30 insertions(+), 27 deletions(-) diff --git a/external/xamarin-android-tools b/external/xamarin-android-tools index a698a33aa4f..37d79c9dcdf 160000 --- a/external/xamarin-android-tools +++ b/external/xamarin-android-tools @@ -1 +1 @@ -Subproject commit a698a33aa4ffcaac90b54caf5e77236d57b0cf9e +Subproject commit 37d79c9dcdf738a181084b0b5890877128d75f1e diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs b/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs index 5c2476ae7d8..3373e1b095f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs @@ -95,7 +95,7 @@ public override bool RunTask () return !Log.HasLoggedErrors; } - static bool TryResolveProject (Artifact artifact, IPomResolver resolver, [NotNullWhen (true)]out ResolvedProject? project) + static bool TryResolveProject (Artifact artifact, IProjectResolver resolver, [NotNullWhen (true)]out ResolvedProject? project) { // ResolvedProject.FromArtifact will throw if a POM cannot be resolved, but our MSBuildLoggingPomResolver // has already logged the failure as an MSBuild error. We don't want to log it again as an unhandled exception. @@ -135,7 +135,7 @@ public bool EnsureDependencySatisfied (ResolvedDependency dependency, MicrosoftN return true; var suggestion = packages.GetNuGetPackage ($"{dependency.GroupId}:{dependency.ArtifactId}"); - var artifact_spec = dependency.ToArtifactString (dependency.Version.HasValue ()); + var artifact_spec = dependency.Version.HasValue () ? dependency.VersionedArtifactString : dependency.ArtifactString; if (suggestion is string nuget) log.LogCodedError ("XA4242", Properties.Resources.XA4242, artifact_spec, nuget); @@ -157,7 +157,7 @@ public void AddAndroidLibraries (ITaskItem []? tasks) if (version != null && MavenExtensions.TryParseArtifactWithVersion (id, version, log, out var art)) { log.LogMessage ("Found Java dependency '{0}:{1}' version '{2}' from AndroidLibrary '{3}'", art.GroupId, art.Id, art.Version, task.ItemSpec); - artifacts.Add (art.ToGroupAndArtifactId (), art); + artifacts.Add (art.ArtifactString, art); } } } @@ -168,7 +168,7 @@ public void AddPackageReferences (ITaskItem []? tasks) // See if JavaArtifact/JavaVersion overrides were used if (task.TryParseJavaArtifactAndJavaVersion ("PackageReference", log, out var explicit_artifact, out var attributes_specified)) { - artifacts.Add (explicit_artifact.ToGroupAndArtifactId (), explicit_artifact); + artifacts.Add (explicit_artifact.ArtifactString, explicit_artifact); continue; } @@ -181,7 +181,7 @@ public void AddPackageReferences (ITaskItem []? tasks) if (artifact != null) { log.LogMessage ("Found Java dependency '{0}:{1}' version '{2}' from PackageReference '{3}'", artifact.GroupId, artifact.Id, artifact.Version, task.ItemSpec); - artifacts.Add (artifact.ToGroupAndArtifactId (), artifact); + artifacts.Add (artifact.ArtifactString, artifact); continue; } @@ -195,7 +195,7 @@ public void AddProjectReferences (ITaskItem []? tasks) foreach (var task in tasks.OrEmpty ()) { // See if JavaArtifact/JavaVersion overrides were used if (task.TryParseJavaArtifactAndJavaVersion ("ProjectReference", log, out var explicit_artifact, out var attributes_specified)) { - artifacts.Add (explicit_artifact.ToGroupAndArtifactId (), explicit_artifact); + artifacts.Add (explicit_artifact.ArtifactString, explicit_artifact); continue; } @@ -219,7 +219,7 @@ public void AddIgnoredDependencies (ITaskItem []? tasks) if (version != null && MavenExtensions.TryParseArtifactWithVersion (id, version, log, out var art)) { log.LogMessage ("Ignoring Java dependency '{0}:{1}' version '{2}'", art.GroupId, art.Id, art.Version); - artifacts.Add (art.ToGroupAndArtifactId (), art); + artifacts.Add (art.ArtifactString, art); } } } @@ -227,18 +227,18 @@ public void AddIgnoredDependencies (ITaskItem []? tasks) bool TrySatisfyDependency (ResolvedDependency dependency) { if (!dependency.Version.HasValue ()) - return artifacts.ContainsKey (dependency.ToGroupAndArtifactId ()); + return artifacts.ContainsKey (dependency.ArtifactString); var dep_versions = MavenVersionRange.Parse (dependency.Version); - if (artifacts.TryGetValue (dependency.ToGroupAndArtifactId (), out var artifact)) + if (artifacts.TryGetValue (dependency.ArtifactString, out var artifact)) return dep_versions.Any (r => r.ContainsVersion (MavenVersion.Parse (artifact.Version))); return false; } } -class MSBuildLoggingPomResolver : IPomResolver +class MSBuildLoggingPomResolver : IProjectResolver { readonly TaskLoggingHelper logger; readonly Dictionary poms = new (); @@ -272,8 +272,8 @@ public MSBuildLoggingPomResolver (TaskLoggingHelper logger) try { using (var file = File.OpenRead (filename)) { - var project = Project.Parse (file); - var registered_artifact = Artifact.Parse (project.ToString ()); + var project = Project.Load (file); + var registered_artifact = Artifact.Parse (project.VersionedArtifactString); // Return the registered artifact, preferring any overrides specified in the task item var final_artifact = new Artifact ( @@ -283,7 +283,7 @@ public MSBuildLoggingPomResolver (TaskLoggingHelper logger) ); // Use index instead of Add to handle duplicates - poms [final_artifact.ToString ()] = project; + poms [final_artifact.VersionedArtifactString] = project; logger.LogDebugMessage ("Registered POM for artifact '{0}' from '{1}'", final_artifact, filename); @@ -295,9 +295,9 @@ public MSBuildLoggingPomResolver (TaskLoggingHelper logger) } } - public Project ResolveRawProject (Artifact artifact) + public Project Resolve (Artifact artifact) { - if (poms.TryGetValue (artifact.ToString (), out var project)) + if (poms.TryGetValue (artifact.VersionedArtifactString, out var project)) return project; logger.LogCodedError ("XA4247", Properties.Resources.XA4247, artifact); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs b/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs index 2197c573f08..383cc1a2d2f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs @@ -110,13 +110,13 @@ public async override System.Threading.Tasks.Task RunTaskAsync () var project = ResolvedProject.FromArtifact (artifact, resolver); // Set the POM file path for _this_ artifact - var primary_pom = resolver.ResolvedPoms [artifact.ToString ()]; + var primary_pom = resolver.ResolvedPoms [artifact.VersionedArtifactString]; result.SetMetadata ("Manifest", primary_pom); Log.LogMessage ("Found POM file '{0}' for Java artifact '{1}'.", primary_pom, artifact); // Create TaskItems for any other POMs we resolved - foreach (var kv in resolver.ResolvedPoms.Where (k => k.Key != artifact.ToString ())) { + foreach (var kv in resolver.ResolvedPoms.Where (k => k.Key != artifact.VersionedArtifactString)) { var pom_item = new TaskItem (kv.Value); var pom_artifact = Artifact.Parse (kv.Key); @@ -163,7 +163,7 @@ public async override System.Threading.Tasks.Task RunTaskAsync () // This wrapper around CachedMavenRepository is used to log the POMs that are resolved. // We need these on-disk file locations so we can pass them as items. -class LoggingPomResolver : IPomResolver +class LoggingPomResolver : IProjectResolver { readonly CachedMavenRepository repository; @@ -174,14 +174,14 @@ public LoggingPomResolver (CachedMavenRepository repository) this.repository = repository; } - public Project ResolveRawProject (Artifact artifact) + public Project Resolve (Artifact artifact) { if (repository.TryGetFilePath (artifact, $"{artifact.Id}-{artifact.Version}.pom", out var path)) { using (var stream = File.OpenRead (path)) { - var pom = Project.Parse (stream) ?? throw new InvalidOperationException ($"Could not deserialize POM for {artifact}"); + var pom = Project.Load (stream) ?? throw new InvalidOperationException ($"Could not deserialize POM for {artifact}"); // Use index instead of Add to handle duplicates - ResolvedPoms [artifact.ToString ()] = path; + ResolvedPoms [artifact.VersionedArtifactString] = path; return pom; } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs index c43bf3dcc53..f854c422b7e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/JavaDependencyVerificationTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using System.Text.Json; using System.Xml; using Java.Interop.Tools.Maven.Models; @@ -386,7 +387,7 @@ public PomBuilder (string groupId, string artifactId, string? version) public string Build () { - using var sw = new StringWriter (); + using var sw = new Utf8StringWriter (); using var xw = XmlWriter.Create (sw); xw.WriteStartDocument (); @@ -487,4 +488,10 @@ public PomBuilder WithParent (string groupId, string artifactId, string? version } public TemporaryFile BuildTemporary () => new TemporaryFile (Build ()); + + // Trying to write XML to a StringWriter defaults to UTF-16, but we want UTF-8 + class Utf8StringWriter : StringWriter + { + public override Encoding Encoding => Encoding.UTF8; + } } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs index 23993d0c9b9..a9b881adec6 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MavenExtensions.cs @@ -154,8 +154,4 @@ public static bool TryParseJavaArtifactAndJavaVersion (this ITaskItem task, stri public static bool IsRuntimeDependency (this ResolvedDependency dependency) => dependency?.Scope != null && dependency.Scope.IndexOf ("runtime", StringComparison.OrdinalIgnoreCase) != -1; public static bool IsOptional (this ResolvedDependency dependency) => dependency?.Optional != null && dependency.Optional.IndexOf ("true", StringComparison.OrdinalIgnoreCase) != -1; - - public static string ToGroupAndArtifactId (this Artifact artifact) => $"{artifact.GroupId}:{artifact.Id}"; - - public static string ToGroupAndArtifactId (this ResolvedDependency dependency) => $"{dependency.GroupId}:{dependency.ArtifactId}"; } From 6996ccc0d9fccb7efa960a835606472fa36bc8b1 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Tue, 19 Mar 2024 13:00:07 -1000 Subject: [PATCH 09/12] Address docs review feedback. --- .../guides/building-apps/build-items.md | 25 +- .../Properties/Resources.Designer.cs | 568 +++++++++--------- 2 files changed, 293 insertions(+), 300 deletions(-) diff --git a/Documentation/guides/building-apps/build-items.md b/Documentation/guides/building-apps/build-items.md index 0d745eaf296..e6d6d954d75 100644 --- a/Documentation/guides/building-apps/build-items.md +++ b/Documentation/guides/building-apps/build-items.md @@ -23,9 +23,16 @@ These are often parent or imported POM files referenced by a Java library's POM ```xml - + ``` + +The following MSBuild metadata are required: + +- `%(JavaArtifact)`: The group and artifact id of the Java library matching the specifed POM + file in the form `{GroupId}:{ArtifactId}`. +- `%(JavaVersion)`: The version of the Java library matching the specified POM file. + See the [Java Dependency Resolution documentation](../JavaDependencyVerification.md) for more details. @@ -146,6 +153,11 @@ cannot detect. ``` + +The following MSBuild metadata are required: + +- `%(Version)`: The version of the Java library matching the specified `%(Include)`. + See the [Java Dependency Resolution documentation](../JavaDependencyVerification.md) for more details. @@ -254,6 +266,17 @@ hosted in Maven. ``` + +The following MSBuild metadata are supported: + +- `%(Version)`: Required version of the Java library referenced by `%(Include)`. +- `%(Repository)`: Optional Maven repository to use. Supported values are `Central` (default), + `Google`, or an `https` URL to a Maven repository. + +The `` item is translated to an +[``](https://github.com/xamarin/xamarin-android/blob/main/Documentation/guides/building-apps/build-items.md#androidlibrary) +item, so any metadata supported by `` like `Bind` or `Pack` are also supported. + See the [AndroidMavenLibrary documentation](../AndroidMavenLibrary.md) for more details. diff --git a/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs b/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs index 86a40b2bfa8..0c326142438 100644 --- a/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs +++ b/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs @@ -10,8 +10,8 @@ namespace Xamarin.Android.Tasks.Properties { using System; - - + + /// /// A strongly-typed resource class, for looking up localized strings, etc. /// @@ -23,15 +23,15 @@ namespace Xamarin.Android.Tasks.Properties { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Resources { - + private static global::System.Resources.ResourceManager resourceMan; - + private static global::System.Globalization.CultureInfo resourceCulture; - + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } - + /// /// Returns the cached ResourceManager instance used by this class. /// @@ -45,7 +45,7 @@ internal Resources() { return resourceMan; } } - + /// /// Overrides the current thread's CurrentUICulture property for all /// resource lookups using this strongly typed resource class. @@ -59,7 +59,7 @@ internal Resources() { resourceCulture = value; } } - + /// /// Looks up a localized string similar to {0}. /// @@ -70,7 +70,7 @@ public static string AAPTManifestError { return ResourceManager.GetString("AAPTManifestError", resourceCulture); } } - + /// /// Looks up a localized string similar to Unknown option `{0}`. Please check `$(AndroidAapt2CompileExtraArgs)` and `$(AndroidAapt2LinkExtraArgs)` to see if they include any `aapt` command line arguments that are no longer valid for `aapt2` and ensure that all other arguments are valid for `aapt2`.. /// @@ -79,7 +79,7 @@ public static string APT0001 { return ResourceManager.GetString("APT0001", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid file name: It must contain only {0}.. /// @@ -88,7 +88,7 @@ public static string APT0002 { return ResourceManager.GetString("APT0002", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid file name: It must contain only {0}.. /// @@ -97,7 +97,7 @@ public static string APT0003 { return ResourceManager.GetString("APT0003", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid file name: It must start with A-z or a-z or an underscore.. /// @@ -106,36 +106,27 @@ public static string APT0004 { return ResourceManager.GetString("APT0004", resourceCulture); } } - - /// - /// Looks up a localized string similar to This could be caused by the project exceeding the Windows maximum path length limitation. See https://learn.microsoft.com/xamarin/android/errors-and-warnings/apt2264 for details.. - /// - public static string APT2264 { - get { - return ResourceManager.GetString("APT2264", resourceCulture); - } - } - + /// - /// Looks up a localized string similar to This could be caused by the project having non-ASCII characters in its filename or path. See https://learn.microsoft.com/xamarin/android/errors-and-warnings/apt2265 for details.. + /// Looks up a localized string similar to Directory '{0}' is from '{1}'.. /// - public static string APT2265 { + public static string XA_Directory_Is_From { get { - return ResourceManager.GetString("APT2265", resourceCulture); + return ResourceManager.GetString("XA_Directory_Is_From", resourceCulture); } } - + /// - /// Looks up a localized string similar to Directory '{0}' is from '{1}'.. + /// Looks up a localized string similar to Could not find an 'AndroidResource' for 'anim'. /// - public static string XA_Directory_Is_From { + public static string XA8000 { get { - return ResourceManager.GetString("XA_Directory_Is_From", resourceCulture); + return ResourceManager.GetString("XA8000", resourceCulture); } } - + /// - /// Looks up a localized string similar to + /// Looks up a localized string similar to /// This code was generated by a tool. /// It was generated from {0} /// Changes to this file may cause incorrect behavior and will be lost if @@ -147,7 +138,7 @@ public static string XA_Manifest_AutoGenerated_Header { return ResourceManager.GetString("XA_Manifest_AutoGenerated_Header", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not determine API level for $(TargetFrameworkVersion) of '{0}'.. /// @@ -156,7 +147,7 @@ public static string XA0000_API_for_TargetFrameworkVersion { return ResourceManager.GetString("XA0000_API_for_TargetFrameworkVersion", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not determine $(AndroidApiLevel) or $(TargetFrameworkVersion); should not be reached.. /// @@ -165,7 +156,7 @@ public static string XA0000_API_or_TargetFrameworkVersion_Fail { return ResourceManager.GetString("XA0000_API_or_TargetFrameworkVersion_Fail", resourceCulture); } } - + /// /// Looks up a localized string similar to Unhandled exception: {0}. /// @@ -174,7 +165,7 @@ public static string XA0000_Exception { return ResourceManager.GetString("XA0000_Exception", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not determine $(TargetFrameworkVersion) for API level '{0}.'. /// @@ -183,7 +174,7 @@ public static string XA0000_TargetFrameworkVersion_for_API { return ResourceManager.GetString("XA0000_TargetFrameworkVersion_for_API", resourceCulture); } } - + /// /// Looks up a localized string similar to Unsupported or invalid $(TargetFrameworkVersion) value of '{0}'. Please update your Project Options.. /// @@ -192,7 +183,7 @@ public static string XA0001 { return ResourceManager.GetString("XA0001", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not find mono.android.jar. /// @@ -201,7 +192,7 @@ public static string XA0002 { return ResourceManager.GetString("XA0002", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid `android:versionCode` value `{0}` in `AndroidManifest.xml`. It must be an integer value.. /// @@ -210,7 +201,7 @@ public static string XA0003 { return ResourceManager.GetString("XA0003", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid `android:versionCode` value `{0}` in `AndroidManifest.xml`. The value must be in the range of 0 to {1}.. /// @@ -219,7 +210,7 @@ public static string XA0004 { return ResourceManager.GetString("XA0004", resourceCulture); } } - + /// /// Looks up a localized string similar to Building with JDK version `{0}` is not supported. Please install JDK version `{1}`. See https://aka.ms/xamarin/jdk9-errors. /// @@ -228,7 +219,7 @@ public static string XA0030 { return ResourceManager.GetString("XA0030", resourceCulture); } } - + /// /// Looks up a localized string similar to Java SDK {0} or above is required when using {1}. ///Download the latest JDK at: https://aka.ms/msopenjdk @@ -239,7 +230,7 @@ public static string XA0031 { return ResourceManager.GetString("XA0031", resourceCulture); } } - + /// /// Looks up a localized string similar to Java SDK {0} or above is required when using .NET 6 or higher. Download the latest JDK at: https://aka.ms/msopenjdk. /// @@ -248,7 +239,7 @@ public static string XA0031_NET { return ResourceManager.GetString("XA0031_NET", resourceCulture); } } - + /// /// Looks up a localized string similar to Java SDK {0} or above is required when using Android SDK Build-Tools {1}.. /// @@ -257,7 +248,7 @@ public static string XA0032 { return ResourceManager.GetString("XA0032", resourceCulture); } } - + /// /// Looks up a localized string similar to Failed to get the Java SDK version because the returned value does not appear to contain a valid version number. `{0} -version` returned: ```{1}```. /// @@ -266,7 +257,7 @@ public static string XA0033 { return ResourceManager.GetString("XA0033", resourceCulture); } } - + /// /// Looks up a localized string similar to Failed to get the Java SDK version. Please ensure you have Java {0} or above installed.. /// @@ -275,7 +266,7 @@ public static string XA0034 { return ResourceManager.GetString("XA0034", resourceCulture); } } - + /// /// Looks up a localized string similar to Unable to determine the Android ABI from the value '{0}'. Edit the project file in a text editor and set the 'RuntimeIdentifiers' MSBuild property to contain only valid identifiers for the Android platform.. /// @@ -284,7 +275,7 @@ public static string XA0035 { return ResourceManager.GetString("XA0035", resourceCulture); } } - + /// /// Looks up a localized string similar to The 'AndroidSupportedAbis' MSBuild property is no longer supported. Edit the project file in a text editor, remove any uses of 'AndroidSupportedAbis', and use the 'RuntimeIdentifiers' MSBuild property instead.. /// @@ -293,7 +284,7 @@ public static string XA0036 { return ResourceManager.GetString("XA0036", resourceCulture); } } - + /// /// Looks up a localized string similar to EmbeddedNativeLibrary '{0}' is invalid in Android Application projects. Please use AndroidNativeLibrary instead.. /// @@ -302,7 +293,7 @@ public static string XA0100 { return ResourceManager.GetString("XA0100", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid value for `$(AndroidSequencePointsMode)`: {0}. /// @@ -311,7 +302,7 @@ public static string XA0104 { return ResourceManager.GetString("XA0104", resourceCulture); } } - + /// /// Looks up a localized string similar to The $(TargetFrameworkVersion) for {0} ({1}) is greater than the $(TargetFrameworkVersion) for the application project ({2}). Please increase the $(TargetFrameworkVersion) for the application project.. /// @@ -320,7 +311,7 @@ public static string XA0105 { return ResourceManager.GetString("XA0105", resourceCulture); } } - + /// /// Looks up a localized string similar to {0} is a Reference Assembly.. /// @@ -329,7 +320,7 @@ public static string XA0107 { return ResourceManager.GetString("XA0107", resourceCulture); } } - + /// /// Looks up a localized string similar to Ignoring Reference Assembly `{0}`.. /// @@ -338,7 +329,7 @@ public static string XA0107_Ignoring { return ResourceManager.GetString("XA0107_Ignoring", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not get version from '{0}'. Defaulting to 1.0. /// @@ -347,7 +338,7 @@ public static string XA0108 { return ResourceManager.GetString("XA0108", resourceCulture); } } - + /// /// Looks up a localized string similar to Unsupported version of AAPT2 found at path '{0}'. Open the project file in a text editor and remove the 'Aapt2ToolPath' MSBuild property or ensure it is set to a valid location.. /// @@ -356,7 +347,7 @@ public static string XA0111 { return ResourceManager.GetString("XA0111", resourceCulture); } } - + /// /// Looks up a localized string similar to AAPT2 was not found at path '{0}'. Open the project file in a text editor and remove the 'Aapt2ToolPath' MSBuild property or ensure it is set to a valid location.. /// @@ -365,7 +356,7 @@ public static string XA0112 { return ResourceManager.GetString("XA0112", resourceCulture); } } - + /// /// Looks up a localized string similar to Google Play requires that new applications and updates must use a TargetFrameworkVersion of {0} (API level {1}) or above. You are currently targeting {2} (API level {3}).. /// @@ -374,7 +365,7 @@ public static string XA0113 { return ResourceManager.GetString("XA0113", resourceCulture); } } - + /// /// Looks up a localized string similar to Unable to find `EmbeddedResource` named `{0}`.. /// @@ -383,7 +374,7 @@ public static string XA0116 { return ResourceManager.GetString("XA0116", resourceCulture); } } - + /// /// Looks up a localized string similar to The TargetFrameworkVersion {0} is deprecated. Please update it to be v5.0 or higher.. /// @@ -392,7 +383,7 @@ public static string XA0117 { return ResourceManager.GetString("XA0117", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not parse '{0}'. /// @@ -401,7 +392,7 @@ public static string XA0118_Parse { return ResourceManager.GetString("XA0118_Parse", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not resolve `target` in lock file for '{0}'. /// @@ -410,7 +401,7 @@ public static string XA0118_Target { return ResourceManager.GetString("XA0118_Target", resourceCulture); } } - + /// /// Looks up a localized string similar to Using Fast Deployment and Android App Bundles at the same time is not currently supported. Use Fast Deployment for Debug configurations and Android App Bundles for Release configurations.. /// @@ -419,7 +410,7 @@ public static string XA0119_AAB { return ResourceManager.GetString("XA0119_AAB", resourceCulture); } } - + /// /// Looks up a localized string similar to Using fast deployment and AOT at the same time is not recommended. Use fast deployment for Debug configurations and AOT for Release configurations.. /// @@ -428,7 +419,7 @@ public static string XA0119_AOT { return ResourceManager.GetString("XA0119_AOT", resourceCulture); } } - + /// /// Looks up a localized string similar to Disabling the interpreter; using the interpreter and AOT at the same time is not supported. Use the interpreter for hot reload support in Debug configurations and AOT for Release configurations.. /// @@ -437,7 +428,7 @@ public static string XA0119_Interpreter { return ResourceManager.GetString("XA0119_Interpreter", resourceCulture); } } - + /// /// Looks up a localized string similar to Using fast deployment and the linker at the same time is not recommended. Use fast deployment for Debug configurations and the linker for Release configurations.. /// @@ -446,7 +437,7 @@ public static string XA0119_LinkMode { return ResourceManager.GetString("XA0119_LinkMode", resourceCulture); } } - + /// /// Looks up a localized string similar to Using fast deployment and a code shrinker at the same time is not recommended. Use fast deployment for Debug configurations and a code shrinker for Release configurations.. /// @@ -455,7 +446,7 @@ public static string XA0119_LinkTool { return ResourceManager.GetString("XA0119_LinkTool", resourceCulture); } } - + /// /// Looks up a localized string similar to Assembly '{0}' is using '[assembly: {1}]', which is no longer supported. Use a newer version of this NuGet package or notify the library author.. /// @@ -464,7 +455,7 @@ public static string XA0121 { return ResourceManager.GetString("XA0121", resourceCulture); } } - + /// /// Looks up a localized string similar to Assembly '{0}' is using a deprecated attribute '[assembly: {1}]'. Use a newer version of this NuGet package or notify the library author.. /// @@ -473,7 +464,7 @@ public static string XA0122 { return ResourceManager.GetString("XA0122", resourceCulture); } } - + /// /// Looks up a localized string similar to Removing {0} from {1}. Lint {2} does not support this check.. /// @@ -482,7 +473,7 @@ public static string XA0123 { return ResourceManager.GetString("XA0123", resourceCulture); } } - + /// /// Looks up a localized string similar to '{0}' is using a deprecated debug information level. ///Set the debugging information to Portable in the Visual Studio project property pages or edit the project file in a text editor and set the 'DebugType' MSBuild property to 'portable' to use the newer, cross-platform debug information level. @@ -493,7 +484,7 @@ public static string XA0125 { return ResourceManager.GetString("XA0125", resourceCulture); } } - + /// /// Looks up a localized string similar to There was a problem parsing {0}. This is likely due to incomplete or invalid XML. Exception: {1}. /// @@ -502,7 +493,7 @@ public static string XA1000 { return ResourceManager.GetString("XA1000", resourceCulture); } } - + /// /// Looks up a localized string similar to AndroidResgen: Warning while updating resource XML '{0}': {1}. /// @@ -511,7 +502,7 @@ public static string XA1001 { return ResourceManager.GetString("XA1001", resourceCulture); } } - + /// /// Looks up a localized string similar to The closest match found for '{0}' is '{1}', but the capitalization does not match. Please correct the capitalization.. /// @@ -520,7 +511,7 @@ public static string XA1002 { return ResourceManager.GetString("XA1002", resourceCulture); } } - + /// /// Looks up a localized string similar to Attempting basic type name matching for element with ID '{0}' and type '{1}'. /// @@ -529,7 +520,7 @@ public static string XA1005 { return ResourceManager.GetString("XA1005", resourceCulture); } } - + /// /// Looks up a localized string similar to If basic type name matching fails, please add a `xamarin:managedType` attribute to the element to specify the fully qualified managed type name of the element.. /// @@ -538,7 +529,7 @@ public static string XA1005_Instructions { return ResourceManager.GetString("XA1005_Instructions", resourceCulture); } } - + /// /// Looks up a localized string similar to The TargetFrameworkVersion (Android API level {0}) is higher than the targetSdkVersion ({1}). Please increase the `android:targetSdkVersion` in the `AndroidManifest.xml` so that the API levels match.. /// @@ -547,7 +538,7 @@ public static string XA1006 { return ResourceManager.GetString("XA1006", resourceCulture); } } - + /// /// Looks up a localized string similar to The minSdkVersion ({0}) is greater than the targetSdkVersion. Please change the value such that the minSdkVersion is less than or equal to the targetSdkVersion ({1}).. /// @@ -556,7 +547,7 @@ public static string XA1007 { return ResourceManager.GetString("XA1007", resourceCulture); } } - + /// /// Looks up a localized string similar to The TargetFrameworkVersion (Android API level {0}) is lower than the targetSdkVersion ({1}). Please increase the `$(TargetFrameworkVersion)` or decrease the `android:targetSdkVersion` in the `AndroidManifest.xml` so that the API levels match.. /// @@ -565,7 +556,7 @@ public static string XA1008 { return ResourceManager.GetString("XA1008", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid `$(AndroidManifestPlaceholders)` value for Android manifest placeholders. Please use `key1=value1;key2=value2` format. The specified value was: `{0}`. /// @@ -574,7 +565,7 @@ public static string XA1010 { return ResourceManager.GetString("XA1010", resourceCulture); } } - + /// /// Looks up a localized string similar to Using ProGuard with the D8 DEX compiler is no longer supported. Please set the code shrinker to 'r8' in the Visual Studio project property pages or edit the project file in a text editor and set the 'AndroidLinkTool' MSBuild property to 'r8'.. /// @@ -583,7 +574,7 @@ public static string XA1011 { return ResourceManager.GetString("XA1011", resourceCulture); } } - + /// /// Looks up a localized string similar to Included layout root element override ID '{0}' is not valid.. /// @@ -592,7 +583,7 @@ public static string XA1012 { return ResourceManager.GetString("XA1012", resourceCulture); } } - + /// /// Looks up a localized string similar to Failed to parse ID of node '{0}' in the layout file '{1}'.. /// @@ -601,7 +592,7 @@ public static string XA1013 { return ResourceManager.GetString("XA1013", resourceCulture); } } - + /// /// Looks up a localized string similar to JAR library references with identical file names but different contents were found: {0}. Please remove any conflicting libraries from EmbeddedJar, InputJar and AndroidJavaLibrary.. /// @@ -610,7 +601,7 @@ public static string XA1014 { return ResourceManager.GetString("XA1014", resourceCulture); } } - + /// /// Looks up a localized string similar to More than one Android Wear project is specified as the paired project. It can be at most one.. /// @@ -619,7 +610,7 @@ public static string XA1015 { return ResourceManager.GetString("XA1015", resourceCulture); } } - + /// /// Looks up a localized string similar to Target Wear application's project '{0}' does not specify required 'AndroidManifest' project property.. /// @@ -628,7 +619,7 @@ public static string XA1016 { return ResourceManager.GetString("XA1016", resourceCulture); } } - + /// /// Looks up a localized string similar to Target Wear application's AndroidManifest.xml does not specify required 'package' attribute.. /// @@ -637,7 +628,7 @@ public static string XA1017 { return ResourceManager.GetString("XA1017", resourceCulture); } } - + /// /// Looks up a localized string similar to Specified AndroidManifest file does not exist: {0}.. /// @@ -646,7 +637,7 @@ public static string XA1018 { return ResourceManager.GetString("XA1018", resourceCulture); } } - + /// /// Looks up a localized string similar to `LibraryProjectProperties` file `{0}` is located in a parent directory of the bindings project's intermediate output directory. Please adjust the path to use the original `project.properties` file directly from the Android library project directory.. /// @@ -655,7 +646,7 @@ public static string XA1019 { return ResourceManager.GetString("XA1019", resourceCulture); } } - + /// /// Looks up a localized string similar to At least one Java library is required for binding. Check that a Java library is included in the project and has the appropriate build action: 'LibraryProjectZip' (for AAR or ZIP), 'EmbeddedJar', 'InputJar' (for JAR), or 'LibraryProjectProperties' (project.properties).. /// @@ -664,7 +655,7 @@ public static string XA1020 { return ResourceManager.GetString("XA1020", resourceCulture); } } - + /// /// Looks up a localized string similar to Specified source Java library not found: {0}. /// @@ -673,7 +664,7 @@ public static string XA1021 { return ResourceManager.GetString("XA1021", resourceCulture); } } - + /// /// Looks up a localized string similar to Specified reference Java library not found: {0}. /// @@ -682,7 +673,7 @@ public static string XA1022 { return ResourceManager.GetString("XA1022", resourceCulture); } } - + /// /// Looks up a localized string similar to Using the DX DEX Compiler is not supported. Please set the DEX compiler to 'd8' in the Visual Studio project property pages or edit the project file in a text editor and set the 'AndroidDexTool' MSBuild property to 'd8'.. /// @@ -691,16 +682,16 @@ public static string XA1023 { return ResourceManager.GetString("XA1023", resourceCulture); } } - + /// - /// Looks up a localized string similar to Ignoring configuration file '{0}'. .NET configuration files are not supported in .NET Android projects that target .NET 6 or higher.. + /// Looks up a localized string similar to Ignoring configuration file '{0}'. .NET configuration files are not supported in Xamarin.Android projects that target .NET 6 or higher.. /// public static string XA1024 { get { return ResourceManager.GetString("XA1024", resourceCulture); } } - + /// /// Looks up a localized string similar to The experimental 'Hybrid' value for the 'AndroidAotMode' MSBuild property is not currently compatible with the armeabi-v7a target ABI. To continue using the experimental 'Hybrid' value for 'AndroidAotMode', deselect the armeabi-v7a target ABI in the Visual Studio project property pages or edit the project file in a text editor and remove 'armeabi-v7a' from the 'AndroidSupportedAbis' MSBuild property.. /// @@ -709,7 +700,7 @@ public static string XA1025 { return ResourceManager.GetString("XA1025", resourceCulture); } } - + /// /// Looks up a localized string similar to Using AAPT is deprecated in favor of AAPT2. Please enable 'Use incremental Android packaging system (aapt2)' in the Visual Studio project property pages or edit the project file in a text editor and set the 'AndroidUseAapt2' MSBuild property to 'true'.. /// @@ -718,16 +709,16 @@ public static string XA1026 { return ResourceManager.GetString("XA1026", resourceCulture); } } - + /// - /// Looks up a localized string similar to Using AAPT is not supported in .NET Android projects that target .NET 6 or higher. Please enable 'Use incremental Android packaging system (aapt2)' in the Visual Studio project property pages or edit the project file in a text editor and set the 'AndroidUseAapt2' MSBuild property to 'true'.. + /// Looks up a localized string similar to Using AAPT is not supported in Xamarin.Android projects that target .NET 6 or higher. Please enable 'Use incremental Android packaging system (aapt2)' in the Visual Studio project property pages or edit the project file in a text editor and set the 'AndroidUseAapt2' MSBuild property to 'true'.. /// public static string XA1026_dotnet { get { return ResourceManager.GetString("XA1026_dotnet", resourceCulture); } } - + /// /// Looks up a localized string similar to The 'EnableProguard' MSBuild property is set to 'true' and the 'AndroidLinkTool' MSBuild property is empty, so 'AndroidLinkTool' will default to 'proguard'.. /// @@ -736,7 +727,7 @@ public static string XA1027 { return ResourceManager.GetString("XA1027", resourceCulture); } } - + /// /// Looks up a localized string similar to The 'AndroidEnableProguard' MSBuild property is set to 'true' and the 'AndroidLinkTool' MSBuild property is empty, so 'AndroidLinkTool' will default to 'proguard'.. /// @@ -745,91 +736,7 @@ public static string XA1028 { return ResourceManager.GetString("XA1028", resourceCulture); } } - - /// - /// Looks up a localized string similar to The 'AotAssemblies' MSBuild property is deprecated. Edit the project file in a text editor to remove this property, and use the 'RunAOTCompilation' MSBuild property instead.. - /// - public static string XA1029 { - get { - return ResourceManager.GetString("XA1029", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The 'RunAOTCompilation' MSBuild property is only supported when trimming is enabled. Edit the project file in a text editor to set 'PublishTrimmed' to 'true' for this build configuration.. - /// - public static string XA1030 { - get { - return ResourceManager.GetString("XA1030", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The 'AndroidHttpClientHandlerType' property value '{0}' must derive from '{1}'. - ///Please change the value to an assembly-qualifed type name which inherits from '{1}' or remove the property completely.. - /// - public static string XA1031 { - get { - return ResourceManager.GetString("XA1031", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The 'AndroidHttpClientHandlerType' property value '{0}' must not derive from 'System.Net.Htt.HttpClientHandler'. - ///Please change the value to an assembly-qualifed type name which inherits from 'System.Net.Http.HttpMessageHandler' or remove the property completely.. - /// - public static string XA1031_HCH { - get { - return ResourceManager.GetString("XA1031_HCH", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Failed to resolve '{0}' from '{1}'. Please check your `AndroidHttpClientHandlerType` setting.. - /// - public static string XA1032 { - get { - return ResourceManager.GetString("XA1032", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Could not resolve '{0}'. Please check your `AndroidHttpClientHandlerType` setting.. - /// - public static string XA1033 { - get { - return ResourceManager.GetString("XA1033", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Your project references '{0}' which uses the `_Microsoft.Android.Resource.Designer` assembly, but you do not have this feature enabled. Please set the `AndroidUseDesignerAssembly` MSBuild property to `true` in your project file.. - /// - public static string XA1034 { - get { - return ResourceManager.GetString("XA1034", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The 'BundleAssemblies' property is deprecated and it has no effect on the application build. Equivalent functionality is implemented by the 'AndroidUseAssemblyStore' and 'AndroidEnableAssemblyCompression' properties.. - /// - public static string XA1035 { - get { - return ResourceManager.GetString("XA1035", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to AndroidManifest.xml //uses-sdk/@android:minSdkVersion '{0}' does not match the $(SupportedOSPlatformVersion) value '{1}' in the project file (if there is no $(SupportedOSPlatformVersion) value in the project file, then a default value has been assumed). - ///Either change the value in the AndroidManifest.xml to match the $(SupportedOSPlatformVersion) value, or remove the value in the AndroidManifest.xml (and add a $(SupportedOSPlatformVersion) value to the project file if it doesn't already exist).. - /// - public static string XA1036 { - get { - return ResourceManager.GetString("XA1036", resourceCulture); - } - } - + /// /// Looks up a localized string similar to The '{0}' MSBuild property is deprecated and will be removed in .NET {1}. See https://aka.ms/net-android-deprecations for more details.. /// @@ -840,23 +747,14 @@ public static string XA1037 { } /// - /// Looks up a localized string similar to The Android Support libraries are not supported in .NET 9 and later, please migrate to AndroidX. See https://aka.ms/xamarin/androidx for more details.. - /// - public static string XA1039 { - get { - return ResourceManager.GetString("XA1039", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use of AppDomain.CreateDomain() detected in assembly: {0}. .NET 6 and higher will only support a single AppDomain, so this API will no longer be available in .NET Android once .NET 6 is released.. + /// Looks up a localized string similar to Use of AppDomain.CreateDomain() detected in assembly: {0}. .NET 6 and higher will only support a single AppDomain, so this API will no longer be available in Xamarin.Android once .NET 6 is released.. /// public static string XA2000 { get { return ResourceManager.GetString("XA2000", resourceCulture); } } - + /// /// Looks up a localized string similar to Support for the 'MONO_GC_PARAMS=bridge-implementation=old' value will be removed in .NET 7.. /// @@ -865,7 +763,7 @@ public static string XA2000_gcParams_bridgeImpl { return ResourceManager.GetString("XA2000_gcParams_bridgeImpl", resourceCulture); } } - + /// /// Looks up a localized string similar to Source file '{0}' could not be found.. /// @@ -874,7 +772,7 @@ public static string XA2001 { return ResourceManager.GetString("XA2001", resourceCulture); } } - + /// /// Looks up a localized string similar to Can not resolve reference: `{0}`, referenced by {1}. Perhaps it doesn't exist in the Mono for Android profile?. /// @@ -883,7 +781,7 @@ public static string XA2002_Framework { return ResourceManager.GetString("XA2002_Framework", resourceCulture); } } - + /// /// Looks up a localized string similar to Can not resolve reference: `{0}`, referenced by {1}. Please add a NuGet package or assembly reference for `{0}`, or remove the reference to `{2}`.. /// @@ -892,7 +790,7 @@ public static string XA2002_NuGet { return ResourceManager.GetString("XA2002_NuGet", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not resolve reference to '{0}' (defined in assembly '{1}') with scope '{2}'. When the scope is different from the defining assembly, it usually means that the type is forwarded.. /// @@ -901,7 +799,7 @@ public static string XA2006 { return ResourceManager.GetString("XA2006", resourceCulture); } } - + /// /// Looks up a localized string similar to Exception while loading assemblies: {0}. /// @@ -910,7 +808,7 @@ public static string XA2007 { return ResourceManager.GetString("XA2007", resourceCulture); } } - + /// /// Looks up a localized string similar to In referenced assembly {0}, Java.Interop.DoNotPackageAttribute requires non-null file name.. /// @@ -919,7 +817,25 @@ public static string XA2008 { return ResourceManager.GetString("XA2008", resourceCulture); } } - + + /// + /// Looks up a localized string similar to This is probably caused by the project exceeding the Max Path length. Please move your entire project closer to the Root of the drive.. + /// + public static string APT2264 { + get { + return ResourceManager.GetString("APT2264", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to This could be caused by the project having non-ASCII characters in it path. + /// + public static string APT2265 { + get { + return ResourceManager.GetString("APT2265", resourceCulture); + } + } + /// /// Looks up a localized string similar to Could not AOT the assembly: {0}. /// @@ -928,7 +844,7 @@ public static string XA3001 { return ResourceManager.GetString("XA3001", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid AOT mode: {0}. /// @@ -937,7 +853,7 @@ public static string XA3002 { return ResourceManager.GetString("XA3002", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not strip IL of assembly: {0}. /// @@ -946,7 +862,7 @@ public static string XA3003 { return ResourceManager.GetString("XA3003", resourceCulture); } } - + /// /// Looks up a localized string similar to Android NDK r10d is buggy and provides an incompatible x86_64 libm.so. See https://code.google.com/p/android/issues/detail?id=161422.. /// @@ -955,7 +871,7 @@ public static string XA3004 { return ResourceManager.GetString("XA3004", resourceCulture); } } - + /// /// Looks up a localized string similar to The detected Android NDK version is incompatible with the targeted LLVM configuration. Please upgrade to NDK r10d or newer.. /// @@ -964,25 +880,25 @@ public static string XA3005 { return ResourceManager.GetString("XA3005", resourceCulture); } } - + /// - /// Looks up a localized string similar to Could not compile native assembly file: {0}{1}. + /// Looks up a localized string similar to Could not compile native assembly file: {0}. /// public static string XA3006 { get { return ResourceManager.GetString("XA3006", resourceCulture); } } - + /// - /// Looks up a localized string similar to Could not link native shared library: {0}{1}. + /// Looks up a localized string similar to Could not link native shared library: {0}. /// public static string XA3007 { get { return ResourceManager.GetString("XA3007", resourceCulture); } } - + /// /// Looks up a localized string similar to Failed to generate Java type for class: {0} due to {1}. /// @@ -991,7 +907,7 @@ public static string XA4209 { return ResourceManager.GetString("XA4209", resourceCulture); } } - + /// /// Looks up a localized string similar to Please add a reference to Mono.Android.Export.dll when using ExportAttribute or ExportFieldAttribute.. /// @@ -1000,7 +916,7 @@ public static string XA4210 { return ResourceManager.GetString("XA4210", resourceCulture); } } - + /// /// Looks up a localized string similar to AndroidManifest.xml //uses-sdk/@android:targetSdkVersion '{0}' is less than $(TargetFrameworkVersion) '{1}'. Using API-{2} for ACW compilation.. /// @@ -1009,7 +925,7 @@ public static string XA4211 { return ResourceManager.GetString("XA4211", resourceCulture); } } - + /// /// Looks up a localized string similar to The type '{0}' must provide a public default constructor. /// @@ -1018,7 +934,7 @@ public static string XA4213 { return ResourceManager.GetString("XA4213", resourceCulture); } } - + /// /// Looks up a localized string similar to The managed type `{0}` exists in multiple assemblies: {1}. Please refactor the managed type names in these assemblies so that they are not identical.. /// @@ -1027,7 +943,7 @@ public static string XA4214 { return ResourceManager.GetString("XA4214", resourceCulture); } } - + /// /// Looks up a localized string similar to References to the type `{0}` will refer to `{0}, {1}`.. /// @@ -1036,7 +952,7 @@ public static string XA4214_Result { return ResourceManager.GetString("XA4214_Result", resourceCulture); } } - + /// /// Looks up a localized string similar to The Java type `{0}` is generated by more than one managed type. Please change the [Register] attribute so that the same Java type is not emitted.. /// @@ -1045,7 +961,7 @@ public static string XA4215 { return ResourceManager.GetString("XA4215", resourceCulture); } } - + /// /// Looks up a localized string similar to `{0}` generated by: {1}. /// @@ -1054,25 +970,25 @@ public static string XA4215_Details { return ResourceManager.GetString("XA4215_Details", resourceCulture); } } - + /// - /// Looks up a localized string similar to The deployment target '{0}' is not supported (the minimum is '{1}'). Please increase (or remove) the //uses-sdk/@android:minSdkVersion value in your AndroidManifest.xml.. + /// Looks up a localized string similar to The deployment target '{1}' is not supported (the minimum is '{2}'). Please increase (or remove) the //uses-sdk/@android:minSdkVersion value in your AndroidManifest.xml.. /// public static string XA4216_MinSdkVersion { get { return ResourceManager.GetString("XA4216_MinSdkVersion", resourceCulture); } } - + /// - /// Looks up a localized string similar to The deployment target '{0}' is not supported (the minimum is '{1}'). Please increase the $(SupportedOSPlatformVersion) property value in your project file.. + /// Looks up a localized string similar to The deployment target '{1}' is not supported (the minimum is '{2}'). Please increase the $(SupportedOSPlatformVersion) property value in your project file.. /// public static string XA4216_SupportedOSPlatformVersion { get { return ResourceManager.GetString("XA4216_SupportedOSPlatformVersion", resourceCulture); } } - + /// /// Looks up a localized string similar to AndroidManifest.xml //uses-sdk/@android:targetSdkVersion '{0}' is less than API-{1}, this configuration is not supported.. /// @@ -1081,7 +997,7 @@ public static string XA4216_TargetSdkVersion { return ResourceManager.GetString("XA4216_TargetSdkVersion", resourceCulture); } } - + /// /// Looks up a localized string similar to Unable to find //manifest/application/uses-library at path: {0}. /// @@ -1090,7 +1006,7 @@ public static string XA4218 { return ResourceManager.GetString("XA4218", resourceCulture); } } - + /// /// Looks up a localized string similar to Cannot find binding generator for language {0} or {1}.. /// @@ -1099,7 +1015,7 @@ public static string XA4219 { return ResourceManager.GetString("XA4219", resourceCulture); } } - + /// /// Looks up a localized string similar to Partial class item '{0}' does not have an associated binding for layout '{1}'.. /// @@ -1108,7 +1024,7 @@ public static string XA4220 { return ResourceManager.GetString("XA4220", resourceCulture); } } - + /// /// Looks up a localized string similar to No layout binding source files were generated.. /// @@ -1117,7 +1033,7 @@ public static string XA4221 { return ResourceManager.GetString("XA4221", resourceCulture); } } - + /// /// Looks up a localized string similar to No widgets found for layout ({0}).. /// @@ -1126,7 +1042,7 @@ public static string XA4222 { return ResourceManager.GetString("XA4222", resourceCulture); } } - + /// /// Looks up a localized string similar to Malformed full class name '{0}'. Missing namespace.. /// @@ -1135,7 +1051,7 @@ public static string XA4223 { return ResourceManager.GetString("XA4223", resourceCulture); } } - + /// /// Looks up a localized string similar to Malformed full class name '{0}'. Missing class name.. /// @@ -1144,7 +1060,7 @@ public static string XA4224 { return ResourceManager.GetString("XA4224", resourceCulture); } } - + /// /// Looks up a localized string similar to Widget '{0}' in layout '{1}' has multiple instances with different types. The property type will be set to: {2}. /// @@ -1153,7 +1069,7 @@ public static string XA4225 { return ResourceManager.GetString("XA4225", resourceCulture); } } - + /// /// Looks up a localized string similar to Resource item '{0}' does not have the required metadata item '{1}'.. /// @@ -1162,7 +1078,7 @@ public static string XA4226 { return ResourceManager.GetString("XA4226", resourceCulture); } } - + /// /// Looks up a localized string similar to Unable to find specified //activity-alias/@android:targetActivity: '{0}'. /// @@ -1171,7 +1087,7 @@ public static string XA4228 { return ResourceManager.GetString("XA4228", resourceCulture); } } - + /// /// Looks up a localized string similar to Unrecognized `TransformFile` root element: {0}.. /// @@ -1180,7 +1096,7 @@ public static string XA4229 { return ResourceManager.GetString("XA4229", resourceCulture); } } - + /// /// Looks up a localized string similar to Error parsing XML: {0}. /// @@ -1189,25 +1105,25 @@ public static string XA4230 { return ResourceManager.GetString("XA4230", resourceCulture); } } - + /// - /// Looks up a localized string similar to The Android class parser value '{0}' is deprecated and will be removed in a future version of .NET Android. Update the project properties to use 'class-parse'.. + /// Looks up a localized string similar to The Android class parser value '{0}' is deprecated and will be removed in a future version of Xamarin.Android. Update the project properties to use 'class-parse'.. /// public static string XA4231 { get { return ResourceManager.GetString("XA4231", resourceCulture); } } - + /// - /// Looks up a localized string similar to The Android code generation target '{0}' is deprecated and will be removed in a future version of .NET Android. Update the project properties to use 'XAJavaInterop1'.. + /// Looks up a localized string similar to The Android code generation target '{0}' is deprecated and will be removed in a future version of Xamarin.Android. Update the project properties to use 'XAJavaInterop1'.. /// public static string XA4232 { get { return ResourceManager.GetString("XA4232", resourceCulture); } } - + /// /// Looks up a localized string similar to The <AndroidNamespaceReplacement> for '{0}' does not specify a 'Replacement' attribute.. /// @@ -1218,7 +1134,7 @@ public static string XA4233 { } /// - /// Looks up a localized string similar to '<{0}>' item '{1}' is missing required attribute '{2}'.. + /// Looks up a localized string similar to '<{0}>' item '{1}' is missing required metadata '{2}'. /// public static string XA4234 { get { @@ -1247,8 +1163,8 @@ public static string XA4236 { } /// - /// Looks up a localized string similar to Cannot download POM file for Maven artifact '{0}'. - ///- {1}. + /// Looks up a localized string similar to Cannot download POM file for Maven artifact '{0}:{1}'. + ///- {2}: {3}. /// public static string XA4237 { get { @@ -1256,6 +1172,16 @@ public static string XA4237 { } } + /// + /// Looks up a localized string similar to Cannot download parent POM file for Maven artifact '{0}:{1}'. + ///- {2}: {3}. + /// + public static string XA4238 { + get { + return ResourceManager.GetString("XA4238", resourceCulture); + } + } + /// /// Looks up a localized string similar to Unknown Maven repository: '{0}'.. /// @@ -1346,7 +1272,7 @@ public static string XA4300 { return ResourceManager.GetString("XA4300", resourceCulture); } } - + /// /// Looks up a localized string similar to APK already contains the item {0}; ignoring.. /// @@ -1355,7 +1281,7 @@ public static string XA4301 { return ResourceManager.GetString("XA4301", resourceCulture); } } - + /// /// Looks up a localized string similar to Cannot determine ABI of native library '{0}'. Move this file to a directory with a valid Android ABI name such as 'libs/armeabi-v7a/'.. /// @@ -1364,7 +1290,7 @@ public static string XA4301_ABI { return ResourceManager.GetString("XA4301_ABI", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not determine ABI of some native libraries. Ignoring those: {0}. /// @@ -1373,7 +1299,7 @@ public static string XA4301_ABI_Ignoring { return ResourceManager.GetString("XA4301_ABI_Ignoring", resourceCulture); } } - + /// /// Looks up a localized string similar to Cannot determine ABI of native library '{0}'. Remove the '{1}' NuGet package, or notify the library author.. /// @@ -1382,7 +1308,7 @@ public static string XA4301_ABI_NuGet { return ResourceManager.GetString("XA4301_ABI_NuGet", resourceCulture); } } - + /// /// Looks up a localized string similar to Unhandled exception merging `AndroidManifest.xml`: {0}. /// @@ -1391,7 +1317,7 @@ public static string XA4302 { return ResourceManager.GetString("XA4302", resourceCulture); } } - + /// /// Looks up a localized string similar to Error extracting resources from "{0}": {1}. /// @@ -1400,7 +1326,7 @@ public static string XA4303 { return ResourceManager.GetString("XA4303", resourceCulture); } } - + /// /// Looks up a localized string similar to ProGuard configuration file '{0}' was not found.. /// @@ -1409,7 +1335,7 @@ public static string XA4304 { return ResourceManager.GetString("XA4304", resourceCulture); } } - + /// /// Looks up a localized string similar to Multidex is enabled, but `$(_AndroidMainDexListFile)` is empty.. /// @@ -1418,7 +1344,7 @@ public static string XA4305 { return ResourceManager.GetString("XA4305", resourceCulture); } } - + /// /// Looks up a localized string similar to Multidex is enabled, but the `$(_AndroidMainDexListFile)` file '{0}' does not exist.. /// @@ -1427,7 +1353,7 @@ public static string XA4305_File_Missing { return ResourceManager.GetString("XA4305_File_Missing", resourceCulture); } } - + /// /// Looks up a localized string similar to R8 does not support `@(MultiDexMainDexList)` files when android:minSdkVersion >= 21. /// @@ -1436,7 +1362,7 @@ public static string XA4306 { return ResourceManager.GetString("XA4306", resourceCulture); } } - + /// /// Looks up a localized string similar to Invalid ProGuard configuration file. {0}. /// @@ -1445,7 +1371,7 @@ public static string XA4307 { return ResourceManager.GetString("XA4307", resourceCulture); } } - + /// /// Looks up a localized string similar to Failed to generate type maps. /// @@ -1454,7 +1380,7 @@ public static string XA4308 { return ResourceManager.GetString("XA4308", resourceCulture); } } - + /// /// Looks up a localized string similar to 'MultiDexMainDexList' file '{0}' does not exist.. /// @@ -1463,7 +1389,7 @@ public static string XA4309 { return ResourceManager.GetString("XA4309", resourceCulture); } } - + /// /// Looks up a localized string similar to `{0}` file `{1}` could not be found.. /// @@ -1472,7 +1398,7 @@ public static string XA4310 { return ResourceManager.GetString("XA4310", resourceCulture); } } - + /// /// Looks up a localized string similar to The application won't contain the paired Wear package because the Wear application package APK is not created yet. If building on the command line, be sure to build the "SignAndroidPackage" target.. /// @@ -1481,16 +1407,16 @@ public static string XA4311 { return ResourceManager.GetString("XA4311", resourceCulture); } } - + /// - /// Looks up a localized string similar to Referencing the Android Wear application project '{0}' from an Android application project is deprecated and will no longer be supported in a future version of .NET Android. Remove the Android Wear application project reference from the Android application project and distribute the Wear application as a standalone application instead.. + /// Looks up a localized string similar to Referencing the Android Wear application project '{0}' from an Android application project is deprecated and will no longer be supported in a future version of Xamarin.Android. Remove the Android Wear application project reference from the Android application project and distribute the Wear application as a standalone application instead.. /// public static string XA4312 { get { return ResourceManager.GetString("XA4312", resourceCulture); } } - + /// /// Looks up a localized string similar to The built-in '{0}' reference has been deprecated. ///Remove the '{0}' reference from your project and add the '{1}' NuGet package instead. @@ -1501,7 +1427,7 @@ public static string XA4313 { return ResourceManager.GetString("XA4313", resourceCulture); } } - + /// /// Looks up a localized string similar to `{0}` is empty. A value for `{0}` should be provided.. /// @@ -1510,7 +1436,7 @@ public static string XA4314 { return ResourceManager.GetString("XA4314", resourceCulture); } } - + /// /// Looks up a localized string similar to Missing Android NDK toolchains directory '{0}'. Please install the Android NDK.. /// @@ -1519,7 +1445,7 @@ public static string XA5101 { return ResourceManager.GetString("XA5101", resourceCulture); } } - + /// /// Looks up a localized string similar to C compiler for target {0} was not found. Tried paths: "{1}". /// @@ -1528,7 +1454,7 @@ public static string XA5101_C_Compiler { return ResourceManager.GetString("XA5101_C_Compiler", resourceCulture); } } - + /// /// Looks up a localized string similar to Toolchain directory for target {0} was not found.. /// @@ -1537,7 +1463,7 @@ public static string XA5101_Toolchain { return ResourceManager.GetString("XA5101_Toolchain", resourceCulture); } } - + /// /// Looks up a localized string similar to Conversion from assembly to native code failed. Exit code {0}. /// @@ -1546,7 +1472,7 @@ public static string XA5102 { return ResourceManager.GetString("XA5102", resourceCulture); } } - + /// /// Looks up a localized string similar to NDK C compiler exited with an error. Exit code {0}. /// @@ -1555,7 +1481,7 @@ public static string XA5103 { return ResourceManager.GetString("XA5103", resourceCulture); } } - + /// /// Looks up a localized string similar to Could not locate the Android NDK. Please make sure the Android NDK is installed in the Android SDK Manager, or if using a custom NDK path, please ensure the $(AndroidNdkDirectory) MSBuild property is set to the custom path.. /// @@ -1564,7 +1490,7 @@ public static string XA5104 { return ResourceManager.GetString("XA5104", resourceCulture); } } - + /// /// Looks up a localized string similar to Toolchain utility '{0}' for target {1} was not found. Tried in path: "{2}". /// @@ -1573,7 +1499,7 @@ public static string XA5105 { return ResourceManager.GetString("XA5105", resourceCulture); } } - + /// /// Looks up a localized string similar to NDK linker exited with an error. Exit code {0}. /// @@ -1582,7 +1508,7 @@ public static string XA5201 { return ResourceManager.GetString("XA5201", resourceCulture); } } - + /// /// Looks up a localized string similar to Cannot find `{0}`. Please install the Android SDK Build-Tools package with the `{1}{2}tools{2}{3}` program.. /// @@ -1591,7 +1517,7 @@ public static string XA5205 { return ResourceManager.GetString("XA5205", resourceCulture); } } - + /// /// Looks up a localized string similar to Cannot find `{0}` in the Android SDK. Please set its path via /p:LintToolPath.. /// @@ -1600,36 +1526,34 @@ public static string XA5205_Lint { return ResourceManager.GetString("XA5205_Lint", resourceCulture); } } - + /// - /// Looks up a localized string similar to Could not find android.jar for API level {0}. This means the Android SDK platform for API level {0} is not installed; it was expected to be in `{1}`. - ///{2} - ///See https://aka.ms/xa5207 for more details.. + /// Looks up a localized string similar to Could not find android.jar for API level {0}. This means the Android SDK platform for API level {0} is not installed. Either install it in the Android SDK Manager ({2}), or change the Xamarin.Android project to target an API version that is installed. ({1} missing.). /// public static string XA5207 { get { return ResourceManager.GetString("XA5207", resourceCulture); } } - + /// - /// Looks up a localized string similar to You can install the missing API level by running `dotnet build -t:InstallAndroidDependencies -f {0} "-p:AndroidSdkDirectory={1}"`, or change the project to target an API version that is installed.. + /// Looks up a localized string similar to Tools > Android > Android SDK Manager.... /// - public static string XA5207_SDK_Manager_CLI { + public static string XA5207_SDK_Manager_Windows { get { - return ResourceManager.GetString("XA5207_SDK_Manager_CLI", resourceCulture); + return ResourceManager.GetString("XA5207_SDK_Manager_Windows", resourceCulture); } } - + /// - /// Looks up a localized string similar to Either install it in the Android SDK Manager (Tools > Android > Android SDK Manager...), or change the .NET Android project to target an API version that is installed.. + /// Looks up a localized string similar to Tools > Open Android SDK Manager.... /// - public static string XA5207_SDK_Manager_Windows { + public static string XA5207_SDK_Manager_CLI { get { - return ResourceManager.GetString("XA5207_SDK_Manager_Windows", resourceCulture); + return ResourceManager.GetString("XA5207_SDK_Manager_CLI", resourceCulture); } } - + /// /// Looks up a localized string similar to Embedded Wear app package name differs from handheld app package name ({0} != {1}).. /// @@ -1638,7 +1562,7 @@ public static string XA5211 { return ResourceManager.GetString("XA5211", resourceCulture); } } - + /// /// Looks up a localized string similar to java.lang.OutOfMemoryError. Consider increasing the value of $(JavaMaximumHeapSize). Java ran out of memory while executing '{0} {1}'. /// @@ -1647,7 +1571,7 @@ public static string XA5213 { return ResourceManager.GetString("XA5213", resourceCulture); } } - + /// /// Looks up a localized string similar to No Android platforms installed at '{0}'. Please install an SDK Platform with the `{1}{2}tools{2}{3}` program.. /// @@ -1656,27 +1580,25 @@ public static string XA5300_Android_Platforms { return ResourceManager.GetString("XA5300_Android_Platforms", resourceCulture); } } - + /// - /// Looks up a localized string similar to The Android SDK directory could not be found. Install the Android SDK by following the instructions at: https://aka.ms/dotnet-android-install-sdk - ///To use a custom SDK path for a command line build, set the 'AndroidSdkDirectory' MSBuild property to the custom path.. + /// Looks up a localized string similar to The Android SDK directory could not be found. Check that the Android SDK Manager in Visual Studio shows a valid installation. To use a custom SDK path for a command line build, set the 'AndroidSdkDirectory' MSBuild property to the custom path.. /// public static string XA5300_Android_SDK { get { return ResourceManager.GetString("XA5300_Android_SDK", resourceCulture); } } - + /// - /// Looks up a localized string similar to The Java SDK directory could not be found. Install the Java SDK by following the instructions at: https://aka.ms/dotnet-android-install-sdk - ///To use a custom JDK path for a command line build, set the 'JavaSdkDirectory' MSBuild property to the custom path.. + /// Looks up a localized string similar to The Java SDK directory could not be found. Ensure that the Android section of the Visual Studio options has a valid Java SDK directory configured. To use a custom SDK path for a command line build, set the 'JavaSdkDirectory' MSBuild property to the custom path.. /// public static string XA5300_Java_SDK { get { return ResourceManager.GetString("XA5300_Java_SDK", resourceCulture); } } - + /// /// Looks up a localized string similar to Failed to generate Java type for class: {0} due to MAX_PATH: {1}. /// @@ -1685,7 +1607,7 @@ public static string XA5301 { return ResourceManager.GetString("XA5301", resourceCulture); } } - + /// /// Looks up a localized string similar to Two processes may be building this project at once. Lock file exists at path: {0}. /// @@ -1694,13 +1616,61 @@ public static string XA5302 { return ResourceManager.GetString("XA5302", resourceCulture); } } - + /// - /// Looks up a localized string similar to Could not find Android Resource '{0}'. Please update @(AndroidResource) to add the missing resource.. + /// Looks up a localized string similar to The 'AndroidHttpClientHandlerType' property value '{0}' must derive from '{1}'. + ///Please change the value to an assembly-qualifed type name which inherits from '{1}' or remove the property completely. /// - public static string XA8000 { + public static string XA1031 { get { - return ResourceManager.GetString("XA8000", resourceCulture); + return ResourceManager.GetString("XA1031", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The 'AndroidHttpClientHandlerType' property value '{0}' must not derive from 'System.Net.Htt.HttpClientHandler'. + ///Please change the value to an assembly-qualifed type name which inherits from 'System.Net.Http.HttpMessageHandler' or remove the property completely. + /// + public static string XA1031_HCH { + get { + return ResourceManager.GetString("XA1031_HCH", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Two processes may be building this project at once. Lock file exists at path: {0}. + /// + public static string XA1032 { + get { + return ResourceManager.GetString("XA1032", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Two processes may be building this project at once. Lock file exists at path: {0}. + /// + public static string XA1033 { + get { + return ResourceManager.GetString("XA1033", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Your project references '{0}' which uses the `_Microsoft.Android.Resource.Designer` assembly, but you do not have this feature enabled. Please set the `AndroidUseDesignerAssembly` MSBuild property to `true` in your project file. + /// + public static string XA1034 { + get { + return ResourceManager.GetString("XA1034", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AndroidManifest.xml //uses-sdk/@android:minSdkVersion '{0}' does not match the $(SupportedOSPlatformVersion) value '{1}' in the project file (if there is no $(SupportedOSPlatformVersion) value in the project file, then a default value has been assumed). + ///Either change the value in the AndroidManifest.xml to match the $(SupportedOSPlatformVersion) value, or remove the value in the AndroidManifest.xml (and add a $(SupportedOSPlatformVersion) value to the project file if it doesn't already exist).. + /// + public static string XA1036 { + get { + return ResourceManager.GetString("XA1036", resourceCulture); } } From f86d3e7c256555637607f64c2d73161e62e6b325 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Wed, 20 Mar 2024 14:43:03 -0400 Subject: [PATCH 10/12] Update ResolvingJavaDependencies.md Fix formatting. --- Documentation/guides/ResolvingJavaDependencies.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/guides/ResolvingJavaDependencies.md b/Documentation/guides/ResolvingJavaDependencies.md index 9a97caaad34..3bc48d0aa02 100644 --- a/Documentation/guides/ResolvingJavaDependencies.md +++ b/Documentation/guides/ResolvingJavaDependencies.md @@ -78,9 +78,11 @@ To include the Java library but not produce C# bindings for it, mark it with `Bi Alternatively, `` can be used to retrieve a Java library from a Maven repository: -``` +```xml + + ``` @@ -96,4 +98,4 @@ Note that while the error message will go away, it does not mean the package wil -``` \ No newline at end of file +``` From e132070db7fe54561c547b0fc2c9ed15f3e17a01 Mon Sep 17 00:00:00 2001 From: Jonathan Pobst Date: Wed, 20 Mar 2024 11:02:32 -1000 Subject: [PATCH 11/12] Review feedback. --- .../Tasks/GetMicrosoftNuGetPackagesMap.cs | 5 +++-- .../Tasks/JavaDependencyVerification.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GetMicrosoftNuGetPackagesMap.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GetMicrosoftNuGetPackagesMap.cs index bbe8d3528bc..d6a1557944d 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GetMicrosoftNuGetPackagesMap.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GetMicrosoftNuGetPackagesMap.cs @@ -13,6 +13,8 @@ namespace Xamarin.Android.Tasks; public class GetMicrosoftNuGetPackagesMap : AndroidAsyncTask { + static readonly HttpClient http_client = new HttpClient (); + public override string TaskPrefix => "GNP"; /// @@ -36,8 +38,7 @@ public override async System.Threading.Tasks.Task RunTaskAsync () if (!all_files.Any (x => x.IsToday)) { // No file for today, download a new one try { - using var http = new HttpClient (); - var json = await http.GetStringAsync ("https://aka.ms/ms-nuget-packages"); + var json = await http_client.GetStringAsync ("https://aka.ms/ms-nuget-packages"); var outfile = Path.Combine (MavenCacheDirectory, $"microsoft-packages-{DateTime.Today:yyyyMMdd}.json"); File.WriteAllText (outfile, json); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs b/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs index 3373e1b095f..441e1b3ccd5 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/JavaDependencyVerification.cs @@ -140,7 +140,7 @@ public bool EnsureDependencySatisfied (ResolvedDependency dependency, MicrosoftN if (suggestion is string nuget) log.LogCodedError ("XA4242", Properties.Resources.XA4242, artifact_spec, nuget); else - log.LogCodedError ("XA4242", Properties.Resources.XA4241, artifact_spec); + log.LogCodedError ("XA4241", Properties.Resources.XA4241, artifact_spec); return false; } From 45c6feb31bbc2f56c50ad6ed520f5c50f1708077 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Fri, 22 Mar 2024 15:09:26 -0400 Subject: [PATCH 12/12] Fix XML formatting. --- ...id.Bindings.JavaDependencyVerification.targets | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.JavaDependencyVerification.targets b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.JavaDependencyVerification.targets index 31d59919a65..7fa94d517d1 100644 --- a/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.JavaDependencyVerification.targets +++ b/src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Bindings.JavaDependencyVerification.targets @@ -25,13 +25,14 @@ that Java binding dependencies are satisfied. + AndroidLibraries="@(AndroidLibrary)" + AdditionalManifests="@(AndroidAdditionalJavaManifest)" + PackageReferences="@(PackageReference)" + ProjectReferences="@(ProjectReference)" + IgnoredDependencies="@(AndroidIgnoredJavaDependency)" + MicrosoftPackagesFile="$(_ResolvedPackageMap)" + ProjectAssetsLockFile="$(ProjectAssetsFile)" + />