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

Firebase Cloud Messagingを使うと手軽にPUSH通知が送れます。
その際にこのように画像をつけることもできます。
![IMG_3414.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6678/98fa0bd1-dd76-9827-f5bd-a0cd603f22cf.jpeg)

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

実装方法に関する [公式ドキュメント](https://firebase.google.com/docs/cloud-messaging/ios/send-image?hl=ja) もありますが
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](https://dev.classmethod.jp/articles/user-notifications-framework-13/)

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

## 実装

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

[公式ドキュメント](https://firebase.google.com/docs/cloud-messaging/ios/send-image?hl=ja) を元に実装します。

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

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

これをSwiftに直すと...

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

となります。

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

```swift
//
//  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を記載します。

```ruby
# 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通知を送ることで確認します。

![CleanShot 2020-11-07 at 14.45.20@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6678/32604c1e-f4b0-1ae7-e7b3-5fb4b9f371d4.png)