在被Xamarin.Android使用的NuGet包中包含本地库

4
我有一个双重项目。第一部分是一组C#绑定,用于包装本地.dll或.so库。这将生成一个NugGet包,然后由其他项目使用。
另一个项目是一个消耗这些C#绑定的Xamarin Forms项目。我的Xamarin项目的UWP部分没有问题,在NuGet包中找到本地库。然而,Android项目无法找到它。实际上,打开APK文件后发现本地.so文件从未被包含进去。
我正在使用NuGet的机制来包含特定架构库,通过在/runtimes/platform-arch/native/文件夹中包含每个平台特定的.dll或.so文件。对于绑定项目,我的文件夹结构如下:

Folder structure of bindings project

我能确认在生成的.nupkg文件中,文件夹结构得到了正确保留,其中在包的根目录下有一个runtimes文件夹和一系列子文件夹。
我使用内置的.csproj机制生成NuGet包,没有使用任何.targets文件。我的NuGet项目的csproj如下:
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
    <IncludeSymbols>true</IncludeSymbols>
    <SymbolPackageFormat>snupkg</SymbolPackageFormat>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
    <Version>1.0.5.1</Version>
    <Company />
    <Product />
  </PropertyGroup>

  <ItemGroup>
    <Content Include="runtimes\**" PackagePath="runtimes">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="OneOf" Version="2.1.150" />
  </ItemGroup>

</Project>

我的项目的第二部分是一个Xamarin Forms项目,我将NuGet包导入到项目的.NET Standard跨平台部分中。
当我构建UWP项目时,我的平台特定的.dll文件被正确地复制到我的.appx文件的根目录中,并且我可以成功地P/Invoke它。(我注意到这只有在我使用x64配置进行构建时才有效,并且我正在x64机器上编译。)然而,在构建Android项目时,没有类似的事情发生在.so Android库中。
整个依赖链看起来像这样:
-------------NuGet Package----------
|   - native_lib.so                |
|   - (other runtime dlls, etc)    |
------------------------------------
                 ^
                 |                 
-----Xamarin.Forms Core Project-----
| - Imports NuGet                  |
------------------------------------
                  ^
                  |
-------Xamarin Android Project------
| - Imports Xamarin Forms Core Proj|
| - Produces APK                   |
------------------------------------

看起来不是命名问题——在绑定项目中尝试将native_lib.so重命名为libnative_lib.so没有效果。

我是否漏掉了一步,或者NuGet根本不理解Xamarin.Android项目需要将本地库复制到APK中?

NuGet项目的源代码:https://github.com/pingzing/scannitsharp 消费NuGet的Xamarin Forms项目的源代码:https://github.com/pingzing/scannit NuGet包:https://www.nuget.org/packages/ScannitSharp/1.0.5.1


Android项目使用packages.config还是PackageReference?您对运行时标识符(RID)有多大的把握? - zivkan
它使用PackageReference(尽管它没有直接依赖于绑定库 - 只有跨平台的Xamarin Forms库,该库依赖于NuGet包)。至于RID,我非常确定:https://github.com/dotnet/corefx/blob/master/src/pkg/Microsoft.NETCore.Platforms/runtime.json 我想我可以尝试只使用“android”。 - PingZing
1个回答

1

一般来说,您需要在问题中分享更多信息,例如您的代码和打包文件。

NuGet难道不知道Xamarin.Android项目需要将本地库复制到APK中吗?

是的,它知道。您需要以一种方式打包NuGet,使MSBuild将此文件包含在最终APK中。

对于Android,可以使用 AndroidNativeLibrary 完成此操作

请参阅https://learn.microsoft.com/en-us/xamarin/android/deploy-test/building-apps/build-process#item-attribute-name

这里有一个可行的示例https://github.com/mfkl/libvlc-nuget/blob/master/build/VideoLAN.LibVLC.Android.targets

我注意到只有在x64配置下构建时才起作用,我正在x64机器上编译。

你可能需要修改目标文件来处理三种可能的情况 AnyCPUx86x64。您的目标应该在实际构建之前运行,使用 BeforeTargets="BeforeBuild"
你可以使用类似以下代码:
<Content Include="@(WindowsX64IncludeFilesFullPath)">
        <Link>$(WindowsX64TargetDir)\$([MSBuild]::MakeRelative($(MSBuildThisFileDirectory)..\build\x64\, %(FullPath)))</Link>
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

请查看这个链接: https://github.com/mfkl/libvlc-nuget/blob/master/build/VideoLAN.LibVLC.Windows.targets


回复:问题中的更多信息 - 好的。我可以添加有关NuGet打包过程的更多信息。“是的,确实如此。您需要以一种方式打包NuGet,以便MSBuild将此文件包含在最终APK中。对于Android,可以使用AndroidNativeLibrary来完成这项工作”-但是这对我不起作用- .so文件包含在NuGet包中,该包仅为.NET Standard库。到达Xamarin Android项目时,我不再能看到它。 - PingZing
当我开始处理Xamarin Android项目时,我已经失去了对它的可见性。我不知道这是什么意思。请分享您的代码。 - mfkl
问题已更新,提供更多信息。我的意思是,Xamarin Android 项目完全不知道涉及本地库的情况。它引用了 Xamarin Forms Netstandard 项目,该项目引用了一个 NuGet 包,其中包含一个 .so 文件。我在这个过程的任何部分都没有使用自定义的 .targets 文件。 - PingZing
将此标记为答案,因为它最终使我找到了正确的路径。我错过了两个步骤:1)在NuGet包的/build文件夹中包含一个使用<AndroidNativeLibrary>声明的ScannitSharp.targets文件,2)将库包含在Xamarin Netstandard库和特定于平台的Android项目中。 - PingZing
请点击以下链接,直接跳转到“AndroidNativeLibrary”部分:Link - bcr
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接