Cloud Firestore トリガー を使って、ドキュメントに変更があった際にプッシュ通知を送ってみました。
前提
- Cloud Firestoreにデバイストークンを保存する(tokensコレクションにデバイスIDをドキュメントIDにして保存する)
- Cloud Firestoreに数字を保存する(notification/badge/currentにNumberを保存する)
- 保存された数字に変更があった際に通知を送ってバッジをつける
- iOSのみ対応(Androidがバッジ非対応のため)
ソースコード
const admin = require('firebase-admin'); const functions = require('firebase-functions'); const { Expo } = require('expo-server-sdk'); admin.apps.length ? admin.app() : admin.initializeApp(); exports.onUpdateBadge = functions.firestore.document('notification/badge').onUpdate(async (change) => { const tokens = await getTokens(); const after = change.after.data(); sendPushNotifications(tokens, after.current); }); async function getTokens() { const db = admin.firestore(); const query = db.collection('tokens').where('token', '>', ''); const snapshot = await query.get(); const tokens = snapshot.docs.map((doc) => { return doc.get('token'); }); return tokens; } async function sendPushNotifications(tokens = [], badge = 0) { let expo = new Expo({ accessToken: process.env.ACCESS_TOKEN }); const messages = []; tokens.forEach((token) => { messages.push({ to: token, sound: 'default', title: '', badge, body: '' }) }); const chunks = expo.chunkPushNotifications(messages); const tickets = []; for (let chunk of chunks) { try { let ticketChunk = await expo.sendPushNotificationsAsync(chunk); tickets.push(...ticketChunk); } catch (error) { console.error(error); } } const receiptIds = []; for (let ticket of tickets) { if (ticket.id) { receiptIds.push(ticket.id); } } const receiptIdChunks = expo.chunkPushNotificationReceiptIds(receiptIds); for (let chunk of receiptIdChunks) { try { let receipts = await expo.getPushNotificationReceiptsAsync(chunk); for (let receiptId in receipts) { let { status, message, details } = receipts[receiptId]; if (status === 'ok') { continue; } else if (status === 'error') { if (details && details.error) { console.error(message); } } } } catch (error) { console.error(error); } } }
ポイント
// notification/badgeに変更があった際のコールバック exports.onUpdateBadge = functions.firestore.document('notification/badge').onUpdate(async (change) => { const tokens = await getTokens(); const after = change.after.data(); // 変更後の値を取得 sendPushNotifications(tokens, after.current); });
関数トリガーをつかって、すでに存在するドキュメントの値が変更されたときにトリガーを設定します。
sendNotificationの部分は、こちらの記事で解説しています。
blog.kimizuka.org
FirebaseのCloud Firestoreはコンソールから手動で書き換えることができるので、関数をデプロイすれば、手動で書き換えながデバッグすることができました。