💨
【FCM】Cloud functionsでfirestoreにメッセージ追加時プッシュ通知
はじめに
こんにちは
今回はFirestoreにデータ追加時、Functionsを使ってプッシュ通知をする機能の実装方法を簡潔に紹介します
準備
- firebase-cli
- プロジェクト
Firestoreの構造
今回は例としてこのようなデータ構造だとします。
イメージとしてはメッセージの変更を検知したら、対象Roomのユーザートークンを取得し、プッシュ通知を行う感じです
rooms:
messages:
createdAt: timestamp
body: String
users:
fcmToken: String
実装方法
まずプロジェクト直下でfirebase init
をします
firebase init functions
実行したら色々聞かれると思うので、ご自分の環境に合わせて選択してください。
Typescriptを選択すると初期状態からエラーが発生していたので、今回はJSを選択しております。
完了したらプロジェクト直下にfunctionsディレクトリーが出来上がっているので、その中のindex.jsを修正していきます。
まず、必要なモジュールなどを定義します
const functions = require("firebase-functions");
const admin = require("firebase-admin")
const db = admin.firestore()
admin.initializeApp()
メッセージの変更を検知したいので、
exports.messagePushNotify = functions.firestore.document("rooms/{roomId}/messages/{messageId}")
.onCreate(async (snap, context) => {
このように書きます。
次にプッシュ通知を行う内容を定義します。
メッセージの内容はfirestoreのmessagesから新しく追加されたメッセージの内容をとってきます。
snap.data().body
の形で今回の場合は取得できますので、
const payload = {
notification: {
title: "アプリ名など",
body: snap.data().body,
}
}
このような形になります。
次に配信先のFCM tokenを取得します。
まずはUsersまでのPathを定義し、データを持ってきます
const roomId = context.params.roomId
const usersRef = db.collection('rooms').doc(roomId).collection('users')
const snapshot = await usersRef.get()
if (snapshot.empty) {
console.log('No matching user')
return
}
今回はドキュメントパスにワイルドカードパターンを使用しているので、このような形で対象RoomIDが取得できます。
// functions.firestore.document("rooms/{roomId}/messages/{messageId}")
const roomId = context.params.roomId
最後にトークンを取得し、対象ユーザーへプッシュ通知の処理を入れれば終了です
snapshot.forEach(doc => {
// push notify
const token = doc.data()['fcmToken']
admin.messaging().sendToDevice(token, payload)
})
全体のソースコード
const functions = require("firebase-functions");
const admin = require("firebase-admin")
const db = admin.firestore()
admin.initializeApp()
// Cloud Firestore trigger
exports.messagePushNotify = functions.firestore.document("rooms/{roomId}/messages/{messageId}")
.onCreate(async (snap, context) => {
// Get roomId from params
const roomId = context.params.roomId
const title = "アプリ名"
const message = snap.data().body
// Notification Details
const payload = {
notification: {
title: title,
body: message,
}
}
// Get the list of device notification tokens.
const usersRef = db.collection('rooms').doc(roomId).collection('users')
const snapshot = await usersRef.get()
if (snapshot.empty) {
console.log('No matching user')
return
}
snapshot.forEach(doc => {
// push notify
const token = doc.data()['fcmToken']
admin.messaging().sendToDevice(token, payload)
})
})
参考
Discussion