Skip to content

Commit

Permalink
[One .NET] pack AndroidLibrary .aar files in .nupkg
Browse files Browse the repository at this point in the history
Fixes: xamarin#7040

It appears we were missing a test case of:

1. `dotnet new androidlib`

2. Add an `.aar` file

3. `dotnet pack`

4. Assert that `lib\net6.0-android31.0\MyAndroidLibrary.aar` exists in
   the `.nupkg` output

We instead end up with "weird" output in the `.nupkg` like:

    lib\net6.0-android31.0\MyDotNetAssembly.dll
    lib\net6.0-android31.0\MyDotNetAssembly.xml
    lib\net6.0-android31.0\MyDotNetAssembly.aar
    content\MyAndroidLibrary.aar
    contentFiles\any\net6.0-android31.0\MyAndroidLibrary.aar

`MyDotNetAssembly.aar` would contain any `.jar` files or
`AndroidResource` files packed inside. However, *other* `.aar` files
are supposed to sit next to `MyDotNetAssembly.dll`.

It was surprisingly difficult to work alongside NuGet's MSBuild
targets to get this to work.

1. In the `_CategorizeAndroidLibraries` MSBuild target, mark
   `TfmSpecificPackageFile="%(Pack)"` to be used in our
   `_IncludeAarInNuGetPackage` MSBuild target.

2. Add these files to `@(TfmSpecificPackageFileWithRecursiveDir)` and
   set `%(NuGetRecursiveDir)` to empty. Otherwise, these items can
   have `%(RecursiveDir)` set to some path, and this causes
   sub-directories in the `.nupkg` output.

I updated several tests for this case. I also updated usage of
`XASdkProject.OtherBuildItems` to use `Sources` instead.
`OtherBuildItems` adds the files to the `.csproj`, and we should be
testing our wildcards in `AutoImport.props`. Previously, some of these
items were being added twice in these tests.
  • Loading branch information
jonathanpeppers committed May 31, 2022
1 parent c9d3bf4 commit 3901e89
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 29 deletions.
Expand Up @@ -97,7 +97,7 @@ This item group populates the Build Action drop-down in IDEs.
<AndroidJavaLibrary Include="@(AndroidLibrary)" Condition=" '%(AndroidLibrary.Extension)' == '.jar' and '%(AndroidLibrary.Bind)' != 'true' " />
<EmbeddedJar Include="@(AndroidLibrary)" Condition=" '%(AndroidLibrary.Extension)' == '.jar' and '%(AndroidLibrary.Bind)' == 'true' " />
<!-- .aar files should be copied to $(OutputPath) in .NET 6-->
<None Include="@(LibraryProjectZip)" CopyToOutputDirectory="PreserveNewest" Link="%(Filename)%(Extension)" />
<None Include="@(LibraryProjectZip)" TfmSpecificPackageFile="%(LibraryProjectZip.Pack)" Pack="false" CopyToOutputDirectory="PreserveNewest" Link="%(Filename)%(Extension)" />
</ItemGroup>
<!-- Legacy binding projects -->
<ItemGroup Condition=" '$(_AndroidIsBindingProject)' == 'true' and '$(UsingAndroidNETSdk)' != 'true' ">
Expand Down
Expand Up @@ -91,14 +91,16 @@ projects.
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);_IncludeAarInNuGetPackage</TargetsForTfmSpecificContentInPackage>
</PropertyGroup>
<Target Name="_IncludeAarInNuGetPackage"
Condition=" '$(IncludeBuildOutput)' != 'false' and '$(AndroidApplication)' != 'true' and Exists('$(_AarOutputPath)') ">
Condition=" '$(IncludeBuildOutput)' != 'false' and '$(AndroidApplication)' != 'true' "
DependsOnTargets="_CategorizeAndroidLibraries">
<GetNuGetShortFolderName
TargetFrameworkMoniker="$(TargetFrameworkMoniker)"
TargetPlatformMoniker="$(TargetPlatformMoniker)">
<Output TaskParameter="NuGetShortFolderName" PropertyName="_NuGetShortFolderName" />
</GetNuGetShortFolderName>
<ItemGroup>
<TfmSpecificPackageFile Include="$(_AarOutputPath)" PackagePath="lib\$(_NuGetShortFolderName)" />
<TfmSpecificPackageFile Condition="Exists('$(_AarOutputPath)')" Include="$(_AarOutputPath)" PackagePath="lib\$(_NuGetShortFolderName)" />
<TfmSpecificPackageFileWithRecursiveDir Include="@(None->WithMetadataValue ('TfmSpecificPackageFile', 'true'))" PackagePath="lib\$(_NuGetShortFolderName)" NuGetRecursiveDir="" />
</ItemGroup>
</Target>

Expand Down
Expand Up @@ -89,27 +89,30 @@ public Foo ()
TextContent = () => {
return "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ImageView xmlns:android=\"http://schemas.android.com/apk/res/android\" android:src=\"@drawable/IMALLCAPS\" />";
}
}
},
new AndroidItem.AndroidAsset ("Assets\\foo\\foo.txt") {
BinaryContent = () => Array.Empty<byte> (),
},
new AndroidItem.AndroidResource ("Resources\\layout\\MyLayout.axml") {
TextContent = () => "<?xml version=\"1.0\" encoding=\"utf-8\" ?><LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\" />"
},
new AndroidItem.AndroidResource ("Resources\\raw\\bar.txt") {
BinaryContent = () => Array.Empty<byte> (),
},
new AndroidItem.AndroidLibrary ("sub\\directory\\foo.jar") {
BinaryContent = () => ResourceData.JavaSourceJarTestJar,
},
new AndroidItem.AndroidLibrary ("sub\\directory\\bar.aar") {
WebContent = "https://repo1.maven.org/maven2/com/balysv/material-menu/1.1.0/material-menu-1.1.0.aar",
},
}
};
libB.OtherBuildItems.Add (new AndroidItem.AndroidAsset ("Assets\\foo\\foo.txt") {
BinaryContent = () => Array.Empty<byte> (),
});
libB.OtherBuildItems.Add (new AndroidItem.AndroidResource ("Resources\\layout\\MyLayout.axml") {
TextContent = () => "<?xml version=\"1.0\" encoding=\"utf-8\" ?><LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\" />"
});
libB.OtherBuildItems.Add (new AndroidItem.AndroidResource ("Resources\\raw\\bar.txt") {
BinaryContent = () => Array.Empty<byte> (),
});
libB.OtherBuildItems.Add (new AndroidItem.AndroidEnvironment ("env.txt") {
TextContent = () => $"{env_var}={env_val}",
});
libB.OtherBuildItems.Add (new AndroidItem.AndroidEnvironment ("sub\\directory\\env.txt") {
TextContent = () => $"{env_var}={env_val}",
});
libB.OtherBuildItems.Add (new AndroidItem.AndroidLibrary ("sub\\directory\\foo.jar") {
BinaryContent = () => ResourceData.JavaSourceJarTestJar,
});
libB.OtherBuildItems.Add (new AndroidItem.AndroidLibrary ("sub\\directory\\arm64-v8a\\libfoo.so") {
BinaryContent = () => Array.Empty<byte> (),
});
Expand All @@ -127,8 +130,10 @@ public Foo ()
Assert.IsTrue (libBBuilder.Build (), $"{libB.ProjectName} should succeed");

// Check .aar file for class library
var aarPath = Path.Combine (FullProjectDirectory, libB.OutputPath, $"{libB.ProjectName}.aar");
var libBOutputPath = Path.Combine (FullProjectDirectory, libB.OutputPath);
var aarPath = Path.Combine (libBOutputPath, $"{libB.ProjectName}.aar");
FileAssert.Exists (aarPath);
FileAssert.Exists (Path.Combine (libBOutputPath, "bar.aar"));
using (var aar = ZipHelper.OpenZip (aarPath)) {
aar.AssertContainsEntry (aarPath, "assets/foo/foo.txt");
aar.AssertContainsEntry (aarPath, "res/layout/mylayout.xml");
Expand Down Expand Up @@ -237,18 +242,21 @@ public void DotNetPack (string targetFramework, int apiLevel)
Sources = {
new BuildItem.Source ("Foo.cs") {
TextContent = () => "public class Foo { }",
}
}
},
new AndroidItem.AndroidResource ("Resources\\raw\\bar.txt") {
BinaryContent = () => Array.Empty<byte> (),
},
new AndroidItem.AndroidLibrary ("sub\\directory\\foo.jar") {
BinaryContent = () => ResourceData.JavaSourceJarTestJar,
},
new AndroidItem.AndroidLibrary ("sub\\directory\\bar.aar") {
WebContent = "https://repo1.maven.org/maven2/com/balysv/material-menu/1.1.0/material-menu-1.1.0.aar",
},
},
};
if (IsPreviewFrameworkVersion (targetFramework)) {
proj.SetProperty ("EnablePreviewFeatures", "true");
}
proj.OtherBuildItems.Add (new AndroidItem.AndroidResource ("Resources\\raw\\bar.txt") {
BinaryContent = () => Array.Empty<byte> (),
});
proj.OtherBuildItems.Add (new AndroidItem.AndroidLibrary ("sub\\directory\\foo.jar") {
BinaryContent = () => ResourceData.JavaSourceJarTestJar,
});
proj.OtherBuildItems.Add (new AndroidItem.AndroidLibrary ("sub\\directory\\arm64-v8a\\libfoo.so") {
BinaryContent = () => Array.Empty<byte> (),
});
Expand All @@ -257,16 +265,29 @@ public void DotNetPack (string targetFramework, int apiLevel)
MetadataValues = "Link=x86\\libfoo.so",
BinaryContent = () => Array.Empty<byte> (),
});
proj.OtherBuildItems.Add (new AndroidItem.AndroidLibrary (default (Func<string>)) {
Update = () => "nopack.aar",
WebContent = "https://repo1.maven.org/maven2/com/balysv/material-menu/1.1.0/material-menu-1.1.0.aar",
MetadataValues = "Pack=false;Bind=false",
});

const string dotnetVersion = "net6.0";
var dotnet = CreateDotNetBuilder (proj);
Assert.IsTrue (dotnet.Pack (), "`dotnet pack` should succeed");

var nupkgPath = Path.Combine (FullProjectDirectory, proj.OutputPath, "..", $"{proj.ProjectName}.1.0.0.nupkg");
FileAssert.Exists (nupkgPath);
using (var nupkg = ZipHelper.OpenZip (nupkgPath)) {
nupkg.AssertContainsEntry (nupkgPath, $"lib/net6.0-android{apiLevel}.0/{proj.ProjectName}.dll");
nupkg.AssertContainsEntry (nupkgPath, $"lib/net6.0-android{apiLevel}.0/{proj.ProjectName}.aar");
}
using var nupkg = ZipHelper.OpenZip (nupkgPath);
nupkg.AssertContainsEntry (nupkgPath, $"lib/{dotnetVersion}-android{apiLevel}.0/{proj.ProjectName}.dll");
nupkg.AssertContainsEntry (nupkgPath, $"lib/{dotnetVersion}-android{apiLevel}.0/{proj.ProjectName}.aar");

nupkg.AssertContainsEntry (nupkgPath, $"lib/{dotnetVersion}-android{apiLevel}.0/bar.aar");
nupkg.AssertDoesNotContainEntry (nupkgPath, "content/bar.aar");
nupkg.AssertDoesNotContainEntry (nupkgPath, "content/sub/directory/bar.aar");
nupkg.AssertDoesNotContainEntry (nupkgPath, $"contentFiles/any/{dotnetVersion}-android{apiLevel}.0/sub/directory/bar.aar");
nupkg.AssertDoesNotContainEntry (nupkgPath, $"lib/{dotnetVersion}-android{apiLevel}.0/nopack.aar");
nupkg.AssertDoesNotContainEntry (nupkgPath, "content/nopack.aar");
nupkg.AssertDoesNotContainEntry (nupkgPath, $"contentFiles/any/{dotnetVersion}-android{apiLevel}.0/nopack.aar");
}

[Test]
Expand Down

0 comments on commit 3901e89

Please sign in to comment.