我正在开发一个适用于 Android、iOS 和桌面操作系统的 .NET 库。它在任何地方都运行良好——除了 iOS。事实上,在 iOS 上,我让它可以用于本地部署,但 Apple Store 拒绝了基于它的应用程序,因为本机依赖项必须位于 Apple“框架”中。
因此,我做了很多研究并了解了 xcframeworks 框架,并重构了我的 nupkg 以在 xcframework 结构中传递本机依赖项。这样,iOS csproj 就会构建并部署 .NET 程序集及其与应用程序的本机依赖项,但应用程序现在在尝试加载该本机依赖项时会抛出
DllNotFoundException
。
Visual Studio 调试输出窗口仅显示此问题:
**System.DllNotFoundException:** 'nerdbank_qrcodes'
我如何调试这个?
或者,我做错了什么?这是我的 nupkg 的布局:
D:\PACKAGES\NUGET\NERDBANK.QRCODES\0.2.55-BETA-G209A879921
| .nupkg.metadata
| nerdbank.qrcodes.0.2.55-beta-g209a879921.nupkg
| nerdbank.qrcodes.0.2.55-beta-g209a879921.nupkg.sha512
| nerdbank.qrcodes.nuspec
| README.md
| THIRD_PARTY_DEPENDENCIES.txt
| THIRD_PARTY_LICENSES.yml
|
+---lib
| +---net8.0
| | Nerdbank.QRCodes.dll
| | Nerdbank.QRCodes.xml
| |
| +---net8.0-ios17.5
| | | Nerdbank.QRCodes.dll
| | | Nerdbank.QRCodes.xml
| | |
| | \---Nerdbank.QRCodes.resources
| | | manifest
| | |
| | \---nerdbank_qrcodes.xcframework
| | | Info.plist
| | |
| | +---ios-arm64
| | | \---nerdbank_qrcodes.framework
| | | Info.plist
| | | nerdbank_qrcodes
| | |
| | \---ios-arm64_x86_64-simulator
| | \---nerdbank_qrcodes.framework
| | Info.plist
| | nerdbank_qrcodes
| |
| \---net8.0-windows7.0
| Nerdbank.QRCodes.dll
| Nerdbank.QRCodes.xml
|
\---runtimes
+---android-arm64
| \---native
| libnerdbank_qrcodes.so
|
+---android-x64
| \---native
| libnerdbank_qrcodes.so
|
+---linux-arm64
| \---native
| libnerdbank_qrcodes.so
|
+---linux-x64
| \---native
| libnerdbank_qrcodes.so
|
+---osx-arm64
| \---native
| libnerdbank_qrcodes.dylib
|
+---osx-x64
| \---native
| libnerdbank_qrcodes.dylib
|
+---win-arm64
| \---native
| nerdbank_qrcodes.dll
|
\---win-x64
\---native
nerdbank_qrcodes.dll
本机框架 dll 是使用
lipo
和 install_name_tool
和 chmod
专门准备的,如下:
# copy Info.plist and the binary into the appropriate .framework directory structure
# so that when NativeBindings.targets references it with ResolvedFileToPublish, it will be treated appropriately.
$RustTargetBaseDir = "$repoRoot/src/nerdbank-qrcodes/target"
$RustDylibFileName = "libnerdbank_qrcodes.dylib"
$DeviceRustOutput = "$RustTargetBaseDir/aarch64-apple-ios/$Configuration/$RustDylibFileName"
$SimulatorX64RustOutput = "$RustTargetBaseDir/x86_64-apple-ios/$Configuration/$RustDylibFileName"
$SimulatorArm64RustOutput = "$RustTargetBaseDir/aarch64-apple-ios-sim/$Configuration/$RustDylibFileName"
$DeviceFrameworkDir = "$repoRoot/bin/$Configuration/device/nerdbank_qrcodes.framework"
$SimulatorFrameworkDir = "$repoRoot/bin/$Configuration/simulator/nerdbank_qrcodes.framework"
New-Item -Path $DeviceFrameworkDir,$SimulatorFrameworkDir -ItemType Directory -Force | Out-Null
Write-Host "Preparing Apple iOS and iOS-simulator frameworks"
Copy-Item $IntermediatePlistPath "$DeviceFrameworkDir/Info.plist"
Copy-Item $IntermediatePlistPath "$SimulatorFrameworkDir/Info.plist"
Write-Host "Created Info.plist with version $version"
if ($IsMacOS) {
# Rename the binary that contains the arm64 architecture for device.
lipo -create -output $DeviceFrameworkDir/nerdbank_qrcodes $DeviceRustOutput
install_name_tool -id "@rpath/nerdbank_qrcodes.framework/nerdbank_qrcodes" "$DeviceFrameworkDir/nerdbank_qrcodes"
chmod +x "$DeviceFrameworkDir/nerdbank_qrcodes"
# Create a universal binary that contains both arm64 and x64 architectures for simulator.
lipo -create -output $SimulatorFrameworkDir/nerdbank_qrcodes $SimulatorX64RustOutput $SimulatorArm64RustOutput
install_name_tool -id "@rpath/nerdbank_qrcodes.framework/nerdbank_qrcodes" "$SimulatorFrameworkDir/nerdbank_qrcodes"
chmod +x "$SimulatorFrameworkDir/nerdbank_qrcodes"
}
事实证明,我最后缺少的就是更改我在
DllImportAttribute
中使用的库名称:
#if IOS
// https://github.com/xamarin/xamarin-macios/issues/21238
private const string LibraryName = "@rpath/nerdbank_qrcodes.framework/nerdbank_qrcodes";
#else
private const string LibraryName = "nerdbank_qrcodes";
#endif