Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] <FilterAssemblies/> should look for .ja…
Browse files Browse the repository at this point in the history
…r files (#3362)

Fixes: #3343

Context: https://github.com/xamarin/XamarinComponents/blob/54646f5c0bef9c618c700628bd1167768d7c9b4f/Android/Guava/source/Guava.ListenableFuture/Guava.ListenableFuture.csproj
Context: https://www.nuget.org/packages/Xamarin.Google.Guava.ListenableFuture/1.0.0

We introduced a performance improvement in 5ec3e3a that "classifies"
assemblies as Xamarin.Android assemblies or not.  This allows us to
skip processing of NetStandard/BCL assemblies throughout the build.

Unfortunately, the `Xamarin.Google.Guava.ListenableFuture.dll`
assembly is "odd":

  * No `[assembly: TargetFramework]` attribute at all
  * No reference to `Mono.Android.dll`

Without either of those, 5ec3e3a thinks that this assembly is *not*
a Xamarin.Android-profile assembly, and thus skips processing.

The only "marker" is that `Xamarin.Google.Guava.ListenableFuture.dll`
has is a `.jar` file as an `@(EmbeddedResource)`, which is put there
by the `@(EmbeddedJar)` Build action.

The weirdness is related to it not having any C# code, and it using
SDK-style projects.

Fix support for the `Xamarin.Google.Guava.ListenableFuture.dll`
and similar assemblies by updating the `<FilterAssemblies/>` task to
look for:

  * `[assembly: TargetFramework("MonoAndroid,Version=v9.0")]`
  * `Mono.Android.dll` reference
  * `EmbeddedResource` ending with `*.jar`  (this is new.)
  * `EmbeddedResource` beginning with `__Android`  (this is new.)

I also reworked this task so that the logic is hardcoded. It does not
seem useful to pass in input parameters from MSBuild targets anymore.
  • Loading branch information
jonathanpeppers authored and jonpryor committed Jul 31, 2019
1 parent 96c61fb commit 5430f93
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 26 deletions.
69 changes: 47 additions & 22 deletions src/Xamarin.Android.Build.Tasks/Tasks/FilterAssemblies.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,16 @@
namespace Xamarin.Android.Tasks
{
/// <summary>
/// Filters a set of assemblies based on a given TargetFrameworkIdentifier or FallbackReference
/// Filters a set of assemblies to be known as "Xamarin.Android" assemblies through various checks:
/// * The presence of [assembly: System.Runtime.Versioning.TargetFramework("MonoAndroid,Version=v9.0")]
/// * A Mono.Android.dll reference
/// * An EmbeddedResource ending with *.jar
/// * An EmbeddedResource beginning with __Android
/// </summary>
public class FilterAssemblies : Task
{
/// <summary>
/// The MonoAndroid portion of [assembly: System.Runtime.Versioning.TargetFramework("MonoAndroid,v9.0")]
/// </summary>
[Required]
public string TargetFrameworkIdentifier { get; set; }

/// <summary>
/// If TargetFrameworkIdentifier is missing, we can look for Mono.Android.dll references instead
/// </summary>
public string FallbackReference { get; set; }
const string TargetFrameworkIdentifier = "MonoAndroid";
const string MonoAndroidReference = "Mono.Android";

[Required]
public bool DesignTimeBuild { get; set; }
Expand Down Expand Up @@ -51,23 +47,52 @@ public override bool Execute ()
output.Add (assemblyItem);
continue;
}
// Fallback to looking at references
if (string.IsNullOrEmpty (targetFrameworkIdentifier) && !string.IsNullOrEmpty (FallbackReference)) {
Log.LogDebugMessage ($"Checking references for: {assemblyItem.ItemSpec}");
foreach (var handle in reader.AssemblyReferences) {
var reference = reader.GetAssemblyReference (handle);
var name = reader.GetString (reference.Name);
if (FallbackReference == name) {
output.Add (assemblyItem);
break;
}
}

// In the rare case, [assembly: TargetFramework("MonoAndroid,Version=v9.0")] may not match
Log.LogDebugMessage ($"{nameof (TargetFrameworkIdentifier)} did not match: {assemblyItem.ItemSpec}");

// Fallback to looking for a Mono.Android reference
if (HasReference (reader)) {
Log.LogDebugMessage ($"{MonoAndroidReference} reference found: {assemblyItem.ItemSpec}");
output.Add (assemblyItem);
continue;
}
// Fallback to looking for *.jar or __Android EmbeddedResource files
if (HasEmbeddedResource (reader)) {
Log.LogDebugMessage ($"EmbeddedResource found: {assemblyItem.ItemSpec}");
output.Add (assemblyItem);
continue;
}
}
}
OutputAssemblies = output.ToArray ();

return !Log.HasLoggedErrors;
}

bool HasReference (MetadataReader reader)
{
foreach (var handle in reader.AssemblyReferences) {
var reference = reader.GetAssemblyReference (handle);
var name = reader.GetString (reference.Name);
if (MonoAndroidReference == name) {
return true;
}
}
return false;
}

bool HasEmbeddedResource (MetadataReader reader)
{
foreach (var handle in reader.ManifestResources) {
var resource = reader.GetManifestResource (handle);
var name = reader.GetString (resource.Name);
if (name.EndsWith (".jar", StringComparison.OrdinalIgnoreCase) ||
name.StartsWith ("__Android", StringComparison.OrdinalIgnoreCase)) {
return true;
}
}
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3862,6 +3862,30 @@ public void AbiDelimiters ([Values ("armeabi-v7a%3bx86", "armeabi-v7a,x86")] str
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
}
}

[Test]
public void WorkManager ()
{
var proj = new XamarinFormsAndroidApplicationProject ();
proj.Sources.Add (new BuildItem.Source ("MyWorker.cs") {
TextContent = () =>
@"using System;
using Android.Content;
using AndroidX.Work;
public class MyWorker : Worker
{
public MyWorker (Context c, WorkerParameters p) : base (c, p) { }
public override Result DoWork () => Result.InvokeSuccess ();
}
"
});
proj.PackageReferences.Add (KnownPackages.Android_Arch_Work_Runtime);
using (var b = CreateApkBuilder (Path.Combine ("temp", TestName))) {
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
}
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ string [] Run (params string [] assemblies)
{
var task = new FilterAssemblies {
BuildEngine = new MockBuildEngine (TestContext.Out),
TargetFrameworkIdentifier = "MonoAndroid",
FallbackReference = "Mono.Android",
InputAssemblies = assemblies.Select (a => new TaskItem (a)).ToArray (),
};
Assert.IsTrue (task.Execute (), "task.Execute() should have succeeded.");
Expand Down Expand Up @@ -98,5 +96,16 @@ public async Task XamarinForms ()
};
CollectionAssert.AreEqual (expected, actual);
}

[Test]
public async Task GuavaListenableFuture ()
{
var assemblies = await GetAssembliesFromNuGet (
"https://www.nuget.org/api/v2/package/Xamarin.Google.Guava.ListenableFuture/1.0.0",
"lib/MonoAndroid50/");
var actual = Run (assemblies);
var expected = new [] { "Xamarin.Google.Guava.ListenableFuture.dll" };
CollectionAssert.AreEqual (expected, actual);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,16 @@ public static class KnownPackages
}
}
};
public static Package Android_Arch_Work_Runtime = new Package {
Id = "Xamarin.Android.Arch.Work.Runtime",
Version = "1.0.0",
TargetFramework = "MonoAndroid90",
References = {
new BuildItem.Reference("Xamarin.Android.Arch.Work.Runtime") {
MetadataValues = "HintPath=..\\packages\\Xamarin.Android.Arch.Work.Runtime.1.0.0\\lib\\MonoAndroid90\\Xamarin.Android.Arch.Work.Runtime.dll"
}
}
};
public static Package Xamarin_Android_Crashlytics_2_9_4 = new Package {
Id = "Xamarin.Android.Crashlytics",
Version = "2.9.4",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,6 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
</ItemGroup>
<FilterAssemblies
DesignTimeBuild="$(DesignTimeBuild)"
TargetFrameworkIdentifier="MonoAndroid"
FallbackReference="Mono.Android"
InputAssemblies="@(_ReferencePath);@(_ReferenceDependencyPaths)">
<Output TaskParameter="OutputAssemblies" ItemName="_MonoAndroidReferencePath" />
</FilterAssemblies>
Expand Down

0 comments on commit 5430f93

Please sign in to comment.