iOSプッシュ通知（社内勉強会用）

# iOSプッシュ通知の復習

iOS Remote notification の provisioning profile, build configuration 周りの設定について、改めて復習したいと思います

---

# 設定

![remote_notif_simple_2x.png](https://qiita-image-store.s3.amazonaws.com/0/107584/cec0b724-db12-05be-a132-0f802a4531ef.png)
[画像出典](https://developer.apple.com/jp/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/ApplePushService.html)

Dev Centerでの設定と、 Provider, Client Appの実装を行う

---

# Client App

- Bundle ID (CFBundleIdentifier)
- APNs entitlements (aps-environment)
- Background mode (UIBackgroundModes)
    -  Background Fetch を使うなら remote-notification を追加
- Application実装
    - デバイストークンの取得
    - Remote Notificationのハンドル

[Appleのプログラミングガイド](https://developer.apple.com/jp/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/HandlingRemoteNotifications.html) に従って Xcode から操作すれば、ほぼ問題なし。

ハマリポイント

- Debug/Releaseビルドでentitlementsを切り替える: http://qiita.com/Takumi_Mori/items/11b8d00f73163d890b24
- 通知のハンドルはDeprecated delegate method も実装する: http://qiita.com/komitake/items/c9fbc6aecad404e71e5d

---

# Dev Center

- Certificate (iOS Distribution, iOS Development)
    - Remote Notification特有の話ではない
    - ビルドを行うマシンに Certificate と Private key の両方が必要
    - 当社内では、Admin権限を持った人がXcodeから無為に証明書revokeしてしまう事故が頻発した時期がある
- App ID
    - Remote Notificationを使うためには、Explicit App IDである必要がある
    - Push Notifications を enabled にする
- Apple Push Services の Certificate (Sandbox or/and Production)
    - App ID に紐づく
    - Sandbox/Production の違いについては後述
    - この証明書を使って、AppleのAPNsサーバとnegotiateに使う
    - 新しいHTTP/2ベースのAPNs Provider APIを使う場合は、Certificate ではなく Key-Pair を使う（らしい。使ったことない）

ハマリポイント

- Development/Distribution Envそれぞれで、 Push Notifications を enabled にできるのは、Globalに1つのみ（後述）

---
# Provider
- 生成した APNs Certificate をサーバに配置
- それを使って、プッシュ通知を行う

---

以上の設定をした上で、プッシュ通知の動作確認をするためには、Build Configuration や Environment毎に適切な組み合わせが必要となるのが、ややこしい。

---
# Developer Program
- Standard Program
    - AppStoreに配信できるのはこっち
- Enterprise Program
    - 企業内ユーザ（不特定多数）にAppStore以外から配布できるのはこっち

当社は、どちらも持ってます

---
# Provisioning Profile
- Development
    - 通常の開発時に使う
- Distribution
    - 配布用にパッケージングする時に使う
    - App Store, Ad Hoc, In House の3種類がある

| Distribution profile | 用途 | 端末制限 |
|:-----------------|:------------------|:------------------:|
| App Store        | AppStore, TestFlight配信| なし（TestFlightとしての制限はある） |
| Ad Hoc           | 社内テスト等 | Dev Centerで個別に登録（100端末まで） |
| In House         | 社内テスト、社内利用等 | なし |

---
# APN環境
- Development
    - 開発環境
    - sandbox環境とも呼ばれていた
- Production
    - 実稼働環境

環境毎にホスト名が違う。

（古いAPNsエンドポイントだと）Dev/Prodで使用するSSL証明書が異なる。

---

# テスト環境（TestFlight)

iTunes Connectから（つまりApp Store公開用のバイナリを/環境で）、テスト配信する。
端末にTestFlightアプリをインストールすることで、AppStoreを経由せずにアプリをインストールする。

- Internal Test
    - iTunes Connect ユーザであること
    - 25人まで
    - 上記の制限から、テスターさんは登録しづらい
- External Test
    - TestFlightアプリユーザなら誰でも招待できる

---

# 整理

|プロビジョニング|ビルド|APN環境|プログラム|テスト配布|
|:------|:------|:------|:------|:------|
|Development|Debug|Development|Standard, Enterprise|開発用途のみ USBデバッグ等|
|Ad Hoc|Release|Production|Standard, Enterprise|Dev Centerで指定した端末のみ OTA等で配布|
|In House|Release|Production|Enterprise|制限なし OTA等で配布|
|App Store|Release|Production|Standard|AppStore, TestFlight|

どれを使うか決めるときに気をつけること

- 同じビルドで同じBundleIDのアプリは、複数のプロビで同時にプッシュ通知を受けることは出来ない
    - AppStore版とAdHoc版は別BundleIDにする
- APN環境が混在すると、Provider（アプリケーションサーバ）はSSL証明書を使い分ける必要が出てくる

---

# おすすめの構成

- 開発開始時はDevelopment
    - ただし、アプリケーションサーバのProd環境には接続しない
    - APN環境（デバイストークンや使うべきSSL証明書など）の混在を防ぐため
    - 事故を防ぐためにAPN有効なプロビは、サービスイン後は無効にしておいたほうがよい？
- 社内テストはIn House
    - AppStoreとBundleIDを変える
    - テスターさんや端末の増減にいちいち対応しなくて良い、営業さんやパートナーにも配布しやすい
    - 受託案件では顧客のEnterpriseプログラムアカウントを借用するとよい
- リリース前には必ずTestFlight
    - AppStoreと同じ環境で試験ができる
    - 受託案件では顧客のStandardプログラムでTestFlightを使うよう調整し、リリース前試験する