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

如何在Jetpack Compose中通过Firebase Cloud Messaging给特定用户发通知

解决方案:Firestore触发FCM通知给管理员

你的需求完全可行,不建议在Android客户端直接发送FCM通知——这种方式存在权限风险、令牌维护困难等问题,正确的实现方式是通过Firebase Cloud Functions监听Firestore的写入事件,在服务端完成通知推送。

当前代码的核心问题

  1. 客户端调用firebaseMessaging.send()需要额外的权限验证,且属于客户端主动发送消息,不符合FCM的推送规范,容易被限制或失败。
  2. 硬编码设备令牌无法适配多管理员场景,且令牌会随设备更新失效,无法动态维护。
  3. onMessageReceived仅打印日志,未实现通知展示逻辑,后台状态下可能无法接收数据消息。

正确实现步骤

1. 完善Firestore数据结构

  • 在admins集合中,每个管理员文档需存储email和fcmToken(管理员登录时需将设备令牌写入此处)。
  • 在warnings集合中存储用户提交的警告内容(包含提交用户ID、警告内容等字段)。

2. 编写Firebase Cloud Functions(服务端推送)

通过Cloud Functions监听warnings集合的新增事件,自动向所有管理员发送通知:

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

exports.sendAdminNotification = functions.firestore
  .document("warnings/{warningId}")
  .onCreate(async (snap, context) => {
    // 获取新增的警告数据
    const warningData = snap.data();
    
    // 查询所有管理员的有效FCM令牌
    const adminsSnapshot = await admin.firestore().collection("admins").get();
    const tokens = [];
    adminsSnapshot.forEach(doc => {
      const token = doc.data().fcmToken;
      if (token) tokens.push(token);
    });

    if (tokens.length === 0) {
      functions.logger.info("无可用的管理员FCM令牌");
      return null;
    }

    // 构建通知内容
    const payload = {
      notification: {
        title: "新警告提交",
        body: `用户 ${warningData.userId} 提交了新警告:${warningData.content}`
      },
      data: {
        warningId: context.params.warningId
      }
    };

    // 批量发送通知
    try {
      const response = await admin.messaging().sendMulticast({
        tokens: tokens,
        notification: payload.notification,
        data: payload.data
      });
      functions.logger.info(`推送成功:${response.successCount} 条,失败:${response.failureCount} 条`);
      return response;
    } catch (error) {
      functions.logger.error("推送通知失败", error);
      return null;
    }
  });

3. 完善Android端FCM处理

(1)管理员令牌自动更新

在CloudMessaging类中,将新生成的设备令牌写入Firestore:

class CloudMessaging : FirebaseMessagingService() {
    private val TAG = "CloudMessaging"

    override fun onNewToken(token: String) {
        Log.d(TAG, "新设备令牌:$token")
        // 仅管理员用户更新令牌到Firestore
        updateAdminFcmToken(token)
    }

    private fun updateAdminFcmToken(token: String) {
        val currentUser = FirebaseAuth.getInstance().currentUser ?: return
        FirebaseFirestore.getInstance()
            .collection("admins")
            .document(currentUser.uid)
            .update("fcmToken", token)
            .addOnSuccessListener { Log.d(TAG, "令牌更新成功") }
            .addOnFailureListener { e -> Log.e(TAG, "令牌更新失败", e) }
    }
}

(2)通知展示逻辑

完善onMessageReceived方法,实现前台/后台的通知展示:

override fun onMessageReceived(message: RemoteMessage) {
    super.onMessageReceived(message)
    // 处理通知消息
    message.notification?.let {
        showNotification(it.title ?: "系统通知", it.body ?: "")
    }
    // 处理数据消息(可选)
    message.data.let { data ->
        Log.d(TAG, "数据消息内容:$data")
    }
}

private fun showNotification(title: String, content: String) {
    val intent = Intent(this, MainActivity::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    }
    val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)

    val notificationBuilder = NotificationCompat.Builder(this, "WARNING_CHANNEL")
        .setSmallIcon(R.drawable.ic_notification)
        .setContentTitle(title)
        .setContentText(content)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setContentIntent(pendingIntent)
        .setAutoCancel(true)

    val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    // Android 8.0+ 必须创建通知渠道
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel = NotificationChannel(
            "WARNING_CHANNEL",
            "警告通知",
            NotificationManager.IMPORTANCE_DEFAULT
        )
        notificationManager.createNotificationChannel(channel)
    }
    notificationManager.notify(0, notificationBuilder.build())
}

4. 部署Cloud Functions

安装Firebase CLI后,执行部署命令:

firebase deploy --only functions

常见问题排查

  • 确保Cloud Functions的服务账号拥有Firestore读取权限和FCM推送权限(默认权限已满足)。
  • 管理员的设备令牌需有效且正确写入Firestore,若令牌过期需重新登录更新。
  • Android 8.0+必须创建通知渠道,否则无法展示通知。
  • 测试时可在Firestore手动新增warnings文档,触发Cloud Functions执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 00:05:27