macOS App 签名与公证流程详解及一键自动化

一、签名证书申请

  • 注册 Apple Developer Program(年费 $99),⚠️务必登录账号所有人的 Apple 账号 ,才能操作申请这个证书。
  • 在 Apple Developer 开发证书申请后台,创建以下证书:
    • Developer ID Application:用于签名应用。
    • Developer ID Installer:用于签名安装包。
  • macOS App 证书 和 iOS App 开发是两套证书,有些证书名字很相似,注意做好区分。
  • 下载并安装相关证书,⚠️证书信任采用默认设置,信任等级要保持一致。

二、签名前的准备工作

在 macOS 中,应用的代码签名和打包结构有严格要求,不正确的库放置位置会导致签名验证失败或运行时崩溃。以下是苹果对 macOS 应用打包结构的要求及解决方案:

1.确保应用结构符合苹果的 macOS 签名规范

macOS 应用 .app 包格式(本质是目录),标准结构如下:

plaintext 复制代码
YourApp.app/
├── Contents/
│   ├── Info.plist               # 应用元数据(必选)
│   ├── PkgInfo                  # 包类型信息(可选)
│   ├── MacOS/                   # 可执行文件目录
│   │   └── YourApp              # 主程序(必选)
│   ├── Resources/               # 资源文件(图标、nib 等)
│   ├── Frameworks/              # 动态框架目录(存放 .framework)
│   │   ├── Framework1.framework
│   │   └── Framework2.framework
│   └── Libraries/               # 动态库目录(存放 .dylib,较少使用)
│       └── libYourLibrary.dylib
└── _CodeSignature/              # 签名信息目录(由 codesign 自动生成)
    └── CodeResources

2.关键目录的作用

2.1 Frameworks/

  • 存放应用依赖的动态框架(.framework),这些框架会被应用动态加载。
  • 签名要求:框架必须单独签名,且其内部的二进制文件、资源文件也需递归签名。

2.2 Libraries/

  • 存放独立的动态库(.dylib),但苹果推荐优先使用 .framework 格式。
  • 注意:若使用 .dylib,需确保路径正确配置(如 @rpath)。

2.3 MacOS/

  • 主程序可执行文件必须位于此目录,否则系统无法找到入口点。

3.检查 YourApp.app 的 Info.plist 配置情况

其中必须包含以下关键字段:

plaintext 复制代码
CFBundleName   YourApp
CFBundleExecutable      YourApp
CFBundlePackageType  APP
CFBundleIdentifier    com.yourcompany.aippt

4.检查库依赖

  • 使用 otool -L 查看依赖库
bash 复制代码
otool -L YourApp.app/Contents/MacOS/YourApp

可以列出可执行文件依赖的所有库及其路径。检查输出中是否存在指向 /usr/lib/usr/local/lib、或其他非应用目录的路径。如果有,说明有库没有正确包含在应用包中。 ⚠️注意:这里只是初步扫描,并不是很准确,是否引用三方库,需要代码确认。

  • 检查嵌入框架和插件 :对应用包内的每个可执行文件(如 Contents/FrameworksContents/PlugIns 中的 .dylib/ .so/*.node 等),同样使用 otool -L 检查。例如:
bash 复制代码
otool -L YourApp.app/Contents/Frameworks/*.dylib

确认所有依赖都指向包内路径(通常以 @rpath@loader_path@executable_path 开头)并且实际存在于应用包中。

5.检查网络配置,尽量关闭VPN,代理等

因代码签名时,系统会向苹果的时间戳服务器(timestamp.apple.com)请求时间戳,用于验证签名的有效性和时间。可能被防火墙、代理或网络环境拦截,无法访问苹果的时间戳服务器。

三、签名流程---脚本自动化

创建一个签名管理的文件夹MacSign,将【待签名.app】文件放进去该目录。 在MacSign目录下,通过文本编辑器,创建名为 sign.command文件:

bash 复制代码
#!/bin/bash
printf "\033c"
{ set +e; unset SHELL_SESSION_HISTORY; } >/dev/null 2>&1
# ===================== 配置 =============================
CERT_NAME="Developer ID Application: Shenzhen Pixel Bloom Technology Co., Ltd. (7UXDYFGRA9)"
APPLE_ID="wyk125@163.com"
TEAM_ID="xxxxxxxxxx"
NOTARY_PASSWORD="xxxx-xxxx-xxxx-xxxx"
APP_DIR="$HOME/MacSign"
INPUT_APP="待签名.app"
OUTPUT_DMG="签名完成.dmg"
# =======================================================
cd "$APP_DIR" || exit 1
# 主界面
echo "=========================================================="
echo "🚀 macOS App 签名与公证一键自动化"
echo "=========================================================="
echo "📦 输入:${INPUT_APP}"
echo "📀 输出:${OUTPUT_DMG}"
echo "=========================================================="

echo -n -e "\n1️⃣  正在给 APP 签名..."
codesign --force --deep --options runtime --sign "$CERT_NAME" "$INPUT_APP" >/dev/null 2>&1 && echo "✅"

echo -n "2️⃣  验证签名有效性..."
codesign --verify --deep --strict "$INPUT_APP" >/dev/null 2>&1 && echo "✅"

echo -n "3️⃣  生成 DMG 安装包..."
hdiutil create -volname "签名完成" -srcfolder "$INPUT_APP" -ov -format UDZO "$OUTPUT_DMG" >/dev/null 2>&1 && echo "✅"

echo -n "4️⃣  给 DMG 签名..."
codesign --sign "$CERT_NAME" "$OUTPUT_DMG" >/dev/null 2>&1 && echo "✅"

# 5️⃣ 公证 
echo -e "\n5️⃣  提交苹果公证(请等待)..."
xcrun notarytool submit "$OUTPUT_DMG" --apple-id "$APPLE_ID" --team-id "$TEAM_ID" --password "$NOTARY_PASSWORD" --wait 2>&1 \
| sed 's/and initiating connection/\nand initiating connection/'
# 公证结果
if [ $? -eq 0 ]; then echo -e "✅ 公证成功"; else echo -e "❌ 公证失败"; sleep 1; fi

# 6️⃣ 绑定凭证
echo -n -e "\n6️⃣  绑定公证凭证..."
xcrun stapler staple "$OUTPUT_DMG" >/dev/null 2>&1 && echo "✅"

# 完成提示
echo -e "\n=========================================================="
echo " ✅ 全部操作完成!"
echo " 📀 成品文件:${APP_DIR}/${OUTPUT_DMG}"
echo "=========================================================="

# 🔥 绝杀:按回车 → 瞬间关闭终端(系统来不及输出任何日志)
read -rs -t 3600
osascript -e 'tell application "Terminal" to quit window 1' >/dev/null 2>&1 & exit 0

⚠️配置信息需要改成自己公司的,才可正常签名。

双击sign.command文件,弹起终端窗口,脚本自动化处理所有流程。

说明:因新系统对拖动触发脚本做了限制,自动操作捕获输入变量异常,为了简化处理,采用固定输入和固定输出。也可能是我未配置正确,欢迎熟悉的朋友赐教下, 我们一起完善下!

INPUT_APP="待签名.app"

OUTPUT_DMG="签名完成.dmg"

执行结果

四、签名流程详解

创建一个签名管理的文件夹MacSign,将【AiPPT.app】文件放进去该目录。

1.先对【AiPPT.app】进行代码签名

1.1清理旧签名(可选)

plaintext 复制代码
codesign --remove-signature AiPPT.app

1.2递归签名依赖项(签名内部文件)

Developer ID Application 需要换成自己公司的

plaintext 复制代码
sudo codesign -f -o runtime -s "Developer ID Application: Shenzhen Pixel Bloom Technology Co., Ltd. (7UXDYFGRA9)" -v AiPPT.app --deep  --verbose=4

三方库一般不用独立签名,重复签名可能会引起签名冲突等不可控的异常问题。 特殊情况下,才单独对内部关键文件签名,后对.app 签名

plaintext 复制代码
sudo codesign -f -o runtime -s "Developer ID Application: Shenzhen Pixel Bloom Technology Co., Ltd. (7UXDYFGRA9)" -v AiPPT.app/Contents/Libraries/bydm.dylib  --verbose=4

1.3验证代码签名

plaintext 复制代码
codesign --verify --deep --strict --verbose=4 AiPPT.app

提示如下,则代码签名成功

AiPPT.app: valid on disk

AiPPT.app: satisfies its Designated Requirement

2.再对【AiPPT.dmg】进行包签名

2.1创建 .dmg 文件

plaintext 复制代码
hdiutil create -volname "AiPPT" -srcfolder "AiPPT.app" -ov -format UDZO "AiPPT.dmg"

2.2对dmg签名

plaintext 复制代码
codesign --sign "Developer ID Application: Shenzhen Pixel Bloom Technology Co., Ltd. (7UXDYFGRA9)" AiPPT.dmg

2.3验证dmg代码签名

plaintext 复制代码
codesign --verify --deep --strict --verbose=4 AiPPT.dmg

提示如下,则代码签名成功

AiPPT.app: valid on disk AiPPT.app: satisfies its Designated Requirement

3.对【AiPPT.dmg】进行签名公证

3.1对 .dmg 本身进行公证

⚠️公证信息需要改成自己公司的,才可正常公证。

plaintext 复制代码
xcrun notarytool submit AiPPT.dmg \
  --apple-id "wyk125@163.com" \
  --team-id "xxxxxxxxx" \
  --password "xxxx-xxxx-xxxx-xxxx" \
  --wait

3.2装订公证票据

将已公证的 .dmg 文件装订票据,以标记该文件已被公证,可离线使用:

bash 复制代码
xcrun stapler staple AiPPT.dmg

4.对签名进行验证

4.1验证APP签名合法性,Gatekeeper验公证结果

plaintext 复制代码
 spctl --assess --type execute --verbose=4 AiPPT.dmg

正确的提示信息如下:

AiPPT.app: accepted source=Notarized Developer ID

4.2获取签名的信息

plaintext 复制代码
spctl -a -vv /Users/wangyongkang/MacSign/AiPPT.dmg

成功获取信息,提示如下:

/Users/wangyongkang/MacSign/AiPPT.app: accepted source=Notarized Developer ID origin=Developer ID Application: Shenzhen Pixel Bloom Technology Co., Ltd. (7UXDYFGRA9)

5.完成以上签名流程,就可分发 .dmg 安装包

✅ 签名有效

✅ 已通过 Apple 公证

✅ 已正确 stapled(嵌入公证票据)

✅ Gatekeeper 认可为安全应用

点击签名后的 .dmg 文件,按流程安装即可。

参考文档

苹果官方文档:developer.apple.com/developer-i...

相关推荐
Timer@4 小时前
LangChain 教程 03|快速开始:10 分钟创建第一个 Agent
前端·javascript·langchain
亿元程序员4 小时前
十年游戏程序员开箱实测:这台显示器,彻底改写了我的游戏开发日常
前端
凉城a4 小时前
前端性能优化解决方案
前端·性能优化
慧一居士4 小时前
Zod 功能、使用场景介绍以及对应场景使用示例
前端·vue.js
我命由我123454 小时前
React - React 配置代理、搜索案例(Fetch + PubSub)、React 路由基本使用、NavLink
开发语言·前端·javascript·react.js·前端框架·html·ecmascript
The Sheep 20234 小时前
C# 操作XML
xml·前端·c#
存在的五月雨5 小时前
Nodejs的一些
前端
l14372332675 小时前
短剧出海翻译工具测评:同一段素材实测对比
大数据·前端·人工智能
小马_xiaoen5 小时前
Vue 3 + TS 实战:手写 v-no-emoji 自定义指令,彻底禁止输入框表情符号!
前端·javascript·vue.js
文心快码BaiduComate5 小时前
有奖征集|解锁Comate超能力:一文玩转Comate Skills
前端·后端