Xcode11 以降のNotarizationの取得方法について


## はじめに

これまでXcode10でビルドしたmacOSアプリのNotarizationの対応は行ったことがあるのですが、
Xcode11では実施したことがありませんでした。
実施にあたり色々とつまづいたので備忘のためドキュメントに残します。

## 前提条件

### ビルド環境

- OS: macOS 10.14.6
- Xcode: 11.3 (11C29)

### ビルドするアプリ

ネットワーク周りの設定を行うアプリで、下記の前提を含みます。

- macOS 10.15より導入されたNetworkExtensionを利用する
- Sparkleといったサードパーティのフレームワークを利用する
- Cocoa.frameworkといったApple謹製のフレームワークを利用する

ビルドするアプリがこれら前提を含まない場合は一部手順は不要となります。

## Notarizationの取得までの概要

そもそもNotarizationとは何か、具体的にどのような手順で取得するのかについては[過去の投稿](https://qiita.com/noby111/items/89840a8ef46185863ace)を参考にしてください。

ざっくりと説明すると、

1. 署名なしの状態でビルドする
2. ビルド物にNotarizationに必要なビルドオプションをつけてcodesignで署名を付ける
3. xcrun altoolを使ってNotarization Serviceに申請を行う
4. 受理されたらxcrun staplerを使ってビルド物に公証をくっ付ける

という手順になります。

Xcode10ではこの手順で上手くいったのですが、Xcode11では後述する理由で上手く行きませんでした。

## つまづいた点① Xcodeの時点で署名が必要

Xcode11ではmacOSアプリのビルドもiOSライクとなり、ビルド時にProvisioningProfileと証明書の指定が必要となります。

これについてはAppleDeveloperで証明書とProvisioningProfileを発行してXcodeで指定すれば良いのですが、次の点に注意してください。

***ProvisioningProfile作成時には、DistributionのDeveloper IDを選択する***

DevelopmentのmacOS App Developmentや、DistributionのMac App StoreでビルドするとNotarizationで下記のエラーが発生します。

```The binary is not signed with a valid Developer ID certificate.```

```The signature of the binary is invalid.```

そのため、必ずDistributionのDeveloper IDを選択してください。

## つまづいた点② Xcodeで署名したものにcodesignで再署名してはいけない

当初私は、Xcode上でDevelopmentのmacOS App DevelopmentのProvisioningProfileと証明書で署名をして、codesignを使って「Developer ID Application XXX」の証明書で署名を付け直していました。

この方法だと、Notarizationは通るのですが、アプリを起動すると必ず```Termination Reason: Namespace CODESIGNING, Code 0x1```というエラーが発生し、アプリが落ちてしまいます。

恐らく、再署名したことでアプリが改ざんされたと見なされて起動ができなくなっているのだと思われます。
尚、codesignには再署名する際に過去の署名時の属性を引き継ぐ```--preserve-metadata```というオプションがありますが、これをフルで指定したとしても結果は変わりませんでした。

>        --preserve-metadata=list
>        When re-signing code that is already signed, reuse some information from the old signature.  If new data is specified
>        explicitly, it is preferred.  You still need to specify the -f (--force) option to enable overwriting signatures at
>        all.  If this option is absent, any old signature has no effect on the signing process.
>        This option takes a comma-separated list of names, which you may reasonably abbreviate:
>
>        identifier    Preserve the signing identifier (--identifier) instead of generating a default identifier.
>
>        entitlements  Preserve the entitlement data (--entitlements).
>
>        requirements  Preserve the internal requirements (--requirements option), including any explicit Designated Require-
>                      ment. Note that all internal requirements are preserved or regenerated as a whole; you cannot pick and
>                      choose individual elements with this option.
>
>        runtime       Preserve the hardened runtime version (-o runtime flag, --runtime-version option) instead of overriding
>                      or deriving the version.
>        For historical reasons, this option can be given without a value, which preserves all of these values as presently
>        known. This use is deprecated and will eventually be removed; always specify an explicit list of preserved items

そのため、必ずXcodeのみで署名を完結するようにしてください。

## つまづいた点③ XcodeでNotarizationに必要なビルドオプションを付ける

[Apple公式のガイド](https://developer.apple.com/documentation/xcode/notarizing_macos_software_before_distribution/resolving_common_notarization_issues)に従って、これまではcodesignに次のオプションをつけて署名を行っていました。

- Secure Timestampを付けるため```--timestamp```オプションを付ける
- Hardened Runtimeを有効化するため```--options=runtime```オプションを付ける
- entitlementsが消えないように```--entitlements {entitlementファイル}```オプションを付ける  
  ※指定するentitlementファイルはXcodeのプロジェクト設定に含まれているもの

全て、Xcode上で完結させるためこれらのオプション指定をXcode上に施します。

- ```--timestamp```と```--options=runtime``` → Build Settings > Signing > Other Code Signing Flags に設定
- ```--entitlements {entitlementファイル}``` → Build Settings > Signing > Code Signing Entitlements に設定

## つまづいた点④ Apple謹製フレームワークはEmbed Without Signingに指定する

Apple謹製のフレームワークをBuild PhasesのLink Binary With Librariesに指定すると、それらをアプリにスタティックで同梱するか、同梱せずダイナミックで利用するかをGeneralのFrameworks, Libraries, and Embedded Contentで選択する必要があります。
Notarizationを受けるためには同梱するライブラリーは署名をつけなければいけないため、「Enbed & Sign」を選択するように思えますが、ここは「Do Not Embed」を選択してください。

「Enbed & Sign」を選択すると、署名がつけられないとビルド時にエラーが発生します。
「Do Not Embed」を選択した場合利用するフレームワークに対応するdylibがContents/Frameworks配下に設置されますが、ビルド時に自動で署名をつけてくれます。

## つまづいた点⑤ サードパーティフレームワークはEnbed & Signに指定する

Apple謹製のフレームワークとは異なり、「Enbed & Sign」を指定する必要があります。
この指定をしないと、Notarizationのタイミングで```The binary is not signed with a valid Developer ID certificate.```や```The signature of the binary is invalid.```が発生します。

## 最後に

以上の点を押さえれば、Xcode11でビルドしたアプリもNotarizationが受けられるようになるはずです。
お疲れ様でした。