为类似 iOS 的平台创建和使用自定义框架

从 .NET 9 开始,本机 AOT 支持发布不依赖于适用于 iOS 的平台的 iOS 工作负载的 .NET 类库。 借助此支持,可以创建可从 iOS、Mac Catalyst 和 tvOS 应用程序使用的自包含本机库。

重要

此方法不附带内置的 Objective-C 互操作性支持,并且可能需要进行其他代码适应(例如封送引用类型参数),以实现互操作性。

生成共享库

本部分介绍使用 NativeAOT 支持创建简单的 .NET 类库项目的步骤,并从中为类似 iOS 的平台生成本机库。

  1. 下载 .NET 9 SDK

  2. 创建类库项目

    dotnet new classlib -n "MyNativeAOTLibrary"
    
  3. 将以下属性添加到项目文件中 MyNativeAOTLibrary.csproj

    <PublishAot>true</PublishAot>
    <PublishAotUsingRuntimePack>true</PublishAotUsingRuntimePack>
    
  4. 编辑 MyNativeAOTLibrary/Class1.cs 源代码以公开托管方法,以便可以从本机代码 aotsample_add中引用它。 例如:

    using System.Runtime.InteropServices;
    namespace NaotLib;
    
    public class Class1
    {
        [UnmanagedCallersOnly(EntryPoint = "aotsample_add")]
        public static int Add(int a, int b)
        {
            return a + b;
        }
    }
    
  5. 通过指定适当的运行时标识符(如下 <rid>所述)发布类库并面向所需的 iOS 类平台:

    dotnet publish -r <rid> MyNativeAOTLibrary/MyNativeAOTLibrary.csproj
    

成功完成上一步将生成一对文件:共享库MyNativeAOTLibrary.dylib及其调试符号MyNativeAOTLibrary.dylib.dSYM,位于: MyNativeAOTLibrary/bin/Release/net9.0/<rid>/publish/

注意

若要创建通用框架,需要发布给定平台的 Arm64 类库和 x64 体系结构。 这意味着需要使用不同的运行时标识符重复步骤 5。 例如,将包含两个maccatalyst-arm64maccatalyst-x64运行时标识符的类库发布为将共享库打包到自定义 MacCatalyst 通用框架的先决条件

创建和使用自定义框架

Apple 要求将共享库 (.dylibs) 打包到框架中才能从应用程序使用。

本部分介绍实现此目的所需的所有步骤,以及使用共享 NativeAOT 库/框架的 iOS/MacCatalyst 应用程序的简单方案。

注意

所述的步骤仅用于演示目的。 实际要求可能因确切用例而异。

将共享库打包到自定义 iOS 框架中

  1. 创建框架文件夹:

    mkdir MyNativeAOTLibrary.framework
    
  2. 调整加载命令:

    • LC_RPATH load 命令

      install_name_tool -rpath @executable_path @executable_path/Frameworks MyNativeAOTLibrary/bin/Release/net9.0/ios-arm64/publish/MyNativeAOTLibrary.dylib
      
    • LC_ID_DYLIB load 命令

      install_name_tool -id @rpath/MyNativeAOTLibrary.framework/MyNativeAOTLibrary MyNativeAOTLibrary/bin/Release/net9.0/ios-arm64/publish/MyNativeAOTLibrary.dylib
      
  3. 将二进制文件手动打包到通用文件中:

    lipo -create MyNativeAOTLibrary/bin/Release/net9.0/ios-arm64/publish/MyNativeAOTLibrary.dylib -output MyNativeAOTLibrary.framework/MyNativeAOTLibrary
    
  4. 将属性列表文件添加到框架:

    • 创建 Info.plist 文件
    touch MyNativeAOTLibrary.framework/Info.plist
    

最后一步之后,框架结构应如下所示:

MyNativeAOTLibrary.framework
    |_ MyNativeAOTLibrary
    |_ Info.plist

将共享库打包到自定义 MacCatalyst 通用框架中

通用框架需要二Arm64x64进制文件和体系结构。 因此,必须事先发布面向以下两个 RID 的本机库: maccatalyst-arm64maccatalyst-x64

  1. 创建框架文件夹结构:

    mkdir -p MyNativeAOTLibrary.framework/Versions/A/Resources
    ln -sfh Versions/Current/MyNativeAOTLibrary MyNativeAOTLibrary.framework/MyNativeAOTLibrary
    ln -sfh Versions/Current/Resources MyNativeAOTLibrary.framework/Resources
    ln -sfh A MyNativeAOTLibrary.framework/Versions/Current
    
  2. 调整加载命令:

    • LC_RPATH load 命令

      install_name_tool -rpath @executable_path @executable_path/../Frameworks MyNativeAOTLibrary/bin/Release/net9.0/maccatalyst-arm64/publish/MyNativeAOTLibrary.dylib
      install_name_tool -rpath @executable_path @executable_path/../Frameworks MyNativeAOTLibrary/bin/Release/net9.0/maccatalyst-x64/publish/MyNativeAOTLibrary.dylib
      
    • LC_ID_DYLIB load 命令

      install_name_tool -id @rpath/MyNativeAOTLibrary.framework/Versions/A/MyNativeAOTLibrary MyNativeAOTLibrary/bin/Release/net9.0/maccatalyst-arm64/publish/MyNativeAOTLibrary.dylib
      install_name_tool -id @rpath/MyNativeAOTLibrary.framework/Versions/A/MyNativeAOTLibrary MyNativeAOTLibrary/bin/Release/net9.0/maccatalyst-x64/publish/MyNativeAOTLibrary.dylib
      
  3. 将二进制文件手动打包到通用文件中:

    lipo -create MyNativeAOTLibrary/bin/Release/net9.0/maccatalyst-arm64/publish/MyNativeAOTLibrary.dylib MyNativeAOTLibrary/bin/Release/net9.0/maccatalyst-x64/publish/MyNativeAOTLibrary.dylib -output MyNativeAOTLibrary.framework/Versions/A/MyNativeAOTLibrary
    
  4. 将属性列表文件添加到框架:

    • 创建 Info.plist 文件
    touch MyNativeAOTLibrary.framework/Versions/A/Resources/Info.plist
    

最后一步之后,框架结构应如下所示:

MyNativeAOTLibrary.framework
    |_ MyNativeAOTLibrary -> Versions/Current/MyNativeAOTLibrary
    |_ Resources -> Versions/Current/Resources
    |_ Versions
        |_ A
        |   |_ Resources
        |   |   |_ Info.plist
        |   |_ MyNativeAOTLibrary
        |_ Current -> A

使用自定义框架

  1. 打开 Xcode (在本示例中 Xcode 16.0 使用)

  2. 创建新的 App 项目

  3. 选择应用的名称(例如 MyiOSApp),然后选择 Objective-C 作为源语言

  4. 添加对框架的 MyNativeAOTLibrary 引用

    • MyiOSApp“常规选项卡的“框架”、“库”和“嵌入内容”下,选择+添加MyNativeAOTLibrary为引用的框架
    • 在对话框中,选择“ 添加其他 ->添加文件 ”,然后浏览到其位置 MyNativeAOTLibrary.framework 并选择它
    • 选择后,为MyNativeAOTLibrary框架设置Embed and Sign选项

    Xcode 添加框架参考

  5. 在“生成设置”选项卡中将位置添加到MyNativeAOTLibrary.framework框架搜索路径列表

    Xcode 添加框架搜索路径

  6. 通过调用公开的托管方法aotsample_add并打印结果进行编辑main.m

    extern int aotsample_add(int a, int b);
    int main(int argc, char * argv[]) {
        ...
        NSLog(@"2 + 5 = %d", aotsample_add(2, 5));
        ...
    }
    
  7. 选择物理 iOS 设备并生成/运行应用

  8. 成功启动应用后检查日志。 应用应打印出来: 2 + 5 = 7

注意

对于 MacCatalyst,除了步骤 7 之外,请使用相同的步骤,其中需要将运行目标设置为: Mac (Mac Catalyst)

使用适用于 iOS 等平台的 NativeAOT 生成静态库

如生成本机库概述中所述,最好基于静态库生成共享库,因为存在一些限制。

但是,如果需要,可以按照生成共享库的步骤生成静态库,并在项目文件中包括附加属性:

<NativeLib>Static</NativeLib>

发布项目后,可以在以下位置找到静态库MyNativeAOTLibrary.aMyNativeAOTLibrary/bin/Release/net9.0/<rid>/publish

本文不介绍如何使用静态库和配置使用者项目。

附录 Info.plist 内容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleName</key>
    <string>MyNativeAOTLibrary</string>
    <key>CFBundleIdentifier</key>
    <string>com.companyname.MyNativeAOTLibrary</string>
    <key>CFBundleVersion</key>
    <string>1.0</string>
    <key>CFBundleExecutable</key>
    <string>MyNativeAOTLibrary</string>
    <key>CFBundlePackageType</key>
    <string>FMWK</string>
</dict>
</plist>