怠慢プログラマーの備忘録

怠慢でナマケモノなプログラマーの備忘録です。

Firestoreの特定のCollectionをCloudFunctionsで監視してPushNotificationを送信する[備忘録]

チャットアプリなどでFirestoreの特定のCollectionが変更された際に対象ユーザーにPushNotificationを送信するといったシーンの実装方法の備忘録です。

Firebase

CloudMessagingがPushNotificationを送信する際に必要になるfcmTokenはFirestoreに保存しておきます。 アプリ側でfcmTokenを取得する際のコードは下記になります。

Sample.swift

InstanceID.instanceID().instanceID { [weak self] (result, error) in
          if let error = error {
            print("Error fetching remote instance ID: \(error)")
          } else if let result = result {
            result.token
          }
}

大まかな流れとしては、

①fcmTokenをアプリ側からFirestoreへ登録する

②CloudFunctionsにFirestoreのCollectionをトリガーとしたfunctionを記載

③function内でPushNotificationの送信先のfcmTokenを特定して送信

CloudFunctionsに記載するfunctionは以下の通りです。

index.js

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const serviceAccount = require('./config.json');
const auth = admin.auth();
const firestore = admin.firestore();
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://{dbURL}.firebaseio.com"
});

/* Observe 'Rooms' and send push notifications when changes occur */ 
exports.sendPushNotification = functions.firestore.document('rooms/{roomId}').onWrite(async (change, context) => {
  try {
    // 最新のTalkを取得
    const newVal = change.after.data();
    const date = newVal.update_date;
    const talksQuery = await firestore.collection('talks').where('date', '==', date).get();
    talksQuery.forEach(async doc => {

      // 対象ユーザーのfcmToken取得
      const userId = doc.get('user_id');
      const infoQuery = await firestore.collection('user_info').where('user_id', '==', userId).get();

      if (infoQuery.size != 0) {
        infoQuery.forEach(doc => {
          const token = doc.get('fcm_token');
  
          // 通知用payload
          const payload = {
              notification: {
                title: "新着メッセージ",
                body: "チャットに新着メッセージがあります",
                badge: "1",
                sound: "default",
              }
          };
          _pushToDevice(token, payload);
        });
      }
    });
  } catch(e) {
    console.error(e)
  }
});

function _pushToDevice(token, payload){
  const options = {
    priority: "high",
  };
  admin.messaging().sendToDevice(token, payload, options)
  .then(pushResponse => {
    console.log("Successfully sent message:", pushResponse);
  })
  .catch(error => {
    console.log("Error sending message:", error);
  });
}