Flutter Firebase Messaging:如何在指定时间向用户发送推送通知
Flutter Firebase Messaging: How to send push notifications to users at specified time
目前我有一个应用程序有一个 Firestore 集合,其中包含特定时间的待办事项,例如 5:00pm - Go for a walk
我创建了一个功能,一旦用户指定了时间,我的 cloud functions
就可以使用 Firebase 云消息传递创建推送通知。
但是,我希望能够在特定时间和日期向用户发送推送通知。
这是我的 cloud functions
文件
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);
});
}
Firebase Cloud Messaging API 会在您调用后尽快发送消息。它没有办法为未来安排交付。所以你必须自己实施。
部分选项:
- 您可以使用 scheduled Cloud Function 定期检查是否有任何消息需要传递。
- 您可以使用 Cloud Tasks 动态安排交付,而不是定期检查。
对于这两个,也可以在这里看到我的回答:
另一种选择:
- 如果消息本身不是动态的,您可以立即send a data message到设备,然后仅在通知到期时才在设备上显示。
另见:
FCM Schedule delivery date or time of push notification
How to Send and receive Scheduled notifications FCM Flutter
还有更多 search results。
使用上面 Frank 的回答,我能够成功地利用 Cloud Tasks 和 Firebase Cloud Messaging 来实现我的功能!它还有一些问题需要解决,但我想如果需要的话,以后有人可以使用它。
我的代码主要基于 suggested article
这是生成的代码
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)
}
})
目前我有一个应用程序有一个 Firestore 集合,其中包含特定时间的待办事项,例如 5:00pm - Go for a walk
我创建了一个功能,一旦用户指定了时间,我的 cloud functions
就可以使用 Firebase 云消息传递创建推送通知。
但是,我希望能够在特定时间和日期向用户发送推送通知。
这是我的 cloud functions
文件
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);
});
}
Firebase Cloud Messaging API 会在您调用后尽快发送消息。它没有办法为未来安排交付。所以你必须自己实施。
部分选项:
- 您可以使用 scheduled Cloud Function 定期检查是否有任何消息需要传递。
- 您可以使用 Cloud Tasks 动态安排交付,而不是定期检查。
对于这两个,也可以在这里看到我的回答:
另一种选择:
- 如果消息本身不是动态的,您可以立即send a data message到设备,然后仅在通知到期时才在设备上显示。
另见:
FCM Schedule delivery date or time of push notification
How to Send and receive Scheduled notifications FCM Flutter
还有更多 search results。
使用上面 Frank 的回答,我能够成功地利用 Cloud Tasks 和 Firebase Cloud Messaging 来实现我的功能!它还有一些问题需要解决,但我想如果需要的话,以后有人可以使用它。
我的代码主要基于 suggested article
这是生成的代码
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)
}
})