隨著 macOS 用戶數量的增長,越來越多的開發者希望將自己的桌面應用或游戲上架到 Mac App Store,以便觸達更多用戶并獲得官方的分發優勢。但 Apple 的上架流程相比其他平臺要嚴格得多,涉及簽名、打包、沙盒、審核、公證等環節。本文將以博文的形式,詳細梳理常見跨平臺框架(Flutter / Electron / Qt / Tauri / Python)以及游戲引擎(Unity / Unreal / Godot)的 打包、簽名、公證與上架流程。
A. Mac App Store 與非商店分發的區別
1. Mac App Store (MAS)
- 分發產物:
.pkg
(Product Archive) - 必須:App 沙盒 + 正確的簽名(Apple Distribution / 3rd Party Mac Developer Installer)
- 上傳方式:Transporter(GUI)、Xcode Organizer 或 iTMSTransporter CLI
- 公證(Notarization):不需要開發者自己跑,Apple 在審核過程中會自動完成。
2. 非商店分發(官網直下 / 第三方渠道)
- 分發產物:
.dmg
/.zip
/.pkg
- 必須:Developer ID 簽名 + Hardened Runtime
- 還需:Notarization 公證 + Stapler 釘票,才能通過 Gatekeeper 校驗。
B. 核心步驟總覽
Mac App Store 流程
- 生成
.app
- 簽名(Apple Distribution)
- 打包
.pkg
(productbuild) - Transporter / Xcode 上傳 App Store Connect
非商店分發流程
- 生成
.app
- 簽名(Developer ID Application + Hardened Runtime)
- 打包(
.dmg
/.zip
/.pkg
) notarytool submit
公證stapler staple
釘票spctl --assess
自測
C. 各平臺構建方式
1) Flutter(macOS 桌面)
flutter config --enable-macos-desktop
flutter build macos --release
# 輸出: build/macos/Build/Products/Release/MyApp.app
- MAS:簽名 →
productbuild
→ Transporter 上傳 - 非商店:簽名 → 打包
.dmg
/.pkg
→ 公證 + stapler
2) Electron
# MAS 構建
electron-builder --mac mas# 非商店構建 (DMG)
electron-builder --mac dmg
- 提供
entitlements.mas.plist
/entitlements.mas.inherit.plist
- MAS 簽名 & 沙盒要求較高
3) Qt(C++ / PyQt / PySide)
# 生成 .app
depoyqt MyApp.app -appstore-compliant
- MAS:簽名 → productbuild → Transporter 上傳
- 非商店:簽名 → dmg/pkg → 公證
4) Tauri
cargo tauri build
- 輸出 universal2
.app
- MAS / 非商店均按簽名 & 打包流程繼續
5) Python(PyInstaller / py2app)
# PyInstaller universal2
pyinstaller --windowed --target-arch universal2 main.py
# 輸出 dist/MyApp.app# py2app\python3
setup.py py2app
- MAS:簽名(Apple Distribution)→ productbuild → Transporter
- 非商店:簽名(Developer ID)→ dmg/pkg → 公證
6) Unity
# Build Settings → Platform: macOS → Build
# 輸出: MyGame.app
- MAS:簽名
.app
→productbuild
→ Transporter - 非商店:簽名 → 打包
.dmg
→ 公證 + stapler
7) Unreal Engine
# File → Package Project → macOS
# 輸出: MyUnrealGame.app
- 后續步驟與 Unity 相同
8) Godot
# Editor → Export → macOS → MyGodotGame.zip
- MAS:解壓 zip → 簽名
.app
→ productbuild - 非商店:簽名 → zip/dmg → 公證
D. 簽名與打包命令示例
簽名(MAS - Apple Distribution)
codesign --deep --force --timestamp \--entitlements Entitlements.plist \--sign "Apple Distribution: Your Name (TEAMID)" \"MyApp.app"productbuild \--component "MyApp.app" /Applications \--product "MyApp.app/Contents/Info.plist" \--sign "3rd Party Mac Developer Installer: Your Name (TEAMID)" \"MyApp.pkg"
簽名(非商店 - Developer ID + Hardened Runtime)
codesign --deep --force --timestamp \--options runtime \--entitlements Entitlements.plist \--sign "Developer ID Application: Your Name (TEAMID)" \"MyApp.app"
公證 + Staple
xcrun notarytool submit MyApp.dmg \--apple-id "your@appleid.com" \--team-id "TEAMID" \--password "app-specific-password" \--waitxcrun stapler staple MyApp.dmgspctl --assess --type install -vv MyApp.dmg
E. 常見 Entitlements 配置(MAS 必須)
<dict><key>com.apple.security.app-sandbox</key><true/><key>com.apple.security.network.client</key><true/><key>com.apple.security.files.user-selected.read-write</key><true/>
</dict>
F. 審核前自檢清單
- ? App 使用 Universal Binary (x86_64 + arm64)
- ? 正確的 版本號 與 分類 (LSApplicationCategoryType)
- ? 沙盒權限最小化
- ? 簽名驗證通過 (
codesign -dv
,pkgutil --check-signature
) - ? (非商店)公證 + stapler 成功
總結
- 上架 MAS:簽名(Apple Distribution)→
productbuild
→ Transporter → 審核(Apple 自動公證) - 非商店分發:簽名(Developer ID + Hardened Runtime)→ 打包 → 公證 (
notarytool
) → stapler → Gatekeeper 校驗
掌握這些步驟,你就能讓 Flutter 應用、Electron 桌面端、Qt 工具、Tauri 應用、Python 應用,甚至 Unity/Unreal/Godot 游戲,順利通過 Apple 的嚴格審查,上架 Mac App Store 或安全分發給用戶。