Firebase Cloud Messaging による通知をバックグラウンドでも受け取る

Swift version 5.0.1
iOS11

Firebase Cloud Messaging でアプリがバックグラウンドでも通知を受け取る方法について。
APNs ペイロードcontent-available: 1を含める必要あり。
これが含まれることでアプリがバックグラウンドであっても
application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
メソッドが呼ばれるようになる。またフォアグラウンドでも同様に呼ばれる。
この引数のクロージャであるfetchCompletionHandlerはメソッドの開始から 30 秒以内に実行する必要がある。

Xcode 設定

Xcode

  • Capabilities -> Background Modes -> Remote notifications
  • Capabilities -> Push Notifications

にチェックを入れる。

f:id:xyk:20190830161336p:plain f:id:xyk:20190830161205p:plain

FCM Token 取得コード

import Firebase

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        FirebaseApp.configure()
        Messaging.messaging().delegate = self
        return true
    }
}

extension AppDelegate: MessagingDelegate {
    // FCMトークン取得
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
        print("Firebase registration token: \(fcmToken)")
    }
}

通知受信時のハンドリング

// AppDelegate
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        if let foo = userInfo["foo"] as? String {
            print("foo: \(foo)") // -> bar
        }
        completionHandler(.newData)
    }

cURL で疎通確認

$ curl --header "Content-Type: application/json" \
--header "Authorization: key={サーバーキー}" \
https://fcm.googleapis.com/fcm/send \
-d '{"notification": {"body": "Hello from curl via FCM!", "sound": "default"},
"priority": "high",
"content_available": true,
"data" {
  "foo": "bar"
},
"to": "{FCMトークン}"}'

サーバーキーは FIrebase 管理画面から取得、FCMトークンは上記 Delegate で取得したトークン。

f:id:xyk:20190829154049p:plain

content_available パラメータは必須。

Firebase Cloud Messaging の HTTP プロトコル

iOS では、このフィールドを使用して APNs ペイロードで content-available を表します。通知やメッセージの送信時にこのフィールドが true に設定されている場合、非アクティブなクライアント アプリのスリープ状態が解除されます。また、メッセージは FCM 接続サーバーではなく APNs を介して、サイレント通知として送信されます。APNs のサイレント通知の配信は保証されておらず、ユーザーが [低電力モード] をオンにする、アプリを強制終了するなどの要因によって結果が異なる場合があることに注意してください。

data パラメータにはカスタムのデータを入れられる。


サイレント通知について

content-available キーが 1 で、かつ alert.bodysoundbadge の各キーを除外することでサイレント通知となる。
サイレント通知を受信すると、通知センターは表示されず application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
が呼び出される。
通知センターは表示しないのでユーザに通知許諾を得ずとも使用可能。

cURLでサイレント通知

$ curl --header "Content-Type: application/json" \
--header "Authorization: key={サーバーキー}" \
https://fcm.googleapis.com/fcm/send \
-d '{
"priority": "high",
"content_available": true,
"data" {
  "foo": "bar"
},
"to": "{FCMトークン}"}'

参考:
Google Developers Japan: iOS で Firebase Cloud Messaging をデバッグする
https://developers-jp.googleblog.com/2017/02/debugging-firebase-cloud-messaging-on.html
プッシュメッセージのカスタマイズ
https://docs.kii.com/ja/guides/cloudsdk/ios/managing-push-notification/push-techinology/message-customize/