diff --git a/Documentation/release-notes/transitive-refasm.md b/Documentation/release-notes/transitive-refasm.md new file mode 100644 index 00000000000..225c8ea0e4b --- /dev/null +++ b/Documentation/release-notes/transitive-refasm.md @@ -0,0 +1,8 @@ +#### Application and library build and deployment + +- [Developer Community 1086457](https://developercommunity.visualstudio.com/content/problem/1086457/index.html): + Changes to libraries referenced by the .NET Standard library in a default + Xamarin.Forms project were not reflected in the running app without a clean + rebuild. More generally, this issue affected any library referenced + indirectly via a .NET Standard library that had the + `ProduceReferenceAssembly` MSBuild property set to `true`. diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs index 3a5ca58a8e9..59a6ab1952a 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs @@ -2692,7 +2692,7 @@ public void BuildWithResolveAssembliesFailure ([Values (true, false)] bool usePa Assert.IsTrue (appBuilder.LastBuildOutput.ContainsText ($"{error} `Microsoft.Azure.EventHubs`, referenced by `MyLibrary`. Please add a NuGet package or assembly reference for `Microsoft.Azure.EventHubs`, or remove the reference to `MyLibrary`."), $"Should recieve '{error}' regarding `Microsoft.Azure.EventHubs`!"); } else { - Assert.IsTrue (appBuilder.LastBuildOutput.ContainsText ($"{error} `Microsoft.Azure.Amqp`, referenced by `MyLibrary` > `Microsoft.Azure.EventHubs`. Please add a NuGet package or assembly reference for `Microsoft.Azure.Amqp`, or remove the reference to `MyLibrary`."), + Assert.IsTrue (appBuilder.LastBuildOutput.ContainsText ($"{error} `Microsoft.Azure.Amqp`, referenced by `Microsoft.Azure.EventHubs`. Please add a NuGet package or assembly reference for `Microsoft.Azure.Amqp`, or remove the reference to `Microsoft.Azure.EventHubs`"), $"Should recieve '{error}' regarding `Microsoft.Azure.Amqp`!"); } //Now add the PackageReference to the app to see a different error message diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs index 349a5374bbd..40fd6dc0017 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs @@ -516,6 +516,68 @@ public void ProduceReferenceAssembly () } } + [Test] + public void TransitiveDependencyProduceReferenceAssembly () + { + var path = Path.Combine (Root, "temp", TestName); + var app = new XamarinAndroidApplicationProject { + ProjectName = "App", + Sources = { + new BuildItem.Source ("Class1.cs") { + TextContent = () => "public class Class1 : Library1.Class1 { }" + }, + } + }; + var lib1 = new DotNetStandard { + ProjectName = "Library1", + Sdk = "Microsoft.NET.Sdk", + TargetFramework = "netstandard2.0", + Sources = { + new BuildItem.Source ("Class1.cs") { + TextContent = () => "namespace Library1 { public class Class1 { } }" + }, + new BuildItem.Source ("Class2.cs") { + TextContent = () => "namespace Library1 { public class Class2 : Library2.Class1 { } }" + } + } + }; + lib1.SetProperty ("ProduceReferenceAssembly", "True"); + var lib2 = new DotNetStandard { + ProjectName = "Library2", + Sdk = "Microsoft.NET.Sdk", + TargetFramework = "netstandard2.0", + Sources = { + new BuildItem.Source ("Class1.cs") { + TextContent = () => "namespace Library2 { public class Class1 { } }" + }, + } + }; + lib2.SetProperty ("ProduceReferenceAssembly", "True"); + lib1.OtherBuildItems.Add (new BuildItem.ProjectReference ($"..\\{lib2.ProjectName}\\{lib2.ProjectName}.csproj", lib2.ProjectName, lib2.ProjectGuid)); + app.References.Add (new BuildItem.ProjectReference ($"..\\{lib1.ProjectName}\\{lib1.ProjectName}.csproj", lib1.ProjectName, lib1.ProjectGuid)); + + using (var lib2Builder = CreateDllBuilder (Path.Combine (path, lib2.ProjectName), cleanupAfterSuccessfulBuild: false)) + using (var lib1Builder = CreateDllBuilder (Path.Combine (path, lib1.ProjectName), cleanupAfterSuccessfulBuild: false)) + using (var appBuilder = CreateApkBuilder (Path.Combine (path, app.ProjectName))) { + Assert.IsTrue (lib2Builder.Build (lib2), "first Library2 build should have succeeded."); + Assert.IsTrue (lib1Builder.Build (lib1), "first Library1 build should have succeeded."); + Assert.IsTrue (appBuilder.Build (app), "first app build should have succeeded."); + + lib2.Sources.Add (new BuildItem.Source ("Class2.cs") { + TextContent = () => "namespace Library2 { public class Class2 { } }" + }); + + Assert.IsTrue (lib2Builder.Build (lib2, doNotCleanupOnUpdate: true), "second Library2 build should have succeeded."); + Assert.IsTrue (lib1Builder.Build (lib1, doNotCleanupOnUpdate: true, saveProject: false), "second Library1 build should have succeeded."); + appBuilder.Target = "SignAndroidPackage"; + Assert.IsTrue (appBuilder.Build (app, doNotCleanupOnUpdate: true, saveProject: false), "app SignAndroidPackage build should have succeeded."); + + var lib2Output = Path.Combine (path, lib2.ProjectName, "bin", "Debug", "netstandard2.0", $"{lib2.ProjectName}.dll"); + var lib2InAppOutput = Path.Combine (path, app.ProjectName, app.IntermediateOutputPath, "android", "assets", $"{lib2.ProjectName}.dll"); + FileAssert.AreEqual (lib2Output, lib2InAppOutput, "new Library2 should have been copied to app output directory"); + } + } + [Test] [Category ("dotnet")] public void LinkAssembliesNoShrink () diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Legacy.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Legacy.targets index 5cce13cbd7c..1cefd0b1c98 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Legacy.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Legacy.targets @@ -258,6 +258,10 @@ projects. .NET 5 projects will not import this file. Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.ResolvedFrom)' != 'ImplicitlyExpandDesignTimeFacades' And '%(ReferenceCopyLocalPaths.Extension)' == '.dll' And '%(ReferenceCopyLocalPaths.RelativeDir)' == '' And Exists('%(ReferenceCopyLocalPaths.Identity)') " /> +