Skip to content

Commit aa05045

Browse files
dellis1972jonpryor
authored andcommitted
[Xamarin.Android.Build.Tasks] Handle Ref Assemblies from Nuget (#3938)
Fixes: #3920 Context: https://github.com/mattleibow/NuGetFoldersTest What is a [reference assembly][0]? The short & glib answer is "an assembly with the [`[assembly:ReferenceAssemblyAttribute]`][1] custom attribute". Unfortunately, the short & glib answer is incomplete: NuGet also has a convention in that assemblies within a [`/ref/` directory][2] are treated as reference assemblies: > …if you want to provide the corresponding compile time assembly > as well then have `AnyCPU` assembly in `/ref/{tfm}` folder. > > Please note, NuGet always picks these compile or runtime assets > from one folder so if there are some compatible assets from `/ref` > then `/lib` will be ignored to add compile-time assemblies. Unfortunately, the `<ResolveAssemblies/>` task only treated assemblies with `[assembly:ReferenceAssembly]` as reference assemblies, not the "NuGet `/ref/` convention" assemblies. Consequently, we would never switch out the "reference assembly" for the `monodroid90`-profile assembly during build time. Update `<ResolveAssemblies/>` so that NuGet-style assemblies located within a `/ref/` directory are treated as reference assemblies, even if they do *not* have the `[assembly:ReferenceAssembly]` attribute. [0]: https://docs.microsoft.com/en-us/dotnet/standard/assembly/reference-assemblies [1]: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.referenceassemblyattribute?view=netframework-4.8 [2]: https://docs.microsoft.com/en-us/nuget/create-packages/supporting-multiple-target-frameworks#architecture-specific-folders
1 parent dd49af3 commit aa05045

File tree

6 files changed

+103
-6
lines changed

6 files changed

+103
-6
lines changed

src/Xamarin.Android.Build.Tasks/Tasks/ResolveAssemblies.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ void Execute (MetadataResolver resolver)
8585
foreach (var assembly in Assemblies) {
8686
// Add each user assembly and all referenced assemblies (recursive)
8787
string resolved_assembly = resolver.Resolve (assembly.ItemSpec);
88-
if (MonoAndroidHelper.IsReferenceAssembly (resolved_assembly)) {
88+
bool refAssembly = !string.IsNullOrEmpty (assembly.GetMetadata ("NuGetPackageId")) && resolved_assembly.Contains ($"{Path.DirectorySeparatorChar}ref{Path.DirectorySeparatorChar}");
89+
if (refAssembly || MonoAndroidHelper.IsReferenceAssembly (resolved_assembly)) {
8990
// Resolve "runtime" library
9091
if (lockFile != null)
9192
resolved_assembly = ResolveRuntimeAssemblyForReferenceAssembly (lockFile, assembly.ItemSpec);
@@ -176,6 +177,8 @@ string ResolveRuntimeAssemblyForReferenceAssembly (LockFile lockFile, string ass
176177
}
177178
foreach (var folder in lockFile.PackageFolders) {
178179
var path = assemblyPath.Replace (folder.Path, string.Empty);
180+
if (path.StartsWith ($"{Path.DirectorySeparatorChar}"))
181+
path = path.Substring (1);
179182
var libraryPath = lockFile.Libraries.FirstOrDefault (x => path.StartsWith (x.Path.Replace('/', Path.DirectorySeparatorChar), StringComparison.OrdinalIgnoreCase));
180183
if (libraryPath == null)
181184
continue;

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.IO;
33
using NUnit.Framework;
44
using Xamarin.ProjectTools;
@@ -644,5 +644,89 @@ protected override void OnCreate (Bundle bundle)
644644
}
645645
}
646646
}
647+
648+
[Test]
649+
public void CheckTheCorrectRuntimeAssemblyIsUsedFromNuget ()
650+
{
651+
string monoandroidFramework;
652+
using (var builder = new Builder ()) {
653+
monoandroidFramework = builder.LatestMultiTargetFrameworkVersion ();
654+
}
655+
string path = Path.Combine (Root, "temp", TestName);
656+
var ns = new DotNetStandard () {
657+
ProjectName = "Dummy",
658+
Sdk = "MSBuild.Sdk.Extras/2.0.54",
659+
Sources = {
660+
new BuildItem.Source ("Class1.cs") {
661+
TextContent = () => @"public class Class1 {
662+
#if __ANDROID__
663+
public static string Library => ""Android"";
664+
#else
665+
public static string Library => "".NET Standard"";
666+
#endif
667+
}",
668+
},
669+
},
670+
OtherBuildItems = {
671+
new BuildItem.NoActionResource ("$(OutputPath)netstandard2.0\\$(AssemblyName).dll") {
672+
TextContent = null,
673+
BinaryContent = null,
674+
Metadata = {
675+
{ "PackagePath", "ref\\netstandard2.0" },
676+
{ "Pack", "True" }
677+
},
678+
},
679+
new BuildItem.NoActionResource ($"$(OutputPath){monoandroidFramework}\\$(AssemblyName).dll") {
680+
TextContent = null,
681+
BinaryContent = null,
682+
Metadata = {
683+
{ "PackagePath", $"lib\\{monoandroidFramework}" },
684+
{ "Pack", "True" }
685+
},
686+
},
687+
},
688+
};
689+
ns.SetProperty ("TargetFrameworks", $"netstandard2.0;{monoandroidFramework}");
690+
ns.SetProperty ("PackageId", "dummy.package.foo");
691+
ns.SetProperty ("PackageVersion", "1.0.0");
692+
ns.SetProperty ("GeneratePackageOnBuild", "True");
693+
ns.SetProperty ("IncludeBuildOutput", "False");
694+
ns.SetProperty ("Summary", "Test");
695+
ns.SetProperty ("Description", "Test");
696+
ns.SetProperty ("PackageOutputPath", path);
697+
698+
699+
var xa = new XamarinAndroidApplicationProject () {
700+
ProjectName = "App",
701+
PackageReferences = {
702+
new Package () {
703+
Id = "dummy.package.foo",
704+
Version = "1.0.0",
705+
},
706+
},
707+
OtherBuildItems = {
708+
new BuildItem.NoActionResource ("NuGet.config") {
709+
},
710+
},
711+
};
712+
xa.SetProperty ("RestoreNoCache", "true");
713+
xa.SetProperty ("RestorePackagesPath", "$(MSBuildThisFileDirectory)packages");
714+
using (var nsb = CreateDllBuilder (Path.Combine (path, ns.ProjectName), cleanupAfterSuccessfulBuild: false, cleanupOnDispose: false))
715+
using (var xab = CreateApkBuilder (Path.Combine (path, xa.ProjectName), cleanupAfterSuccessfulBuild: false, cleanupOnDispose: false)) {
716+
nsb.ThrowOnBuildFailure = xab.ThrowOnBuildFailure = false;
717+
Assert.IsTrue (nsb.Build (ns), "Build of NetStandard Library should have succeeded.");
718+
Assert.IsFalse (xab.Build (xa, doNotCleanupOnUpdate: true), "Build of App Library should have failed.");
719+
File.WriteAllText (Path.Combine (Root, xab.ProjectDirectory, "NuGet.config"), @"<?xml version='1.0' encoding='utf-8'?>
720+
<configuration>
721+
<packageSources>
722+
<add key='nuget.org' value='https://api.nuget.org/v3/index.json' protocolVersion='3' />
723+
<add key='bug-testing' value='..' />
724+
</packageSources>
725+
</configuration>");
726+
Assert.IsTrue (xab.Build (xa, doNotCleanupOnUpdate: true), "Build of App Library should have succeeded.");
727+
string expected = Path.Combine ("dummy.package.foo", "1.0.0", "lib", monoandroidFramework, "Dummy.dll");
728+
Assert.IsTrue (xab.LastBuildOutput.ContainsText (expected), $"Build should be using {expected}");
729+
}
730+
}
647731
}
648732
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,15 @@ public string LatestTargetFrameworkVersion () {
167167
return lastFrameworkVersion;
168168
}
169169

170+
public string LatestMultiTargetFrameworkVersion ()
171+
{
172+
GetTargetFrameworkVersionRange (out string _, out string _, out string _, out string lastFrameworkVersion);
173+
lastFrameworkVersion = lastFrameworkVersion.Replace ("v", string.Empty);
174+
if (lastFrameworkVersion != "10.0")
175+
lastFrameworkVersion = lastFrameworkVersion.Replace (".", string.Empty);
176+
return $"monoandroid{lastFrameworkVersion}";
177+
}
178+
170179
public string LatestTargetFrameworkVersion (out string apiLevel) {
171180
GetTargetFrameworkVersionRange (out string _, out string _, out apiLevel, out string lastFrameworkVersion);
172181
return lastFrameworkVersion;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public override string SaveProject ()
7171
if (bi.DependentUpon != null) sb.Append ($"DependentUpon=\"{bi.DependentUpon ()}\" ");
7272
if (bi.Version != null) sb.Append ($"Version=\"{bi.Version ()}\" ");
7373
if (bi.SubType != null) sb.Append ($"SubType=\"{bi.SubType ()}\" ");
74-
if (bi.Metadata.Any ()) {
74+
if (!bi.Metadata.Any ()) {
7575
sb.AppendLine ($"\t\t/>");
7676
} else {
7777
sb.AppendLine ($">");

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@ public void Save (XamarinProject project, bool doNotCleanupOnUpdate = false, boo
5656

5757
// Copy our solution's NuGet.config
5858
var nuget_config = Path.Combine (XABuildPaths.TopDirectory, "NuGet.config");
59-
if (File.Exists (nuget_config)) {
60-
File.Copy (nuget_config, Path.Combine (Root, ProjectDirectory, "NuGet.config"), overwrite: true);
59+
var dest = Path.Combine (Root, ProjectDirectory, "NuGet.config");
60+
if (File.Exists (nuget_config) && !File.Exists (dest)) {
61+
File.Copy (nuget_config, dest, overwrite: true);
6162
}
6263
}
6364
else

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ public virtual void UpdateProjectFiles (string directory, IEnumerable<ProjectRes
270270
string filedir = directory;
271271
if (path.Contains (Path.DirectorySeparatorChar)) {
272272
filedir = Path.GetDirectoryName (path);
273-
if (!Directory.Exists (filedir))
273+
if (!Directory.Exists (filedir) && (p.Content != null || p.BinaryContent != null))
274274
Directory.CreateDirectory (filedir);
275275
}
276276

0 commit comments

Comments
 (0)