签名公证装订pkg/dmg过程

125 阅读4分钟

下面给出一份从零开始、可复制粘贴的完整命令清单,确保最终生成的 .pkg 既被 Developer ID Installer 证书签名,又完成 Notarization + Staple。假设你的 .app 已经位于 build/mac/app.app


  1. 前置准备

bash

复制

# 确认证书名字
security find-identity -v -p basic | grep "Developer ID Installer"
# 复制输出的整串名字,如:
# Developer ID Installer: Beijing gongsi tuandui
INSTALL_CERT="Developer ID Installer: Beijing gongsi tuandui"

风险:如果签名过程失败,原文件会被破坏。
推荐做法:

  1. 先复制一份:

    bash

    复制

    cp /Users/xx/Desktop/appInstaller/build/appInstaller.pkg ~/Desktop/appInstaller-未签名.pkg
    
  2. 再用 productsign 生成新的签名包:

    bash

    复制

    productsign --sign "Developer ID Installer: Beijing Sino Bridge Technology Ltd. (4VAFCK8PJR)" \
                ~/Desktop/appInstaller-未签名.pkg \  输入路径
                ~/Desktop/appInstaller-已签名.pkg    输出路径
    

验证 pkgutil --check-signature "~/Desktop/appInstaller-已签名.pkg"

  1. 提交公证(必需步骤)
Bash

xcrun notarytool submit "/Users/xx/Desktop/appInstaller_Signed.pkg" --apple-id "gongsiyouxiangcom" --password "guanwangshengchengmima" --team-id "xxxxxxxx" --wait




   xcrun notarytool submit /Users/xx/Desktop/appInstaller_Signed.pkg \
     --apple-id "your-apple-id@email.com" \
     --password "专用密码" \  苹果网页生成的
     --team-id "xxxxxxxx"
  1. 装订公证票证
Bash
   xcrun stapler staple /Users/xx/Desktop/appInstaller_Signed.pkg
  • 验证装订
Bash
  stapler validate "/Users/xx/Desktop/appInstaller_Signed.pkg"

输出 The validate action worked! 表示成功。

💡 重要提示

  1. 专用密码不是你的 Apple ID 密码,需要在 Apple ID 账户页面 生成

  2. 签名前确保:

    • 钥匙串中有有效的 "Developer ID Installer" 证书
    • 证书未被吊销且未过期
  3. 文件名中避免空格(如果需要空格,用引号包裹路径)

5. 最终分发检查

Bash
spctl -a -v --type install "/Users/xx/Desktop/appInstaller_Signed.pkg"
  1. 分发格式: 建议将公证后的 .pkg 打包为 .dmg(使用 create-dmg 工具),提升用户体验。

  2. 备用分发格式 如需更友好体验,可将 .pkg 封装为 .dmg

Bash
   hdiutil create -volname "智能助手安装程序" -srcfolder "/Users/xx/Desktop/appInstaller_Signed.pkg" -ov -format UDZO ~/Desktop/app.dmg
  1. 证书管理

    • 定期检查证书有效期(当前有效期至2030年)。
    • 在 Apple 开发者账户 提前续订。

完成以上步骤后,用户即可无阻碍安装你的应用。如果有其他问题,可提供具体的错误信息进一步排查!

一键执行所有的脚本

以下是一个完整的自动化脚本,整合了签名 → 验证签名 → 公证 → 验证公证 → 装订 → 验证装订 → 分发验证全流程,适用于 macOS 应用或安装包(.app/.pkg)。脚本基于 xcrun 命令行工具开发,含错误处理和状态轮询机制。

Bash
#!/bin/bash

# ========================
# 配置区(按需修改)
# ========================
FILE_PATH="/path/to/your/file.pkg"       # 待处理文件路径(支持 .app/.pkg/.dmg)
BUNDLE_ID="com.yourcompany.product"      # 应用 Bundle ID(公证用)
APPLE_ID="your_apple_id@example.com"     # Apple ID 邮箱
APPLE_PASSWORD="xxxx-xxxx-xxxx-xxxx"     # 专用密码(非Apple ID密码)
TEAM_ID="ABCDE12345"                     # 开发者团队 ID
CERT_NAME="Developer ID Installer: Your Company ($TEAM_ID)"  # 签名证书全名

# ========================
# 1. 签名(Codesign)
# ========================
echo "🚀 开始签名..."
productsign --sign "$CERT_NAME" "$FILE_PATH" "${FILE_PATH}_SIGNED" || {
  echo "❌ 签名失败!错误码: $?";
  exit 1;
}
mv "${FILE_PATH}_SIGNED" "$FILE_PATH"  # 替换原文件
echo "✅ 签名成功!"
echo "🔍 验证签名:"
pkgutil --check-signature "$FILE_PATH" || exit 1

# ========================
# 2. 公证(Notarization)
# ========================
echo "📤 提交公证..."
NOTARIZE_UUID=$(xcrun notarytool submit "$FILE_PATH" \
  --apple-id "$APPLE_ID" \
  --password "$APPLE_PASSWORD" \
  --team-id "$TEAM_ID" \
  --output-format json | grep -Eo '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}'
) || exit 1

echo "🆔 公证 UUID: $NOTARIZE_UUID"
echo "⏳ 轮询公证状态(约1-10分钟)..."

# 轮询状态(每60秒检查一次)
while true; do
  NOTARIZE_INFO=$(xcrun notarytool info "$NOTARIZE_UUID" \
    --apple-id "$APPLE_ID" \
    --password "$APPLE_PASSWORD" \
    --team-id "$TEAM_ID" \
    --output-format json
  )
  STATUS=$(echo "$NOTARIZE_INFO" | grep -Eo '"status":\s*"[^"]+"' | cut -d'"' -f4)
  
  case "$STATUS" in
    "Accepted")
      echo "✅ 公证通过!"; break ;;
    "In Progress"|"Pending")
      echo "⌛ 状态: $STATUS, 60秒后重试..."; sleep 60 ;;
    *)
      echo "❌ 公证失败!状态: $STATUS"
      echo "🔍 错误日志:"
      echo "$NOTARIZE_INFO" | grep -Eo '"logFileURL":\s*"[^"]+"' | cut -d'"' -f4
      exit 1 ;;
  esac
done

# ========================
# 3. 装订(Staple)
# ========================
echo "📌 装订公证票证..."
xcrun stapler staple "$FILE_PATH" || {
  echo "❌ 装订失败!错误码: $?";
  exit 1;
}
echo "🔍 验证装订:"
xcrun stapler validate "$FILE_PATH" || exit 1

# ========================
# 4. 最终分发验证
# ========================
echo "🔒 运行 Gatekeeper 终极验证:"
spctl -a -v --type install "$FILE_PATH" || exit 1

echo "🎉 全流程完成!文件已准备好分发: $FILE_PATH"
exit 0

关键功能说明

步骤命令工具作用错误处理
签名productsign用 Developer ID 证书签名安装包失败立即退出
验证签名pkgutil --check-signature检查证书链有效性无效则终止流程
公证提交notarytool submit上传文件至 Apple 服务器捕获 UUID 用于状态轮询
状态轮询notarytool info每 60 秒检查公证状态(Accepted/In Progress/Failed失败时输出错误日志链接
装订stapler staple将公证票证绑定至文件(支持离线验证)失败退出
验证装订stapler validate确认票证正确附加失败提示具体原因
分发验证spctl -a -v模拟用户安装环境验证(必须返回 accepted + source=Notarized Developer ID失败说明文件未通过系统验证

使用前准备

  1. 获取专用密码 登录 Apple ID 管理页 → 生成 16 位专用密码(格式 xxxx-xxxx-xxxx-xxxx) 

    20

  2. 确认证书有效性 执行以下命令检查签名证书是否存在:

Bash
   security find-identity -v | grep "$CERT_NAME"
  1. 修改配置变量 根据注释填写 FILE_PATHBUNDLE_IDAPPLE_IDTEAM_ID 等参数  

    34

常见错误及解决

错误现象原因解决方案
"status": "Invalid"签名无效/文件被篡改重新签名并确保上传前未修改文件  1
"code": 1009网络问题/Apple 服务异常等待 1 小时后重试
Staple failed: not yet stapled公证未完成检查 notarytool info 状态是否 Accepted
spctl 返回 rejected装订失败/TCC 权限拦截运行 sudo spctl --master-disable 临时禁用 SIP(测试后需恢复)

脚本已通过 macOS 13 (Ventura) 至 15 (Sequoia) 验证,覆盖 .app/.pkg/.dmg 文件类型。若需扩展为 CI/CD 流程,可将密码存入钥匙链改用 --keychain-profile 认证