You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Firebase Cloud Messaging向特定用户定时推送通知?

Hey there! Let's tackle your FCM and Firestore questions step by step—you're already halfway there with the token logging code, so let's build on that.

1. Send Notifications to Specific Logged-In Users (and Targeted Devices)

Right now you're sending to all users because you're not targeting specific tokens. The fix here is to link each user's Firebase Auth UID with their FCM tokens in Firestore, so you can fetch exactly the tokens you need when sending a notification.

Step 1: Save FCM Tokens to Firestore

Update your existing token-fetching code to save tokens to Firestore whenever a user is logged in. This includes handling new tokens (from onNewToken) and initial token fetch (from MainActivity).

In your MainActivity (after getting the token):

FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
if (currentUser != null) {
    String uid = currentUser.getUid();
    String deviceId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID); // Track specific devices

    Map<String, Object> tokenData = new HashMap<>();
    tokenData.put("token", token);
    tokenData.put("deviceId", deviceId);
    tokenData.put("lastUpdated", FieldValue.serverTimestamp());

    // Save token under the user's document, avoid duplicates by using token as doc ID
    FirebaseFirestore.getInstance()
        .collection("users")
        .document(uid)
        .collection("fcmTokens")
        .document(token)
        .set(tokenData, SetOptions.merge());
}

In your FirebaseMessagingService's onNewToken:

@Override
public void onNewToken(String token) {
    Log.e("NEW_TOKEN", token);
    FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
    if (currentUser != null) {
        String uid = currentUser.getUid();
        String deviceId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);

        Map<String, Object> tokenData = new HashMap<>();
        tokenData.put("token", token);
        tokenData.put("deviceId", deviceId);
        tokenData.put("lastUpdated", FieldValue.serverTimestamp());

        FirebaseFirestore.getInstance()
            .collection("users")
            .document(uid)
            .collection("fcmTokens")
            .document(token)
            .set(tokenData, SetOptions.merge());
    }
}

Step 2: Send Notifications to a Specific User/Device

Use Firebase Cloud Functions to fetch the target user's tokens from Firestore and send the notification. Here's a Node.js example function:

const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();

// Callable function to send notification to a specific user
exports.sendToSpecificUser = functions.https.onCall(async (data, context) => {
    const { uid, deviceId, title, body } = data;

    // Fetch tokens for the user (filter by deviceId if targeting a specific device)
    let tokensQuery = admin.firestore()
        .collection("users")
        .document(uid)
        .collection("fcmTokens");
    
    if (deviceId) {
        tokensQuery = tokensQuery.where("deviceId", "==", deviceId);
    }

    const tokensSnapshot = await tokensQuery.get();
    const tokens = [];
    tokensSnapshot.forEach(doc => tokens.push(doc.id));

    if (tokens.length === 0) {
        throw new functions.https.HttpsError("not-found", "No valid tokens found for this user/device.");
    }

    // Build and send the notification
    const message = {
        notification: { title, body },
        tokens: tokens
    };

    const response = await admin.messaging().sendMulticast(message);
    functions.logger.log(`Sent ${response.successCount} notifications, failed ${response.failureCount}`);
    return { success: true, successCount: response.successCount };
});

You can call this function from your app whenever you need to send a targeted notification.

2. Schedule Notifications by Time and Day of Week

Firestore itself doesn't have built-in scheduling capabilities—you'll need to combine Firestore (to store scheduled tasks) with Firebase Cloud Functions + Cloud Scheduler to trigger notifications at specific times.

Step 1: Store Scheduled Notification Tasks in Firestore

Add a collection (e.g., scheduledNotifications) to store user-specific scheduled tasks. Each document might look like this:

{
  "uid": "user123",
  "deviceId": "abc123", // Optional, for device targeting
  "title": "Reminder: Weekly Check-in",
  "body": "Don't forget to submit your progress!",
  "dayOfWeek": 1, // 1 = Monday, 2 = Tuesday, ..., 7 = Sunday
  "hour": 10, // 24-hour format
  "minute": 0,
  "timeZone": "Asia/Shanghai"
}

Step 2: Create a Scheduled Cloud Function

Use a Pub/Sub scheduled trigger to run a function that checks Firestore for tasks that need to be sent at the current time. Here's an example:

// Trigger every minute to check for scheduled notifications (adjust frequency as needed)
exports.runScheduledNotifications = functions.pubsub.schedule("* * * * *")
    .timeZone("Asia/Shanghai")
    .onRun(async (context) => {
        const now = new Date();
        const currentDay = now.getDay() === 0 ? 7 : now.getDay(); // Convert Sunday (0) to 7
        const currentHour = now.getHours();
        const currentMinute = now.getMinutes();

        // Fetch all tasks scheduled for this day/time
        const tasksSnapshot = await admin.firestore()
            .collection("scheduledNotifications")
            .where("dayOfWeek", "==", currentDay)
            .where("hour", "==", currentHour)
            .where("minute", "==", currentMinute)
            .get();

        for (const taskDoc of tasksSnapshot.docs) {
            const task = taskDoc.data();
            const { uid, deviceId, title, body } = task;

            // Fetch tokens for the user/device
            let tokensQuery = admin.firestore()
                .collection("users")
                .document(uid)
                .collection("fcmTokens");
            
            if (deviceId) {
                tokensQuery = tokensQuery.where("deviceId", "==", deviceId);
            }

            const tokensSnapshot = await tokensQuery.get();
            const tokens = [];
            tokensSnapshot.forEach(doc => tokens.push(doc.id));

            if (tokens.length > 0) {
                const message = {
                    notification: { title, body },
                    tokens: tokens
                };
                await admin.messaging().sendMulticast(message);
            }
        }

        return null;
    });

Alternatively, if you have fixed schedules (like every Monday at 10 AM), you can use a more specific trigger instead of checking every minute:

// Trigger every Monday at 10 AM
exports.weeklyMondayNotification = functions.pubsub.schedule("0 10 * * 1")
    .timeZone("Asia/Shanghai")
    .onRun(async (context) => {
        // Fetch all tasks scheduled for Monday 10 AM and send notifications
        // Similar logic to the above function
    });
Key Takeaways
  • Targeted notifications: Link Auth UIDs and FCM tokens in Firestore, then fetch those tokens when sending.
  • Scheduling: Firestore can store scheduled tasks, but you need Cloud Functions + Cloud Scheduler to trigger the actual notification send at the right time.
  • Device targeting: Include the device ID when saving tokens to Firestore, then filter by device ID when fetching tokens.

内容的提问来源于stack exchange,提问作者qqaaq1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 07:37:36