You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何调试iOS模拟器/设备上原生依赖抛出的DllNotFoundException

关于iOS平台.NET库原生依赖加载失败的调试与问题排查

问题背景

开发一款支持Android、iOS及桌面系统的.NET库,其他平台运行正常,但iOS平台出现异常。此前本地部署iOS版本可正常运行,但基于该库的应用被App Store拒绝,原因是原生依赖必须封装在Apple Framework中。重构nupkg将原生依赖放入xcframework结构后,iOS csproj可正常构建,且.NET程序集与原生依赖似乎已随应用部署,但应用加载原生依赖时抛出System.DllNotFoundException: 'nerdbank_qrcodes'异常,Visual Studio调试输出仅显示该错误信息。

当前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

原生Framework处理脚本

# 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"
}

排查方向与调试步骤

  • 确认xcframework是否被嵌入到最终App包
    构建完成后找到生成的.app包,右键选择「显示包内容」,查看Frameworks目录下是否存在nerdbank_qrcodes.framework。若不存在,说明NuGet包结构或MSBuild配置有误,导致xcframework未被正确复制到App包中。

  • 验证Framework二进制的架构与路径配置
    在Mac终端执行以下命令:

    # 检查支持的架构
    lipo -info /path/to/nerdbank_qrcodes.framework/nerdbank_qrcodes
    # 检查install_name配置
    otool -L /path/to/nerdbank_qrcodes.framework/nerdbank_qrcodes
    

    确保设备版本的Framework包含arm64架构,模拟器版本包含x86_64和arm64;同时otool输出中的id必须为@rpath/nerdbank_qrcodes.framework/nerdbank_qrcodes。

  • 检查DllImport的库名是否正确
    确认.NET代码中DllImport声明的库名是nerdbank_qrcodes(与Framework目录名一致,不带.framework后缀),而非之前动态库的名称(如libnerdbank_qrcodes)。

  • 查看Xcode控制台的详细日志
    使用Xcode连接设备调试App,查看Console面板的输出,通常会包含加载失败的具体原因(如签名无效、架构不兼容、依赖缺失等)。

  • 检查NuGet包的资源配置
    当前xcframework放置在lib/net8.0-ios17.5/Nerdbank.QRCodes.resources/目录下,需确认MSBuild能识别该结构并正确处理。可在项目的.csproj中显式添加xcframework引用,或检查NuGet包的.targets文件是否正确配置ResolvedFileToPublish,确保xcframework被纳入App包。

  • 验证Framework的签名有效性
    App Store要求所有Framework必须正确签名,执行以下命令检查签名状态:

    codesign -vvv /path/to/nerdbank_qrcodes.framework
    

可能的操作错误点

  • xcframework的Info.plist配置不符合规范
    需确保xcframework的Info.plist中正确声明各切片的平台与架构:设备切片的SupportedPlatform为iOS,SupportedArchitecture为arm64;模拟器切片对应配置正确。

  • 动态库重命名不彻底
    从Rust生成的.dylib文件重命名为Framework内的二进制时,需确保直接命名为nerdbank_qrcodes(与Framework目录同名),不能保留.dylib后缀。

  • NuGet包结构未遵循.NET iOS规范
    iOS平台的原生Framework需放置在正确的NuGet目录结构中,确保MSBuild能自动识别并嵌入到App包,避免手动放置导致的路径识别问题。

内容的提问来源于stack exchange,提问作者Andrew Arnott

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 22:34:58