macOSアプリをMac App Store外で配布するときは、Appleに提出して公証(notarization)を受ける。公証に通ったアプリには、Appleが公証チケットを発行する。このチケットをアプリに添付する操作がstaple(ステープル)である。チケットを添付したアプリは、オフラインの環境でも、Gatekeeperが公証済みであると判断できる。
公証からstapleまでは、次の流れである。
$ ditto -c -k --keepParent [アプリ名].app [アプリ名].zip
$ xcrun notarytool submit [アプリ名].zip --keychain-profile "[プロファイル名]" --wait
$ xcrun stapler staple [アプリ名].app
stapleした後は、配布用のzipを作り直す。実行例はXcode 27.0、macOS 27.0.1のもの。認証情報(--keychain-profile)は、事前にnotarytool store-credentialsで保存しておく。
- 前の記事: 【notarytool】App用パスワードで公証用の認証情報を保存する
- 親記事: GitHubを使い、macOSアプリを署名・公証・自動アップデート付きで公開する
- 次の記事: 【notarytool】公証に失敗した理由をログから調べる
公証に提出するzipを作る
notarytool submitに渡せるのは、zip、.pkg、.dmgのいずれかである。.appはディレクトリのため、そのままでは提出できない。dittoでzipにまとめる。
$ ditto -c -k --keepParent [アプリ名].app [アプリ名].zip
--keepParentを付けると、zipの中に[アプリ名].appディレクトリが含まれる。
.appを直接提出すると、エラーになる。
$ xcrun notarytool submit [アプリ名].app --keychain-profile "[プロファイル名]"
Conducting pre-submission checks for [アプリ名].app and initiating connection to the Apple notary service...
Error: [アプリ名].app must be a zip archive (.zip), flat installer package (.pkg), or UDIF disk image (.dmg), use 'notarytool submit --force' to skip this validation and submit anyway.
公証を提出して結果を待つ
notarytool submitで、zipをAppleのノータリーサービスに提出する。--waitを付けると、公証の処理が終わるまで待つ。
$ xcrun notarytool submit [アプリ名].zip --keychain-profile "[プロファイル名]" --wait
Conducting pre-submission checks for [アプリ名].zip and initiating connection to the Apple notary service...
Submission ID received
id: [提出ID]
Successfully uploaded file
id: [提出ID]
path: [アプリ名].zip
Waiting for processing to complete.
Current status: In Progress...Current status: In Progress....Current status: Accepted.....Processing complete
id: [提出ID]
status: Accepted
status: Acceptedになれば、公証は成功である。今回の検証用の小さなアプリでは、提出から結果が出るまで約20秒だった。アプリの大きさや混雑によって、所要時間は変わる。
提出のIDは、後から結果を確認するために使う。notarytool infoで、提出の状態を確認できる。
$ xcrun notarytool info [提出ID] --keychain-profile "[プロファイル名]"
Successfully received submission info
createdDate: [提出した日時]
id: [提出ID]
name: [アプリ名].zip
status: Accepted
statusには、処理中のIn Progress、成功のAccepted、失敗のInvalidなどがある。Invalidになった場合の調べ方は、公証のログの記事で解説する。
参考: 【notarytool】公証に失敗した理由をログから調べる
stapleで公証チケットを添付する
xcrun stapler stapleで、公証チケットをアプリに添付する。対象は.appである。
$ xcrun stapler staple [アプリ名].app
Processing: [アプリ名].app
Processing: [アプリ名].app
The staple and validate action worked!
zipにはstapleできない。
$ xcrun stapler staple [アプリ名].zip
Processing: [アプリ名].zip
Stapler is incapable of working with ZIP archive files.
stapleの前後でアプリの状態を確認する
チケットが添付されているかどうかは、stapler validateで確認できる。stapleの前は、チケットがないと表示される。
$ xcrun stapler validate [アプリ名].app
Processing: [アプリ名].app
[アプリ名].app does not have a ticket stapled to it.
stapleの後は、検証に成功する。
$ xcrun stapler validate [アプリ名].app
Processing: [アプリ名].app
The validate action worked!
公証チケットは、アプリのContents/CodeResourcesファイルとして保存される。stapleの前のContentsには、このファイルがない。
$ ls [アプリ名].app/Contents
_CodeSignature
Info.plist
MacOS
PkgInfo
Resources
$ xcrun stapler staple [アプリ名].app
$ ls [アプリ名].app/Contents
_CodeSignature
CodeResources
Info.plist
MacOS
PkgInfo
Resources
codesign -dvにも、チケットの有無が表示される。
$ codesign -dv --verbose=4 [アプリ名].app 2>&1 | grep Notarization
Notarization Ticket=stapled
stapleした後に配布用のzipを作り直す
公証に提出したzipには、チケットが含まれない。提出したzipは、stapleする前のアプリを固めたものだからである。
stapleしたアプリを配布するには、stapleの後に、もう一度zipを作る。
$ ditto -c -k --keepParent [アプリ名].app [アプリ名]-[バージョン].zip
作り直したzipには、公証チケットのContents/CodeResourcesが含まれる。
$ unzip -l [アプリ名]-[バージョン].zip | grep 'Contents/CodeResources'
1653 10-04-2026 09:13 [アプリ名].app/Contents/CodeResources
提出に使ったzipには、このファイルがない。配布するのは、stapleの後に作ったzipである。
stapleしなくても公証済みと判定される
spctlでGatekeeperの判定を確認すると、stapleの前でも、公証済みのアプリはNotarized Developer IDと判定される。インターネットに接続できる環境では、GatekeeperがAppleのサーバーに公証の記録を問い合わせる。
参考: 【spctl】Gatekeeperの判定を配布前に確認する
$ spctl --assess --type execute -vv [アプリ名].app
[アプリ名].app: accepted
source=Notarized Developer ID
origin=Developer ID Application: [名前] ([Team ID])
stapleしておくと、問い合わせができないオフライン環境でも、同じ判定になる。配布するアプリには、stapleを実行する。
