发布适用于 macOS 的 .NET 应用

与其他平台相比,发布适用于 macOS 的 .NET 应用程序需要执行几个额外的步骤,因为 Apple 的安全要求。

先决条件

在发布适用于 macOS 的 .NET 应用程序之前,请确保具有以下各项:

  • Apple 开发人员帐户:代码签名和公证所需的帐户。
  • Xcode 命令行工具:提供codesignaltool和其他实用工具。
  • .NET SDK:确保已安装最新的 .NET SDK。

使用 .NET SDK 生成应用

使用 .NET 应用程序发布概述 中所述的方法之一生成应用程序。 可以创建依赖于框架的应用程序或自包含应用程序。

对应用进行签名和公证

使用 Apple 的开发人员文档 对应用程序的原生二进制文件进行签名和公证。 .NET 创建一个本机 apphost 可执行文件作为应用程序的入口点。 此 apphost 必须签名,并且如果应用使用特殊功能,则必须为其分配适当的 权利

未作为 Native AOT 发布的应用的权利

对于未作为 Native AOT 发布的应用,com.apple.security.cs.allow-jit需要相应权利。

作为 Native AOT 发布的应用的权利

对于作为 Native AOT 发布的应用,不需要任何权利。

用于调试和诊断的可选权限

以下权利支持其他调试和诊断功能:

  • com.apple.security.get-task-allow使用createdumpdotnet dump收集转储时需要。
  • com.apple.security.cs.debugger:需要将调试器附加到进程。

警告

未能对应用进行签名和公证可能会导致应用程序在执行受限作时崩溃。

通用二进制

macOS 支持 通用二进制文件:单个 Mach-O 文件,其中包含多个 CPU 体系结构的计算机代码。 macOS 会选择与当前处理器相匹配的架构切片,因此,同一个文件可在采用 Apple 芯片(arm64)和 Intel(x64)的计算机上原生运行。

.NET不直接生成通用二进制文件。 相反,你只需针对每种架构分别发布一次应用,然后使用 Apple lipo 工具将这两个原生可执行文件合并。 两种 .NET 发布模式会生成可按这种方式进行合并的自包含原生可执行文件:

发布单文件通用二进制文件

将应用针对每种架构各发布一次,并分别发布到单独的目录中:

dotnet publish -c Release -r osx-arm64 --self-contained true \
    -p:PublishSingleFile=true -o out/osx-arm64

dotnet publish -c Release -r osx-x64 --self-contained true \
    -p:PublishSingleFile=true -o out/osx-x64

然后合并两个可执行文件并重新对结果签名:

mkdir -p out/universal
lipo -create -output out/universal/MyApp out/osx-arm64/MyApp out/osx-x64/MyApp
codesign --force --sign - out/universal/MyApp

独立单文件发布将运行时、托管程序集和本机库嵌入可执行文件本身,因此合并的文件是完整的应用。 通用二进制文件大致是两个输入的总和。

将某个按架构划分的输出目录中剩余的所有文件(例如 appsettings.json 或被排除在捆绑包之外的文件)复制到合并后的可执行文件旁边。

发布 Native AOT 通用二进制文件

这些步骤与单文件相同,但将单文件属性替换为 PublishAot

dotnet publish -c Release -r osx-arm64 -p:PublishAot=true -o out/osx-arm64
dotnet publish -c Release -r osx-x64   -p:PublishAot=true -o out/osx-x64

mkdir -p out/universal
lipo -create -output out/universal/MyApp out/osx-arm64/MyApp out/osx-x64/MyApp
codesign --force --sign - out/universal/MyApp

原生 AOT 生成的文件比单文件发布小得多,因此通用二进制文件的体积也会保持较小。

Native AOT 还会为每个体系结构生成一个 MyApp.dSYM 调试符号包。 若要保留这两个切片的符号,请保留按架构划分的目录,或将捆绑包内的 DWARF 二进制文件与 lipo 合并。