如何在Jetpack Compose中通过Firebase Cloud Messaging给特定用户发通知
解决方案:Firestore触发FCM通知给管理员
你的需求完全可行,不建议在Android客户端直接发送FCM通知——这种方式存在权限风险、令牌维护困难等问题,正确的实现方式是通过Firebase Cloud Functions监听Firestore的写入事件,在服务端完成通知推送。
当前代码的核心问题
- 客户端调用
firebaseMessaging.send()需要额外的权限验证,且属于客户端主动发送消息,不符合FCM的推送规范,容易被限制或失败。 - 硬编码设备令牌无法适配多管理员场景,且令牌会随设备更新失效,无法动态维护。
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
相关产品推荐
相关产品推荐

