iOSでプッシュ通知を実装する(PHP,Swift3)

https://akira-watson.com/iphone/push-notification_1.html が比較的わかりやすい(けど若干情報が古い)
色々調べたけどFirebase使った方がいいんじゃ?という結論になりました。
画像が多いので注意

追記
Firebase を使用してiOSのPush通知を実装する








Apple Push Notificationサービスとは


Appleが提供している通知サービスのこと(直訳)
大まかな概要としては
iOSよりPush通知の許可を行い、APNsからデバイストークンを取得する
→ 取得したデバイストークンを何らかの方法で保持する(サーバDBなど)
→ 開発者が何れかの手段でAPNsへ通知依頼(デバイストークン使用)
→ APNsからデバイストークンに対応した端末へ通知が送られる
→ 受け取った通知によって処理を行う


証明書をサーバに配置する必要あり

サーバの実装が意外と面倒なので、言語に対応するソースを取ってくる
php なら ApnsPHP
https://github.com/immobiliare/ApnsPHP


環境
OS:Mac Sierra


IDE:Xcode 8.0 → 8.1
言語:Swift3
サーバサイド:PHP




取り扱うファイル・用語一覧


いっぱいありすぎて混乱するので事前にまとめておく

Apple Dev Center

https://developer.apple.com/ のこと。
メンバセンター、iOS Dev Centerなどとも呼ばれています。
正式名称がわからなかったので以降はApple Dev Centerで統一します。


CertificateSigningRequest.certSigningRequest

以降CSRと記述、直訳すると証明書署名要求
その名の通りApple Dev Center へ証明書を要求するのに使用する(アップロードして使う)。
それ以外では使用しない。
キーチェーンアクセスからPCのCSRを作成する。

aps_development.cer

通知サービスのSSL証明書
Apple Dev Center より作成するApp ID
Push Notifications を有効化した後、上記のCSRをアップロードして取得する(開発用と本番用で分かれている)
App ID毎に固有(再作成可能)
キーチェーンに登録して使用する

aps_development.p12

.pem形式に変換するためにはaps_development.cerをキーチェーンに登録して、一度.p12形式として書き出す必要がある。APNsPHPを使用する場合は証明書と秘密鍵の2つを書き出す必要がある。

aps_development.pem

aps_development.cerから変換する。
サーバに配置して使用する。
通常は証明書のみでいいが、APNsPHPを使用する場合証明書と、秘密鍵が必要。
プッシュ通知を実現するのに最低限必要な情報はこれとデバイストークンの模様。

Provisioning profile

公開時に必須だがプッシュ通知を実装するためには開発時から取得しておく必要がある。
最近はある程度自動でやってくれる部分もあるので多少楽(むしろわかりにくくなった?)


entrust_2048_ca.cer

Entrust のルート証明書
APNsPHP の実装に必要でAPNs自体に必要ということでは無いような気がする。
https://www.entrust.com/root-certificates/entrust_2048_ca.cer
以前は開発用・製品用で分かれていたが統合された。

entrust_2048_ca.pem

ルート証明書を変換したもの
サーバに配置して使用する。
最終的にaps_development.pem とentrust_2048_ca.pemの2つをサーバへ配置することになる(名前はなんでもいい)

以上を踏まえて解説していきます。




CSRを作成する


1_1. Mac からキーチェーンアクセス起動
1_2. メニュー(キーチェーンアクセス) → 環境設定
1_3. 証明書タブから オンライン証明書状況プロトコル → 切
証明書失行リスト → 切
CSR
なぜこれをやるのかと終わった後戻していいのか戻すべきなのかがちょっと分からなかった

1_4. メニュー(キーチェーンアクセス) → 証明書アシスタント → 認証局に証明書を要求...

1_5. 証明書アシスタントが起動するのでユーザのメールアドレスに開発者として登録したアドレス、通称はなんでもいい、CAのメールアドレスは空白、ディスクに保存を選択して、鍵ペア情報を指定にチェック → 続ける


1_6. CertificateSigningRequest.certSigningRequest を適当な場所へ保存




作成CSRをApple Dev Center へアップロードしてaps_development.pemを取得する



2_1. Apple Dev Center(https://developer.apple.com/account/ios/certificate)へアクセス(事前に開発者登録を済ませておくこと)

2_2. App IDsから+ボタンを押下
iOS App IDs

2_3. 必要事項を記入して現在作成しているアプリのApp IDを作成
App ID 作成
APP ID Description
アプリの説明。なんでもいい
App ID Suffix
Explicit App ID を選択
プロジェクトで使うBundle IDを指定(URLを逆にしたような形式がよく使われる)
App Service
Push Notifications にチェックを入れること

全て入力したらコンティニュー


2_4. App IDs から先ほど選択したApp IDを選択

2_5. 初期状態ではPush NotificationsがConfigurable(構成可能)になっているのでEditを押下して編集する。
App ID Edit

2_6. Create Certificate...を押下する。一度作成しておけばDownloadから何度でもダウンロード可能

2_7. CSRを取得する手順が表示される。Continueを押下する。
CSR 作成方法

2_8. Choose FileよりMac上で作成したCSRをアップロードする → Continue
Upload CSR File

2_9. Downloadからaps_development.cer をダウンロードする。
certificate download

2_10. ダウンロードしたaps_development.cerをダブルクリック。

2_11. Apple Development iOS Push Services: jp.co.xxxx.testAppとその直下の秘密鍵(開発者名が出ているはず)を2つ選択して右クリック → 2項目を書き出す

2_12. 名前は適当。.p12形式で書き出す
p12書き出し

2_13. パスワードは未記入。
パスワード

2_14. ターミナルからコマンド

openssl pkcs12 -in aps_development.p12 -out aps_development.pem -nodes -clcerts
で.pem形式へ変換。
作成したaps_development.pem はサーバに配置して使用する。

以降CSRを使うことはないはず(本番用で同じ手順を踏むことになる)




Provisioning Profile を作成してプロジェクトに適用する



3_1. https://developer.apple.com/account/ios/certificate へ戻る

3_2. Provisioning Profiles → All → +を押下

3_3. 開発用か本番用かなどを選択します。今回は開発用を選択
Provisioning Profile

3_4. App ID作成済みでプロファイル未作成のものが一覧で表示されるので該当するものを選択

3_5. Certificates、デバッグで使用する端末などを設定する。

3_6. XXXX.mobileprovisionがダウンロードできる

3_7. XXXX.mobileprovisionをダブルクリック(Xcode は終了しておくこと)

3_8. プロジェクト設定 → General → Signing → Automatically → manage signingにチェック

3_9. プロジェクト設定 → Capabillities → PushNotificationsをONにする
XCode Capabillities

警告が出ているところを適当にクリックすれば補足してくれる(雑)



iOS端末のデバイストークンの取得処理の記述を行う


取得自体は特別な設定をせずとも可能
AppDelegateへ以下を追記・修正する。


class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

        // プッシュ通知登録
        let apnsTypes : UIUserNotificationType = [.badge, .sound, .alert]
        let notiSettings = UIUserNotificationSettings(types: apnsTypes, categories: nil)
        application.registerUserNotificationSettings(notiSettings)
        application.registerForRemoteNotifications()

        return true
    }

    // プッシュ通知登録成功時のデバイストークン取得処理
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let tokenText = deviceToken.map { String(format: "%.2hhx", $0) }.joined()
        print("deviceToken = \(tokenText)")
    }

    // プッシュ通知登録失敗時
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Failed to get token, error: \(error)")
    }


    // 通知取得時処理
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        print(userInfo)
    }

application.registerForRemoteNotifications を呼び出した時push通知を許可するかの確認ダイアログが表示される。
通知許可時にデバイストークンが取得・表示されるのでメモしておく(サーバの実装で使う)
プッシュ通知許可画面





APNsPHPでサーバの実装を行う



Entrust のルート証明書を取得する
https://www.entrust.com/get-support/ssl-certificate-support/root-certificate-downloads/
https://www.entrust.com/root-certificates/entrust_2048_ca.cer
よりダウンロード

ターミナルよりコマンド
openssl x509 -in entrust_2048_ca.cer -inform PEM -out entrust_2048_ca.pem
で変換する。

wgetコマンドが使用できるなら
wget https://www.entrust.com/root-certificates/entrust_2048_ca.cer -O - > entrust_2048_ca.pem
が楽。ただしMacには標準で搭載されていない。

ApnsPHPを取得・実装する

https://github.com/immobiliare/ApnsPHP
よりダウンロード

ApnsPHPフォルダとsample_push.phpを使用する。
PHP実行環境は適宜用意すること。

面倒なので今回はApacheで /Library/WebServer/Documents 直下に作成する。
ApnsPHPフォルダとsample_push.phpを/Library/WebServer/Documentsへ配置する。
同階層にaps_development.pemを配置する。
同階層にentrust_2048_ca.pemを配置する。

sample_push.php を3箇所編集する

//30行目あたりaps_development.pemを設定する。

// apple dev center より取得したファイル 
$push = new ApnsPHP_Push(
ApnsPHP_Abstract::ENVIRONMENT_SANDBOX, // 開発用 
    // ApnsPHP_Abstract::ENVIROMENT_PRODUCTION, // 本番用 
    'dev_push.pem'
);
// 開発用と本番用で第一引数が違うので注意すること

// 40行目あたりentrustのルート証明書を設定する
// Set the Root Certificate Autority to verify the Apple remote peer
// https://www.entrust.com/root-certificates/entrust_2048_ca.cer 
// より取得変換したファイル 
$push->setRootCertificationAuthority('entrust_2048_ca.pem');

// 上記のすぐ下デバイストークンを設定する。
// Instantiate a new Message with a single recipient
$message = new ApnsPHP_Message('2bb220032a263cxxxxxxxxxxxxxxxxx1628aaf181d293d40aaa4eb76f87c');


http://localhost/sample_push.php へアクセスするとプッシュ通知が送付される
APNsPHP Sample



メモ


うまくいかないときはApnsPHPのCertificateCreationを読んでみる。
https://github.com/immobiliare/ApnsPHP/blob/master/Doc/CertificateCreation.md
App IDやプロファイル作成時にきちんと説明が(英語で!!)書かれているのでよく読んでみる。
上記と同様の環境であれば上記の手順は全て必要なので一からやり直した方が多分早い。

APNsサーバへ接続と切断を繰り返すとDos認定を受けるので基本接続しっぱなし
1日1回程度であれば問題ない
当然ながらデバイストークンの登録処理が必要になる。
確認した限りではデバイストークンはアプリごとに固有で再インストールごとに変更されていた。
証明書関連は全て同じPCで行うこと。
詳細な処理に関しては今回は割愛。



mbaasなどがあるので使えるならそっちの方が楽
iOSアプリ作るならAndroidアプリも作ることになるだろうしFirebaseオススメ


2016年11月5日土曜日