Xcode 8: xcodebuildで、Automatic Signingに対応する

# はじめに

Xcode8より、Automatic Signingが導入されました。

※詳細は、[WWDC16 Session401: What's New in Xcode App Signing](https://developer.apple.com/videos/play/wwdc2016/401/)を御覧ください。

Jenkins,Bambooなどで、xcodebuildを用いたBuild/Archiveを行う際、これに対応するために、ビルドスクリプトへ修正が必要となりました。

今回は、その対応におけるポイントと、各ビルドエラーメッセージ対応を記載しておきます。

もし勘違いなどありましたら、教えてください:)

# ポイント

Build/Archiveは、必ず、**Developer Certificate + Provisioning Profileで署名する**ことです。

そして、ExportArchvie/PackageApplicationでのIPA生成時に、Distribution Certificate + Provisioning Profileで署名し直し、配布します。

このとき、**両方のProvisioning Profileが同じ、application-identifier(\<Team ID\>.\<Bundle ID\>)に対応している必要**があります。(WildCard(*)のApp IDを設定していなければ、大方問題ないはずです)

これらのポイントに基づき、以下、エラーメッセージベースに対応を方法を記載していきます。

# ビルドエラー1: Select a development team in the project editor.

```
Signing for *** requires a development team. Select a development team in the project editor.
Code signing is required for product type 'Application' in SDK 'iOS 10.0'
```

Xcode Project > Generalで、Team IDが"None"に選択されていますので、適切なTeam IDを選択しましょう。Build/Archiveは、Developer Certificateで署名するので、問題ありません。

また、その際、エラーメッセージに沿って、ProjectのCapabilities(Entitlements)に適したApp IDの設定など行います。

# ビルドエラー2: *** is automatically signed, but provisioning profile ...

```
*** has conflicting provisioning settings. *** is automatically signed, but provisioning profile XXXXXXXX has been manually specified. Set the provisioning profile value to "Automatic" in the build settings editor, or switch to manual signing in the project editor.
Code signing is required for product type 'Application' in SDK 'iOS 10.0'
```

こちらは、projectで、Automaticを選択しているにも関わらず、xcodebuildで、
`PROVISIONING_PROFILE=XXXXXXXX`を設定しているときのエラーです。

`PROVISIONING_PROFILE`を取り除きます。

Automatic Signingに任せて、Developer Provisioning Profileでビルドしましょう。

# ビルドエラー3: *** is automatically signed, but code signing identity...
```
*** has conflicting provisioning settings. *** is automatically signed, but code signing identity iPhone Distribution: **** has been manually specified.  Set the code signing identity value to "iPhone Developer" in the build settings editor, or switch to manual signing in the project editor.
Code signing is required for product type '***' in SDK 'iOS 10.0'
```

Xcode Project > Build Settingsで、"Code Signing Identity"を"iPhone Developer"としましょう。

# ビルドエラー4: User interaction is not allowed.

```
/path/to/***.app: User interaction is not allowed.
```

iOSエンジニアならお馴染み(?)のエラーメッセージですが、ここにハマりました。。。

先に伝えたポイントにある通り、Buildは、Developer Certificateで、行われます。
そのため、Distribution CertificateのPrivate Keyだけでなく、Developerの方にも対応をしないといけません。

以下、対応方法です。

1. ビルドマシンの"Keychain Access"を開く
2. Team ID用のDeveloper Certificate > Private Keyを右クリック
3. "Get Info" > "Access Control"で、"Allow all applications to access this item"にチェックマークを入れる

もし、インストールしていない場合は、p12ファイルからインストールするか、もしくは、Signing Certificate per Macを作成しましょう。

※ビルドマシンで、ビルド用いる各Certificateは、login Keychainではなく、System Keychainに入れておくことをおすすめします。

# ビルドエラー5: error: exportArchive: The operation couldn’t be completed. 

`xodebuild -exportarchive`を実行したときに、以下のようなエラーが発生する場合があります。

```
error: exportArchive: The operation couldn’t be completed. (IDEDistributionErrorDomain error 3.)

Error Domain=IDEDistributionErrorDomain Code=3 "(null)" UserInfo={IDEDistributionErrorSigningIdentityToItemToUnderlyingErrorKey={
    "<DVTSigningCertificate: 0x7fe7cc0331c0; name='iPhone Distribution: **** (XXXXXXXXX)', hash='68571AEEC4C0D1F7037214840356A0708BF979E9', serialNumber='7AB9DBC09812221C', certificateKind='1.2.840.113635.100.6.1.4, issueDate='2016-04-29 00:16:29 +0000''>" =     {
        "<IDEDistributionItem: 0x7fe7cc17f560 '*****' '<DVTFilePath:0x7fe7cbca22d0:'/../******.app'>'>" = "Error Domain=IDECodesignResolverErrorDomain Code=10 \"No matching provisioning profiles found\" UserInfo={NSLocalizedRecoverySuggestion=No valid 'ad-hoc' profiles were found., NSLocalizedDescription=No matching provisioning profiles found, IDECodesignResolverError_ResolutionInputsKey=<IDECodesignResolutionInputs: 0x7fe7cc0b9190; portalTeamID='XXXXXXXXX', usingTeamBasedSigning='NO', bundleIdentifier='******', targetName='(null)', provisioningProfilePurpose='2', requiresProvisioningProfile='YES', provisioningProfilePlatform='iOS', certificateKind='1.2.840.113635.100.6.1.4', requiredEntitlements='{\n    \"application-identifier\" = \"A9ZFU9BNR3.tech.astonlab.Creuset\";\n    \"keychain-access-groups\" =     (\n        \"*************\"\n    );\n}', requiredCodesignableDevices='(null)', requiredFeatures='(null)'>\n}";
    };
}}
```

長いですが、要は、
`No valid 'ad-hoc' profiles were found. No matching provisioning profiles found`

というエラーです。

これは、Automatic Signingによって選択された、Provisioning Profileの`application-identifier`が、Export Options plistの`teamID`と一致していないために発生していました。

これに対応するためには、まず、build/archiveのビルドログから、codesign時のEntitlementsとSigning Identityを確認してください。

ここから、Automatic Signingによって、どのapplication-identifierが選択され、どのDeveloper Certificateを利用したかがわかります。

一つのケースとして、Wild Card(*)のみのApp IDで、Development Provisioning Profileを作成していると起こりやすいようです。

以下の手順で、それを取り除きます。

1. 該当のProvisioning ProfileをDeveloper Portalより削除
2. Xcode > Preferences > Accountsから、Developer Accountを選択
3. Install済みのProvisioning Profileを右クリックで、"Move to Trash"

これによって、ビルド時に、適切なDevelopment Provisioning Profileが選択されて、application-identifierが一致した、Distribution Provisioning Profileで、無事、IPAを作成できるようになります。

# 最後に

xcodebuildにおける、Automatic Signingへの対応方法を記載しました。

なお、Xcode 8より、`PROVISIONING_PROFILE_SPECIFIER`というBuild Settingsが追加になっています。

これは、Customized Signingで利用でき、`PROVISIONING_PROFILE`と異なり、UUIDではなく、Provisioning Profileの名称で指定ができます。Provisioning Profileへのデバイス追加等変更のたびに、UUIDの変更が入らないため、大変便利とのこと。

こちらは、まだ試していませんが、何か問題に当たったら、追記しようと思います。