2017年6月12日月曜日

Firebase で iOS にプッシュ通知を送信してみた

概要

プッシュ通知を Firebase に移行してみたので設定や流れをメモしておきます
ある程度端折っいる流れもあるのでその点はあしからず
基本は公式ドキュメントを見ることをおすすめします

環境

  • macOS 10.12.5
  • Xcode 8.3.2 (8E2002)
  • Firebase (2017/6/9 時点)
  • プッシュ対象端末 iPhone5 iOS 10.3.2

流れ

AppID にプッシュ通知用の証明書を登録する

作成するときは AppID の一覧から作成することをおすすめします
iOS Certificates にログインして

Identifiers -> App IDs -> 対象の AppID を選択 -> Edit

で編集画面に移動し「Push Notifications」の欄をチェックオンにします
そしてそこから「Create Certificate」でプッシュ通知用の証明書を作成します
作成には CSR が必要になるので事前に作成します
Development, Production 用の証明書の 2 つが作成できれば OK です
firebase_push1.png

作成したプッシュ通知用の証明書から p12 ファイルを書き出す

先ほどの画面から証明書を「Download」できるので Mac 上にダウンロードします
そして、ダブルクリックしてキーチェーンアクセスで開いて p12 ファイルを書き出しましょう
firebase_push3.png

パスワードはなしで書き出しました
後から気づいたのですが、Firebase は p12 ファイルのパスワードも設定できるのでパスワードはありでも大丈夫だと思います

p12 ファイルを Firebase に登録する

Firebase のコンソールにログインしましょう

プロジェクトの設定 -> クラウドメッセージング -> 対象のアプリを選択 -> APNs 証明書

を選択します
同じような項目で「APNs 認証キー」という項目がありますが、そっちじゃないので注意してください
firebase_push4.png

「開発用 APNs 証明書」「本番環境の APNs 証明書」という 2 つの欄があるので書き出した p12 ファイルをそれぞれアップロードしてください
ちゃんと Development 用の証明書から書き出した p12 ファイルは「開発用の APNs 証明書」Production 用の証明書から書き出し p12 ファイルは「本番環境の APNs 証明書」に設定しましょう
当然ですが、間違えるとプッシュ通知が送信されません

アプリ側修正

これで Firebase 側の設定は完了です
アプリ側の修正をしていきましょう

ライブラリのインストールは Cocoapods を使います

pod 'Firebase/Messaging'

プロジェクトのプッシュ通知を有効にします
プロジェクトを選択した状態で Capabilities を選択し「Push Notifications」を ON にします
firebase_push2.png

あとは AppDelete.swift を編集します
今回は Swift3 の文法を使っています
Swift2 だと若干コールするメソッドが違うので気をつけてください
全部紹介すると長いのでポイントを紹介します

import UserNotifications

を import しましょう

// Firebase の初期化
FIRApp.configure()
// プッシュ通知の許可を表示する
if #available(iOS 10.0, *) {
    let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
    UNUserNotificationCenter.current().requestAuthorization(
        options: authOptions,
        completionHandler: {_, _ in })
    // For iOS 10 display notification (sent via APNS)
    UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
    // For iOS 10 data message (sent via FCM)
    FIRMessaging.messaging().remoteMessageDelegate = self as? FIRMessagingDelegate
} else {
    let settings: UIUserNotificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
    application.registerUserNotificationSettings(settings)
}
application.registerForRemoteNotifications()

didFinishLaunchingWithOptions に追加します
これでアプリの初回起動時にプッシュ通知を許可するかどうかのダイアログが出るようになり、許可を押した人にプッシュ通知できるようになります

// メッセージ受信時の処理
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
    print(userInfo)
}

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                 fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    print(userInfo)
    completionHandler(UIBackgroundFetchResult.newData)
}

メッセージを受信したときの処理です
メッセージをカスタマイズしていて何か特別な処理をしたいときはここにロジックを記載します

動作確認

これで OK なはずです
あとは Firebase の Notifications からメッセージを作成して送信すればメッセージが届くはずです

当然ですが実機でないと届きません
なので、Mac に iPhone を接続して Firebase 対応したアプリをビルドしてインストールしてください
アプリ起動時にプッシュ通知の許可拒否のダイアログが表示されるのでそこでも必ず許可を選択してください

最後に

Firebase を使って iOS にプッシュ通知を送信してみました
自分が一番ハマったのは証明書の部分で始め Production 用の証明書と p12 ファイルしか登録しないでやっていたら全然プッシュ通知が届かなく、Development 用の証明書も作成したら届くようになりました

あとはコードの部分ですが、今回のコードは公式のドキュメントに記載されていることとほぼ同様です
でも「firebase ios push」あたりでググると公式ドキュメントが一番最初に出てきません
引っかかった記事のサンプルコードを使っていたのですが、単純にプッシュ通知したいだけなのに setAPNSToken を使っていたりしてうまく動作しませんでした
単純にプッシュ通知を受け取りたいだけなら上記のコードだけで十分だと思います
それ以外にもアプリがアクティブになった場合のプッシュ通知の処理や、通知の開封状況などを解析するためのコードがありますが単純にプッシュ通知したい場合であれば不要です

あともう一点良くわからなかったのは Firebase ではプッシュ通知を送信するときに単一の端末にだけ送信する機能があります
そのときに「FCM 登録トークン」というものを使うのですが、これが Firebase 上のどこで確認できるかさっぱりわかりませんでした
コード上でデバッグする方法はドキュメントに載っていたのですが、コンソール上で確認する方法はわかりませんでした
たぶん、個別配信をするときは FCM 登録トークンを使わないで、トピックを使ってやれということだとは思います
FCM 登録トークンは開発者が知りたい時に直接コードにデバッグコードを埋め込んで取得しましょうというスタンスなんだと思います
それともどっかで確認できるのかもしれませんが、、

参考サイト

1 件のコメント:

  1. Firebase の 4.0 系になってから初期化するメソッドが変わっていたので注意してください

    // Firebase の初期化
    FirebaseApp.configure()
    // プッシュ通知の許可を表示する
    if #available(iOS 10.0, *) {
    let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
    UNUserNotificationCenter.current().requestAuthorization(
    options: authOptions,
    completionHandler: {_, _ in })
    // For iOS 10 display notification (sent via APNS)
    UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
    // For iOS 10 data message (sent via FCM)
    Messaging.messaging().delegate = self as? MessagingDelegate
    } else {
    let settings: UIUserNotificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
    application.registerUserNotificationSettings(settings)
    }
    application.registerForRemoteNotifications()

    返信削除