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

如何配置Firebase Messaging仅向已登录用户发送通知?

嘿,我之前也踩过这个坑!其实核心逻辑就是把FCM令牌的注册与用户登录状态绑定——只有当用户成功登录后,才把设备的FCM令牌和用户账号关联起来,发送通知时只针对这些已绑定的令牌推送就行。下面是具体的实现步骤:

解决思路与代码实现

1. 延迟FCM令牌的获取与上传

默认FCM会在应用启动时自动生成令牌,但我们要把这个动作延后到用户登录成功之后:

// 在用户登录成功的回调中执行令牌获取与绑定
FirebaseAuth.getInstance().signInWithEmailAndPassword(email, password)
    .addOnCompleteListener(task -> {
        if (task.isSuccessful()) {
            FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
            if (currentUser == null) return;
            
            // 用户登录成功,获取FCM令牌
            FirebaseMessaging.getInstance().getToken()
                .addOnCompleteListener(tokenTask -> {
                    if (!tokenTask.isSuccessful()) {
                        Log.w(TAG, "获取FCM令牌失败", tokenTask.getException());
                        return;
                    }
                    String fcmToken = tokenTask.getResult();
                    // 将令牌与用户UID绑定,存入Firebase Firestore/实时数据库
                    FirebaseFirestore.getInstance()
                        .collection("user_fcm_tokens")
                        .document(currentUser.getUid())
                        .set(new HashMap<String, Object>() {{
                            put("token", fcmToken);
                            put("update_time", new Date());
                        }});
                });
        }
    });

2. 处理用户退出登录的场景

用户退出时,要把对应令牌从存储中移除,避免后续误发通知:

// 退出登录方法中添加令牌清理逻辑
FirebaseAuth.getInstance().signOut();
FirebaseMessaging.getInstance().getToken()
    .addOnCompleteListener(tokenTask -> {
        if (tokenTask.isSuccessful()) {
            String currentToken = tokenTask.getResult();
            // 从数据库删除该令牌的绑定记录
            FirebaseFirestore.getInstance()
                .collection("user_fcm_tokens")
                .whereEqualTo("token", currentToken)
                .get()
                .addOnCompleteListener(queryTask -> {
                    if (queryTask.isSuccessful()) {
                        for (QueryDocumentSnapshot doc : queryTask.getResult()) {
                            doc.getReference().delete();
                        }
                    }
                });
            // 可选:删除本地令牌,暂时禁用该设备的通知接收
            FirebaseMessaging.getInstance().deleteToken();
        }
    });

3. 发送通知时仅针对已登录用户的令牌

不要使用主题订阅(未登录用户可能也会订阅),而是从数据库取出所有已绑定用户的令牌,批量推送:

// 后端用Firebase Admin SDK发送通知的示例
FirebaseFirestore.getInstance().collection("user_fcm_tokens").get()
    .addOnCompleteListener(task -> {
        if (task.isSuccessful()) {
            List<String> targetTokens = new ArrayList<>();
            for (QueryDocumentSnapshot doc : task.getResult()) {
                targetTokens.add(doc.getString("token"));
            }
            // 构建通知内容
            Message message = Message.builder()
                .setNotification(Notification.builder()
                    .setTitle("专属通知")
                    .setBody("只有登录用户才能看到这条消息!")
                    .build())
                .setTokens(targetTokens)
                .build();
            // 批量发送
            FirebaseMessaging.getInstance().sendEachForMulticast(message);
        }
    });

额外注意事项

  • 处理令牌更新:FCM令牌可能因设备重启、应用重装等情况变化,所以在onNewToken方法中要判断用户是否已登录,已登录则更新数据库中的令牌:
@Override
public void onNewToken(String newToken) {
    super.onNewToken(newToken);
    FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
    if (currentUser != null) {
        // 用户已登录,更新数据库令牌
        FirebaseFirestore.getInstance()
            .collection("user_fcm_tokens")
            .document(currentUser.getUid())
            .update("token", newToken, "update_time", new Date());
    }
}
  • 不要在应用启动时自动上传令牌,确保只有登录后的用户才会被纳入通知列表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:35:50