Android端跨设备推送通知实现方案咨询(基于Firebase)
嘿,刚好做过类似的竞标通知需求,结合你用Firebase的现状,给你梳理一套完整的实现方案,应该能快速搞定跨设备推送的问题:
核心逻辑梳理
你现在能给自己推通知,说明FCM的基础配置(比如google-services.json、依赖引入)已经没问题了。现在要实现给竞标用户推通知,核心就是拿到目标用户的FCM令牌,然后在发布者接受竞标时,把通知消息推送到这个令牌对应的设备上。
具体实现步骤
1. 先把用户的FCM令牌存到Firebase数据库
用户登录后,得把当前设备的FCM令牌和用户ID绑定存储,这样后面才能通过用户ID找到对应的令牌。而且令牌可能会变,所以每次应用启动都建议更新一次。
代码示例(Kotlin):
// 获取当前设备的FCM令牌 FirebaseMessaging.getInstance().token.addOnCompleteListener { task -> if (!task.isSuccessful) { Log.w(TAG, "获取FCM令牌失败", task.exception) return@addOnCompleteListener } val token = task.result ?: return@addOnCompleteListener // 假设当前登录用户的ID存在currentUserId变量里 FirebaseFirestore.getInstance().collection("users") .document(currentUserId) .update("fcmToken", token) .addOnSuccessListener { Log.d(TAG, "FCM令牌已更新到数据库") } .addOnFailureListener { e -> Log.w(TAG, "FCM令牌存储失败", e) } }
2. 在发布者接受竞标时,触发通知发送逻辑
当发布者点击“接受竞标”按钮,先从数据库里拿到竞标用户的ID,再通过这个ID去users集合里取出对应的FCM令牌,然后调用发送通知的方法。
代码示例(Kotlin):
// 假设选中的竞标ID是selectedBidId FirebaseFirestore.getInstance().collection("bids") .document(selectedBidId) .get() .addOnSuccessListener { bidDoc -> val bidderUserId = bidDoc.getString("bidderUserId") ?: return@addOnSuccessListener // 获取竞标用户的FCM令牌 FirebaseFirestore.getInstance().collection("users") .document(bidderUserId) .get() .addOnSuccessListener { userDoc -> val fcmToken = userDoc.getString("fcmToken") fcmToken?.let { // 发送通知 sendNotificationToTargetUser(it, "竞标被接受!", "你的竞标已被发布者确认,快去查看任务详情吧~") } ?: Log.w(TAG, "竞标用户未设置FCM令牌,无法推送通知") } }
3. 选择合适的通知发送方式
这里有两种常见方式,推荐用第二种更安全:
方式一:客户端直接发送(适合快速测试,不推荐生产环境)
可以调用FCM的REST API,但要注意不能把FCM服务器密钥放在客户端,否则会有安全风险。如果只是测试,可以临时用,但生产环境一定要换方式。
方式二:Firebase Cloud Functions(推荐生产环境)
把发送通知的逻辑放在云端,当数据库里的竞标状态变为accepted时自动触发,既安全又不用客户端处理复杂逻辑。
Cloud Functions代码示例(Node.js):
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); // 监听竞标状态更新,发送通知 exports.sendBidAcceptNotification = functions.firestore .document("bids/{bidId}") .onUpdate((change, context) => { const beforeStatus = change.before.data().status; const afterStatus = change.after.data().status; // 只有当状态从非accepted变为accepted时触发 if (beforeStatus !== "accepted" && afterStatus === "accepted") { const bidderUserId = change.after.data().bidderUserId; const taskId = change.after.data().taskId; // 获取竞标用户的FCM令牌 return admin.firestore().collection("users").doc(bidderUserId).get() .then(userDoc => { const fcmToken = userDoc.data().fcmToken; if (!fcmToken) { console.log("竞标用户未设置FCM令牌"); return null; } // 构建通知内容 const payload = { notification: { title: "竞标被接受啦!", body: "你的竞标已被发布者确认,点击查看任务详情", clickAction: "OPEN_TASK_DETAIL" // 对应Android里的跳转动作 }, data: { taskId: taskId // 携带任务ID,方便跳转 } }; // 发送通知到目标设备 return admin.messaging().sendToDevice(fcmToken, payload) .then(response => { console.log("通知发送成功", response); return null; }) .catch(error => { console.error("通知发送失败", error); }); }); } return null; });
4. Android端处理通知接收与跳转
如果你之前已经实现了接收通知,这部分只需要调整下跳转逻辑就行。比如点击通知跳转到任务详情页:
自定义FirebaseMessagingService示例(Kotlin):
class MyFirebaseMessagingService : FirebaseMessagingService() { override fun onMessageReceived(remoteMessage: RemoteMessage) { super.onMessageReceived(remoteMessage) // 提取通知内容和数据 val title = remoteMessage.notification?.title ?: "新通知" val body = remoteMessage.notification?.body ?: "" val taskId = remoteMessage.data["taskId"] // 显示通知 showNotification(title, body, taskId) } private fun showNotification(title: String, body: String, taskId: String?) { // 跳转任务详情页的Intent val intent = Intent(this, TaskDetailActivity::class.java) taskId?.let { intent.putExtra("EXTRA_TASK_ID", it) } intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) val pendingIntent = PendingIntent.getActivity( this, 0, intent, PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE ) // 创建通知渠道(Android O及以上必须) val channelId = "bid_notification_channel" val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( channelId, "竞标通知", NotificationManager.IMPORTANCE_DEFAULT ) notificationManager.createNotificationChannel(channel) } // 构建通知 val notificationBuilder = NotificationCompat.Builder(this, channelId) .setSmallIcon(R.drawable.ic_notification) .setContentTitle(title) .setContentText(body) .setAutoCancel(true) .setContentIntent(pendingIntent) notificationManager.notify(0, notificationBuilder.build()) } }
别忘了在AndroidManifest.xml里注册这个Service:
<service android:name=".MyFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
一些注意事项
- 令牌更新:FCM令牌可能会因为设备重置、应用重装等情况变化,所以每次应用启动都要更新一次令牌到数据库。
- 测试环境:用真实设备测试,模拟器可能无法接收FCM通知(需要配置Google Play服务)。
- 权限:确保应用已经申请了
POST_NOTIFICATIONS权限(Android 13及以上)。
内容的提问来源于stack exchange,提问作者javacoder123
相关产品推荐
相关产品推荐

