Skip to content

Commit 5ca58d1

Browse files
[Xamarin.Android.Build.Tasks] <FilterAssemblies/> support missing TFI
Context: https://www.nuget.org/packages/Refractored.Controls.CircleImageView/ Context: https://github.com/Azure-Samples/MyDriving The MyDriving sample app currently fails to build on master with: Resources/layout/fragment_profile.axml(2): error APT0000: attribute civ_border_width (aka com.microsoft.mydriving:civ_border_width) not found. The failure happens with both `aapt` and `aapt2`. This layout is using a custom view such as: <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:local="http://schemas.android.com/apk/res-auto"> ... <refractored.controls.CircleImageView local:civ_border_width="0dp" /> ... </ScrollView> This comes from the `Refractored.Controls.CircleImageView` NuGet package. In 5ec3e3a, I added a `<FilterAssemblies/>` MSBuild task that appears to be to blame. It is not returning `Refractored.Controls.CircleImageView.dll`, but it needs to! `Refractored.Controls.CircleImageView.dll` has no `[assembly: System.Runtime.Versioning.TargetFrameworkAttribute]`... // C:\src\des\MyDriving\packages\Refractored.Controls.CircleImageView.1.0.1\lib\MonoAndroid10\Refractored.Controls.CircleImageView.dll // Refractored.Controls.CircleImageView, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null // Global type: <Module> // Architecture: x86 // Runtime: v4.0.30319 // Hash algorithm: SHA1 using Android.Runtime; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; [assembly: AssemblyTitle("Refractored.Controls.CircleImageView")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("")] [assembly: AssemblyCopyright("2015 Refractored LLC/James Montemagno")] [assembly: AssemblyTrademark("")] [assembly: NamespaceMapping(Java = "de.hdodenhof.circleimageview", Managed = "Refractored.Controls")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: SecurityPermission(8, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] It is indeed a `MonoAndroid` assembly, since it references `Mono.Android.dll`. It is weird, though... So I think the fix here is: * `<FilterAssemblies/>` needs to also check for an assembly reference to `Mono.Android` as a fallback. * `<ResolveAssemblies/>` now adds a `%(MonoAndroidReference)=True` item metadata. * When creating the `@(_ResolvedUserMonoAndroidAssemblies)` item group, we also check for `%(MonoAndroidReference)=True`. I added a test to verify this scenario.
1 parent 28e1f93 commit 5ca58d1

File tree

5 files changed

+72
-7
lines changed

5 files changed

+72
-7
lines changed

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,18 @@
88
namespace Xamarin.Android.Tasks
99
{
1010
/// <summary>
11-
/// Filters a set of assemblies based on a given TargetFrameworkIdentifier
11+
/// Filters a set of assemblies based on a given TargetFrameworkIdentifier or References
1212
/// </summary>
1313
public class FilterAssemblies : Task
1414
{
1515
[Required]
1616
public string TargetFrameworkIdentifier { get; set; }
1717

18+
/// <summary>
19+
/// If TargetFrameworkIdentifier is missing, we can look for Mono.Android.dll references instead
20+
/// </summary>
21+
public string FallbackReference { get; set; }
22+
1823
[Required]
1924
public bool DesignTimeBuild { get; set; }
2025

@@ -40,6 +45,19 @@ public override bool Execute ()
4045
var targetFrameworkIdentifier = assemblyDefinition.GetTargetFrameworkIdentifier (reader);
4146
if (targetFrameworkIdentifier == TargetFrameworkIdentifier) {
4247
output.Add (assemblyItem);
48+
continue;
49+
}
50+
// Fallback to looking at references
51+
if (string.IsNullOrEmpty (targetFrameworkIdentifier) && !string.IsNullOrEmpty (FallbackReference)) {
52+
Log.LogDebugMessage ($"Checking references for: {assemblyItem.ItemSpec}");
53+
foreach (var handle in reader.AssemblyReferences) {
54+
var reference = reader.GetAssemblyReference (handle);
55+
var name = reader.GetString (reference.Name);
56+
if (FallbackReference == name) {
57+
output.Add (assemblyItem);
58+
break;
59+
}
60+
}
4361
}
4462
}
4563
}

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,22 +223,28 @@ void AddAssemblyReferences (MetadataResolver resolver, Dictionary<string, ITaskI
223223
indent += 2;
224224

225225
// Add this assembly
226+
ITaskItem assemblyItem = null;
226227
if (topLevel) {
227-
if (!string.IsNullOrEmpty (targetFrameworkIdentifier) && assemblies.TryGetValue (assemblyName, out ITaskItem taskItem)) {
228-
if (string.IsNullOrEmpty (taskItem.GetMetadata ("TargetFrameworkIdentifier"))) {
229-
taskItem.SetMetadata ("TargetFrameworkIdentifier", targetFrameworkIdentifier);
228+
if (assemblies.TryGetValue (assemblyName, out assemblyItem)) {
229+
if (!string.IsNullOrEmpty (targetFrameworkIdentifier) && string.IsNullOrEmpty (assemblyItem.GetMetadata ("TargetFrameworkIdentifier"))) {
230+
assemblyItem.SetMetadata ("TargetFrameworkIdentifier", targetFrameworkIdentifier);
230231
}
231232
}
232233
} else {
233-
assemblies [assemblyName] = CreateAssemblyTaskItem (assemblyPath, targetFrameworkIdentifier);
234+
assemblies [assemblyName] =
235+
assemblyItem = CreateAssemblyTaskItem (assemblyPath, targetFrameworkIdentifier);
234236
}
235237

236238
// Recurse into each referenced assembly
237239
foreach (var handle in reader.AssemblyReferences) {
238240
var reference = reader.GetAssemblyReference (handle);
239241
string reference_assembly;
240242
try {
241-
reference_assembly = resolver.Resolve (reader.GetString (reference.Name));
243+
var referenceName = reader.GetString (reference.Name);
244+
if (assemblyItem != null && referenceName == "Mono.Android") {
245+
assemblyItem.SetMetadata ("MonoAndroidReference", "True");
246+
}
247+
reference_assembly = resolver.Resolve (referenceName);
242248
} catch (FileNotFoundException ex) {
243249
var references = new StringBuilder ();
244250
for (int i = 0; i < resolutionPath.Count; i++) {

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3636,6 +3636,36 @@ public void CompilerErrorShouldNotRunLinkAssemblies ()
36363636
Assert.IsFalse (StringAssertEx.ContainsText (b.LastBuildOutput, "The \"LinkAssemblies\" task failed unexpectedly"), "The LinkAssemblies MSBuild task should not run!");
36373637
}
36383638
}
3639+
3640+
/// <summary>
3641+
/// This assembly weirdly has no [assembly: System.Runtime.Versioning.TargetFrameworkAttribute()], at all...
3642+
/// </summary>
3643+
[Test]
3644+
public void AssemblyWithMissingTargetFramework ()
3645+
{
3646+
var proj = new XamarinAndroidApplicationProject {
3647+
AndroidResources = {
3648+
new AndroidItem.AndroidResource ("Resources\\layout\\test.axml") {
3649+
TextContent = () =>
3650+
@"<?xml version=""1.0"" encoding=""utf-8""?>
3651+
<ScrollView
3652+
xmlns:android=""http://schemas.android.com/apk/res/android""
3653+
xmlns:local=""http://schemas.android.com/apk/res-auto"">
3654+
<refractored.controls.CircleImageView local:civ_border_width=""0dp"" />
3655+
</ScrollView>"
3656+
}
3657+
}
3658+
};
3659+
proj.PackageReferences.Add (KnownPackages.CircleImageView);
3660+
using (var b = CreateApkBuilder (Path.Combine ("temp", TestName))) {
3661+
Assert.IsTrue (b.Build (proj), "build should have succeeded.");
3662+
3663+
// We should have a java stub, in addition to the build succeeding
3664+
var intermediate = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath);
3665+
var javaStub = Path.Combine (intermediate, "android", "src", "md54908d67eb9afef4acc92753cc61471e9", "CircleImageView.java");
3666+
FileAssert.Exists (javaStub);
3667+
}
3668+
}
36393669
}
36403670
}
36413671

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Android/KnownPackages.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,16 @@ public static class KnownPackages
726726
}
727727
},
728728
};
729+
public static Package CircleImageView = new Package {
730+
Id = "Refractored.Controls.CircleImageView",
731+
Version = "1.0.1",
732+
TargetFramework = "MonoAndroid10",
733+
References = {
734+
new BuildItem.Reference ("Refractored.Controls.CircleImageView") {
735+
MetadataValues = "HintPath=..\\packages\\Refractored.Controls.CircleImageView.1.0.1\\lib\\MonoAndroid10\\Refractored.Controls.CircleImageView.dll"
736+
}
737+
},
738+
};
729739
}
730740
}
731741

src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
506506
<FilterAssemblies
507507
DesignTimeBuild="$(DesignTimeBuild)"
508508
TargetFrameworkIdentifier="MonoAndroid"
509+
FallbackReference="Mono.Android"
509510
InputAssemblies="@(_ReferencePath);@(_ReferenceDependencyPaths)">
510511
<Output TaskParameter="OutputAssemblies" ItemName="_MonoAndroidReferencePath" />
511512
</FilterAssemblies>
@@ -2213,7 +2214,7 @@ because xbuild doesn't support framework reference assemblies.
22132214

22142215
<CreateItem
22152216
Include="@(_ResolvedUserAssemblies)"
2216-
Condition="'%(_ResolvedUserAssemblies.TargetFrameworkIdentifier)' == 'MonoAndroid'">
2217+
Condition="'%(_ResolvedUserAssemblies.TargetFrameworkIdentifier)' == 'MonoAndroid' Or '%(_ResolvedUserAssemblies.MonoAndroidReference)' == 'True'">
22172218
<Output TaskParameter="Include" ItemName="_ResolvedUserMonoAndroidAssemblies" />
22182219
</CreateItem>
22192220
</Target>

0 commit comments

Comments
 (0)