Reputation: 1431
Currently I have an app that has a Firestore collection with To Do items at a specific time e.g 5:00pm - Go for a walk
I have created a function that once a user has specified a time, my cloud functions
can create a push notification using Firebase Cloud Messaging.
However, I want to be able to send the user that push notification at that specific time & date.
Here is my cloud functions
file
async function onCreateNotification(uid, time, text) {
const user = admin.firestore().collection('users').doc(uid).get();
// Make this function execute at a specific time
await admin.messaging().sendToDevice(
user.tokens,
{
data: {
user: JSON.stringify(user),
text: JSON.stringify(text)
}
},
{
// Required for background/quit data-only messages on iOS
contentAvailable: true,
// Required for background/quit data-only messages on Android
priority: "high"
}
).then((response) => {
// See the MessagingDevicesResponse reference documentation for
// the contents of response.
console.log('Successfully sent message:', response);
}).catch((error) => {
console.log('Error sending message:', error);
});
}
Upvotes: 1
Views: 2331
Reputation: 1431
Using Frank's answer above, I was able to successfully utilize Cloud Tasks and Firebase Cloud Messaging to implement my feature! It's got a few kinks left to work out still, but I figured someone could use this later on if need be.
I mostly based my code from the suggested article
Here's the resulting code
cloud functions
const functions = require("firebase-functions");
const admin = require('firebase-admin')
const { CloudTasksClient } = require('@google-cloud/tasks');
admin.initializeApp()
exports.createTask = functions.https.onCall(async (data, context) => {
log("Create Task")
const taskClient = new CloudTasksClient();
let { time, uid, id } = data
// Get Date from time in format mm-dd-yyyy
let entryDate = new Date(time[0], time[1], time[2], time[3], time[4],);
const date = join(entryDate, '-');
let prevEntry = await admin.firestore().doc(`/users/${uid}/${date}/${id}`).get()
let prevEntryData = await prevEntry.data()
if (prevEntryData.hasOwnProperty('expirationTask')) {
// Delete old expiration task
await taskClient.deleteTask({ name: prevEntryData.expirationTask })
}
// This works now! Now I should create a task on google tasks
const todayDate = new Date()
const expirationAtSeconds = (entryDate.getTime() - new Date().getTime()) / 1000
const project = JSON.parse(process.env.FIREBASE_CONFIG).projectId
const location = 'us-central1'
const queue = 'firestore-ttl'
const queuePath = taskClient.queuePath(project, location, queue)
const url = `https://${location}-${project}.cloudfunctions.net/firestoreTtlCallback`
const docPath = `/users/${uid}/${date}/${id}`
const payload = {
docPath,
uid,
}
const task = {
httpRequest: {
httpMethod: 'POST',
url,
body: Buffer.from(JSON.stringify(payload)).toString('base64'),
headers: {
'Content-Type': 'application/json'
},
},
scheduleTime: {
seconds: expirationAtSeconds
}
}
const [response] = await taskClient.createTask({ parent: queuePath, task })
const expirationTask = response.name;
const update = { expirationTask }
// update the entry with the expiration task name
await admin.firestore().doc(docPath).update(update)
log("Done with Create Task")
return ['Success!']
})
// Callback to send message to users
exports.firestoreTtlCallback = functions.https.onRequest(async (req, res) => {
try {
const payload = req.body;
let entry = await (await admin.firestore().doc(payload.docPath).get()).data();
let tokens = await (await admin.firestore().doc(`/users/${payload.uid}`).get()).get('tokens')
// log(entry);
// log(tokens)
await admin.messaging().sendToDevice(
tokens,
{
data: {
title: JSON.stringify('App'),
body: JSON.stringify(entry['text'])
}
},
{
contentAvailable: true,
priority: 'high'
}
).then((response) => {
log('Successfully sent message:')
log(response)
admin.firestore().doc(payload.docPath).update({ expirationTask: admin.firestore.FieldValue.delete() })
}).catch((error) => {
log('Error in sending Message')
log(error)
})
res.status(200)
} catch (err) {
log(err)
res.status(500).send(err)
}
})
Upvotes: 0
Reputation: 600006
The Firebase Cloud Messaging API delivers the messages as soon as possible after you call it. It doesn't have a way to schedule delivery for the future. So you will have to implement that yourself.
Some options:
For both of those, also see my answer here: Is there any TTL (Time To Live ) for Documents in Firebase Firestore
As another alternative:
Also see:
How can scheduled Firebase Cloud Messaging notifications be made outside of the Firebase Console?
And many more of these search results.
Upvotes: 1