Firebase Cloud Messagingで画像付きのPUSH通知を行う


Firebase Cloud Messagingを使うと手軽にPUSH通知が送れます。
その際にこのように画像をつけることもできます。

※ サンプル画像のお借り先
https://picsum.photos/

実装方法に関する 公式ドキュメント もありますが
Objective-Cで書かれていたためSwift版のサンプルコードを書いてみました。

概要

PUSH通知の送り側からは画像URLを渡してあげます。
画像本体をPUSH通知に載せるわけではありません。
※ PUSH通知に大きなデータを入れないためにそうしていそうです。

iPhoneにPUSH通知が届いてから
その中にあるURLから画像をダウンロードするようです。

この、iPhone側に届いてからという部分はNotification Service app extensionを利用します。
Notification Service app extensionはPUSH通知が届いてから加工できる機能です。
ただし、細かい処理はFirebase Cloud Messaging側が処理してくれるのであまり考えなくていいです。

Notification Service app extension

まずNotification Service app extensionについての基本を知りましょう。
こちらの記事などで概要を押さえてみましょう。

[iOS 10] Notification Service app extension を使用してリモート通知のペイロードを編集する #wwdc

Notification Service app extensionとは画像を表示するためだけの機能ではなく
PUSH通知全般を受け取ってから加工するというイメージが重要です。

実装

それでは実際に実装していきましょう。
先程の記事などを参考に NotificationService.swift を作ってください。

公式ドキュメント を元に実装します。

Firebaseとしてやっているのは次の行だけなので
次の行以外はNotificationService.swift の初期生成のコードで大丈夫です。

[[FIRMessaging extensionHelper] populateNotificationContent:self.bestAttemptContent withContentHandler:contentHandler];

これをSwiftに直すと...

Messaging.serviceExtension().populateNotificationContent(bestAttemptContent, withContentHandler: contentHandler)

となります。

最終的なコードはこのようになります。

//
//  NotificationService.swift
//  NotificationService
//
//  Created by yoneapp on 2020/11/07.
//

import UserNotifications
import Firebase

class NotificationService: UNNotificationServiceExtension {

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

        if let bestAttemptContent = bestAttemptContent {
            // Modify the notification content here...
            bestAttemptContent.title = "\(bestAttemptContent.title) [modified]"

            Messaging.serviceExtension().populateNotificationContent(bestAttemptContent, withContentHandler: contentHandler)
        }
    }

    override func serviceExtensionTimeWillExpire() {
        // Called just before the extension will be terminated by the system.
        // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }

}

Notification Service app extensionでターゲットが増えていますから
PodfileへのFirebaseライブラリの追加を忘れないようにしましょう。
次のようにスキーマ毎にpodを記載します。

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'ImagePushSample' do
  # Comment the next line if you don't want to use dynamic frameworks
  use_frameworks!

  # Pods for ImagePushSample
  pod 'Firebase/Analytics'
  pod 'Firebase/Messaging'

  target 'ImagePushSampleTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'ImagePushSampleUITests' do
    # Pods for testing
  end
end

target 'NotificationService' do
  use_frameworks!

  pod 'Firebase/Analytics'
  pod 'Firebase/Messaging'
end

動作確認

動作確認を行う際は、このようにFirebaseの管理画面から
画像URLをつけてPUSH通知を送ることで確認します。