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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:04:35