個人開発だと適当になりがちなiOSの証明書とアカウントを理解する

2018新卒のiOSエンジニアの山田です。
個人開発では適当に処理(Signingに任せっぱなし)してることが多かったので、これを機になんとなくやっていたことを明確に理解していきます。

# 証明書関連のあれこれ
CSR・証明書・Provisioning Profileについては
[iOSエンジニアが公開暗号鍵方式とApple証明書について調べた](https://qiita.com/guitar_char/items/0b35ba7c02f3c748c5ab)
これで調べた。

この記事が本当に分かり易かった。
[iOSアプリのプロビジョニング周りを図にしてみる](https://qiita.com/fujisan3/items/d037e3c40a0acc46f618)

## 主要な登場人物
| 種類      |     権限 |
|:-------:|:----------:|
| CSR   |All |
| 開発用証明書| All |
| 開発用Provisioning Profile| All |
| 配布用証明書 | Admin以上 | | | 
| 配布用Provisioning Profile| Admin以上 | 
| App ID  |   All ※(削除のみAdmin以上)| 
| デバイス管理  |   All |

## CSR
証明書署名リクエスト。公開鍵と所有者の情報などが署名されている。
**ローカルのキーチェーンで作成し**、証明書を作成するのに使う。
作成時に、秘密鍵と公開鍵も同時に作られる。

CSRと秘密鍵はマシン変更時や引き継ぎ時などにまとめて使うことが多いので、まとめてちゃんと管理しておくのが良いとのこと。

## 証明書
CSRを使って、「Certificates, Identifiers & Profiles」上で作成する。

作成後はダウンロードして、ダブルクリックでキーチェーンに登録して使う。
証明書は秘密鍵を含んでおらず、引き継ぎなどで別のマシンで開発を継続するときは、配布用証明書と秘密鍵をp12ファイルにしてやりとりすることが多い。

**Xcode上でアプリを実機用にビルドするのに必ず必要。(シミュレーター実行の場合は不要)**

monacaのサイトがすごい分かり易かった。
[iOS アプリのビルド](https://docs.monaca.io/ja/products_guide/monaca_ide/build/ios/build_ios/)

証明書には大別して2種類あり、その中で分類がある。

### 開発用証明書(Development)

- iOSアプリ開発用証明書
- APNsサービスSSL証明書(Sandbox)

### 本番用証明書(Production)
- App Storeとアドホック配信用証明書
- APNsサービスSSL証明書(Production)
- Pass Type ID 証明書
- Website Push ID 証明書
- WatchKit Services 証明書
- VoIP Services 証明書

がある。
権限によって作成できる証明書が変わるので、権限のリストを要確認。

## Provisioning Profile

プロファイルには、

- AppID
- 開発機識別子
- 証明書

の情報が紐づけられている。
**Xcode上でアプリを実機用にビルドするのに必ず必要。(シミュレーター実行の場合は不要)**

- 登録したAppIDで
- 登録した開発デバイスを使って、
- 紐づけた証明書と、キーチェーンに保存してある証明書が一致

した時のみ、ビルド可能になる仕組み。
[ Provisioning Profile とは　～アプリ開発に必要な事務手続き～
](http://mycode.snow69it.net/818/)を参考にした。

プロファイルも開発用と配布用の2種類に大別され、その中で分類がある。

### 開発用プロファイル
**検証デバイスでの動作確認の際に**、信頼できる開発元かどうかを確認する。
どの権限レベルでも扱える。

- iOSアプリ開発用プロファイル
- tvOSアプリ開発用プロファイル

### 配布用プロファイル
内部にAdHocとAppStoreがあるが、どちらもAdmin以上の権限で作成可能

**App Storeで一般配布する際に**、信頼できる開発元がどうかを確認する。

- App Store
- tvOS App Store

**Ad-Hocで評価検証用のipaを配布するときに**、信頼できる開発元がどうかを確認する。

- Ad Hoc
- tvOS Ad Hoc

※ Ad Hocとはラテン語で「限定目的のための」のような意味
developer.apple.comによれば、アドホック配布ではアプリケーションが動作する「デバイスを限定」する。という文脈

## App ID
アプリケーションを識別するために使われる。
プロファイルを作成するのに必要。

<font color="OrangeRed"> **開発用と配布用での区別はない。** </font>
作成と設定は全権限で可能であるが、**削除のみMember権限では扱えない。**

以下の要素から構成される。

- **App ID Description:**
AppIDの説明。識別用なのでなんでもよい。

- **App ID Prefix:**
App IDの接頭辞。自動的にTeamIDが割り当てられる。

- **App ID Suffix:**
App IDの接尾辞。Explicit App ID と Wildcard App ID が選択可能。特別な理由がない限りExplicit App ID が推奨される。

- **App Services:**
当該アプリに組み込むもしくは組み込む予定のサービスにチェックを入れる。開発前で選択困難の場合は後回しで問題ない（App ID作成後に編集可能）

### Explicit App ID
プロジェクトファイルのBundle Identifierと完全一致した文字列を入力
**Bundle IDはXcodeプロジェクトファイルのBundle Identifierと一致させる必要がある**。

例えばここで作成したApp IDが xxxxx.jp.domainname.appname の場合はBundle Identifierはjp.domainname.appname でなければならない。

**push通知やCloudKitなどの特有の機能が使える**

### Wildcard App ID
例えば「jp.domainname.\*」のように入力した場合は、ここで生成されるAppIDは、xxxxx.jp.domainname.\* となり、Bundle Identifier の左側（逆ドメイン）が一致していれば右側（プロジェクト名）がどのような名称でも構わない。

#### メリット:
たとえば、Xcodeのプロジェクトで、すべてのデバイスをサポートしていてXcodeで

- jp.domainname.app-ios
- jp.domainname.app-tv
- jp.domainname.app-watch
- jp.domainname.app-mac

のように4つのプロジェクトが存在している時に、ワイルドカードの「jp.domainname.\*」を利用すると作成するAppIDは一つで済む。

#### デメリット:
**以下の機能が全て使えない！**

![qa1713_xcodeCapabilities2.png](https://qiita-image-store.s3.amazonaws.com/0/114709/046ffdd5-1a19-603a-98d4-66ba52087d68.png)


参考:
[【2016年最新版】わかりやすく徹底解説！AppIDを登録する手順](http://unitynightowlgames.hatenablog.com/entry/2016/10/02/221903)

[Technical Q&A QA1713
When should I use a wildcard App ID?](https://developer.apple.com/library/content/qa/qa1713/_index.html)

## デバイス管理
- デバイス名
- UDID

を登録すれば、デバイス登録完了。
実機検証するのに、ここで登録したデバイスでないと実行できない。

UDIDはitunesから確認できる。ググるとたくさん出てくる。

# アカウント関連のあれこれ
## 法人用と個人用アカウントの違い
エンタープライズ版は企業が持つでかいアカウントのことだと思っていたが、下の表を見るとIn-HouseとAppStoreの欄が異なっていることが分かる。これは、エンタープライズが社内アプリ用で、スタンダードがAppStore公開用のアカウントであるということ。

| できること       |       スタンダード  |    エンタープライズ    |
|:-----------------|:------------------:|:------------------:|
| 実機デバッグ(開発用配布)              |              ◯ |        ◯        |
| Ad Hoc(評価用配布)           |            ◯|       ◯       |
| In-House(組織内配布)             |             **<font color="OrangeRed"> ☓ </font>**  |        ◯        |
| AppStore(一般公開)               |                ◯ |         **<font color="OrangeRed"> ☓ </font>**         |
| 対象             |             個人・法人 |       法人       |
|金額          |          11,800円/年 |      37,800円/年       |

## メンバーの権限
[プログラムにおける役割とiTunes Connectにおける役割](https://developer.apple.com/jp/support/roles/)に書いてあった。

権限は3種類あり、上から順番に権限レベルが高い。

- **Team Agent:**
登録者(契約者)本人で、チームに唯一の存在

- **Admin:**
契約関連の作業以外の全てを扱うことができる

- **Member:**
開発に必要な最低限の作業のみを許されている

## 権限のリスト
下のリストを見ると、**Admin**の権限レベルがかなり高い。
権限の扱いを企業レベルで考えると、

- **Team Agent:**
iOS統括の責任者、社内インフラ担当など

- **Admin:** 
プロジェクトごとのリードiOSエンジニア

- **Member:**
プロジェクトの他のiOSエンジニア

のような権限活用になるだろうか。

※Xcode7からMemberの権限が一部緩くなっている。
※AppleのページではXcode7以上かどうかで場合分けしているが、Xcode9時代なので無視して可能か不可能かの二分類で表記する。

| 権限一覧       |       Team Agent   |   Admin    | Member |
|:-------|:---------:|:---------:|:------:|
| 法的な契約の締結     |        ◯ |    ☓    | ☓| 
|メンバーシップの更新     |       ◯ |   ☓       | ☓ |
| Developer ID 証明書の作成 |    ◯  |    ☓  | ☓ |
| メンバーの招待と役割の割り当て   |    ◯ |       ◯  | ☓ |
| Provisioning Profileの作成  |    ◯ |   ◯  | ◯ |
| 証明書署名リクエストの承認  |    ◯ |  ◯ | ☓ |
| 開発用証明書の作成と削除| ◯  | ◯  | ◯  |
| UDID の追加と無効化| ◯| ◯  | ◯  |
| App ID の登録、設定| ◯| ◯ | ◯  |
| App ID　の削除| ◯|◯ | ☓|
| iOS配布用証明書と配布用Provisioning Profileの作成| ◯| ◯ |☓ |
| APNS証明書とPass Type IDの作成| ◯| ◯ | ☓|
| Mac App / Mac Installer配布証明書の作成|◯ | ◯ | ☓|
| Technical Support Incident の購入と送信 | ◯| ◯ | ◯  |
| Developer Forums への投稿|◯ | ◯ | ◯  |
| プレリリース版ソフトウェアのDL| ◯| ◯ | ◯  |
|Provisioning ProfileのDL | ◯| ◯ | ◯  |
| 証明書署名リクエスト(CSR)の送信|◯ | ◯ | ◯  |
| Safari 拡張機能証明書の作成| ◯| ◯ | ◯  |
| Safari Extensions GalleryへのSafari拡張機能の提出| ◯| ◯ | ◯  |

# Signing
上記以降、色々と説明したが、Xcode8からはSigningという機能がある。

**簡単に説明すると、CSRの作成以降はXcode上で自動で証明書設定やプロファイル設定が出来るようになっている (ただし、Development証明書のみ)**

## Signing Certificate per Mac
> Signing Certificate per Macは、「開発用p12ファイルを開発マシン間でやり取りする」、という複数台のPCで開発を行う際の問題に対する解決策として、Signing Certificate per Macという仕組みを導入した、という話でした。

>Signing Certificate per Macは、Debugビルド用の証明書については個々のMacで別個に作成して使えるようにしよう、というもので要点としては以下の通りです。
- Debugビルドonly
- XcodeとiOS Dev Centerの双方で生成できる
- Xcode8移行から生成可能
- Xcode7以前でも使用可能

## Signing in Xcode
> - SigningがBuild SettingsからGeneralタブに移動
- Automatic SigningとCustomized Signingという仕組みを導入
- Automatic Signingでは、Capabilitiesに変更を加えた場合などに、自動的にProvisioning Profileが更新される
- Customized Signingは今までのApp Signingと同じ。
- Provisioning Profileのエラーでは、fix issueのみではなく、説明的なエラーメッセージを表示するように
- Automatic SigningでのProvisioning Profileのステータス変更について、Report Navigatorペインで表示されるように。
- Provisioning Profileの更新に伴うProvisioning Profileの選択が不要に

## Best Practices

> 最後のBest Practicesは、Xcode8からのワークフローに対応して、以下のように開発を進めよう、というものでした。

> - 開発時には、Automatic Signingを使おう
- GeneralタブのSigningとCapabilitiesタブで全てを管理しよう
- Customized Signingを使う場合にも、CODE_SIGNING_IDENTITYをデフォルトのままにしておこう(Signing Certificate per Macのため)
**Automatically manage signing**をオンにして、GeneralやCapabilitiesからボタンを押したりスライダーをオンにするだけで、これらの設定が可能になる。プロファイルや証明書のダウンロードも不要。

Appleは、この機能の利用を推奨している。

参考:
[[iOS 10] Xcode 8 の新しい Signing 機能について](https://dev.classmethod.jp/smartphone/xcode-8-signing/)

[What's New in Xcode App Signingまとめ](https://qiita.com/nerd0geek1/items/0b36c68897ee87e0a0c6)

# 感想
開発時にはSigningの機能にまかせっきりで大丈夫そうでしたが、リリース時に「全く分からない！」とならないように、証明書やアカウントの知識は頭に叩き込んでおいた方が良いと思いました。

また、「リリースしよう！ビルドできない！調べなきゃ！作らなきゃ！修正しなきゃ！」となってくると、**焦りで本来するはずのないリスクのある操作をしてしまったりする**ため、こういうドキドキを減らすためにもしっかり覚えておこうと思います。

# P.S
2020年時点で、最終的に筆者のアプローチは「開発もプロダクション用もAutomatic Signingに任せる」となりました。Xcodeでarchive→validate→Automatically manage signing」と進むと

> Xcode will create and update profiles, app IDs, and certificates

と記載されており、証明書関連の知識は、受託開発などで細かいコントロールが必要でmanual signingするしかない場合以外ではXcodeに任せ切ることができるようになっています。

証明書関連は複雑かつ面倒で、かつ年に触る回数も少なく忘れやすく、忘れるたびに調べ直して対応する(そしてその時に前の担当者が辞めているプロジェクトなどあり、鍵の引き渡し失敗で作り直したり面倒のループに...)大変な経験を何度も繰り返しており、可能な限りXcodeに任せる方針としました。

なので、運用は基本的には以下のようなものです。

1. CSRは手動で作成する。
2. DevelopmentとDistributionの2つを作成して証明書をインストールする。(必要に応じてそのほかも)
3. あとはXcodeのAutomatic Signingにおまかせ
4. BitriseなどのCIサービスを使うときも、その2つのp12ファイルだけをアップロードし、「iOS Auto Provision with App Store Connect API」のようなステップを利用する。

「archive→validate→Automatically manage signing」を最初に実行した時点で各種必要なものがAppleDeveloperに生成されているので、それ以降AppStoreConnectでAppを作成する時にidを参照できるようになります。リリースするつもりのプロジェクトを作成したら、最初にvalidateを実行するぐらいでも良いと考えています。