如何用Firebase Cloud Functions实现设备间消息推送(排除发送者/定向推送)
没问题,我来帮你搞定这个需求!下面是完整的实现方案,包含Android客户端(Java)和Firebase云函数的代码示例,完全匹配你提到的场景:
整体实现思路
核心流程是:Android客户端收集发送者ID、通知内容(可选指定接收者),调用Firebase云函数;云函数负责查询目标用户的FCM推送令牌,排除发送者后,调用FCM API完成通知推送。
Android Java客户端代码
首先确保你已经集成了Firebase Auth、Firebase Functions和Firebase Messaging SDK。下面是发送通知的核心代码:
import android.os.Bundle; import android.widget.Button; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import com.google.firebase.auth.FirebaseAuth; import com.google.firebase.functions.FirebaseFunctions; import com.google.firebase.functions.FirebaseFunctionsException; import java.util.HashMap; public class NotificationSenderActivity extends AppCompatActivity { private FirebaseFunctions firebaseFunctions; private FirebaseAuth firebaseAuth; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_notification_sender); firebaseFunctions = FirebaseFunctions.getInstance(); firebaseAuth = FirebaseAuth.getInstance(); // 绑定发送按钮点击事件 Button sendBtn = findViewById(R.id.btn_send_notification); sendBtn.setOnClickListener(v -> triggerNotificationSend()); } // 触发通知发送逻辑,支持广播或定向推送 private void triggerNotificationSend() { // 获取当前发送者的UID String senderUid = firebaseAuth.getCurrentUser().getUid(); // 通知内容 String notificationTitle = "新消息提醒"; String notificationBody = "这是来自用户A的测试通知"; // 定向推送时填写目标用户UID,广播推送时设为null String targetUserUid = "user_B_uid"; // 广播时改为 null // 调用云函数 firebaseFunctions.getHttpsCallable("sendCustomNotification") .call(new HashMap<String, Object>() {{ put("senderUid", senderUid); put("title", notificationTitle); put("body", notificationBody); put("targetUid", targetUserUid); }}) .addOnCompleteListener(task -> { if (task.isSuccessful()) { Toast.makeText(this, "通知发送成功", Toast.LENGTH_SHORT).show(); } else { Exception e = task.getException(); if (e instanceof FirebaseFunctionsException) { FirebaseFunctionsException ffe = (FirebaseFunctionsException) e; Toast.makeText(this, "发送失败:" + ffe.getDetails(), Toast.LENGTH_LONG).show(); } } }); } }
补充:FCM令牌存储代码
用户登录或App启动时,需要将FCM令牌保存到Firestore,供云函数查询使用:
import com.google.firebase.firestore.FirebaseFirestore; import com.google.firebase.messaging.FirebaseMessaging; import android.util.Log; // 在用户登录成功后调用 private void saveFcmToken() { FirebaseMessaging.getInstance().getToken() .addOnCompleteListener(task -> { if (!task.isSuccessful()) { Log.w("FCM", "获取令牌失败", task.getException()); return; } String fcmToken = task.getResult(); // 将令牌保存到Firestore的users集合中,以用户UID为文档ID FirebaseFirestore.getInstance().collection("users") .doc(firebaseAuth.getCurrentUser().getUid()) .update("fcmToken", fcmToken) .addOnSuccessListener(aVoid -> Log.d("FCM", "令牌保存成功")) .addOnFailureListener(e -> Log.w("FCM", "令牌保存失败", e)); }); }
Firebase Cloud Functions代码(Node.js)
首先确保你已经初始化了Firebase云函数项目,然后在index.js中添加以下代码:
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); // 云函数:处理自定义通知推送 exports.sendCustomNotification = functions.https.onCall(async (data, context) => { // 验证用户身份(可选但建议添加) if (!context.auth) { throw new functions.https.HttpsError("unauthenticated", "请先登录"); } const { senderUid, title, body, targetUid } = data; let targetTokens = []; if (targetUid) { // 定向推送:获取指定用户的FCM令牌 const userDoc = await admin.firestore().collection("users").doc(targetUid).get(); if (userDoc.exists && userDoc.data().fcmToken) { targetTokens.push(userDoc.data().fcmToken); } else { throw new functions.https.HttpsError("not-found", "目标用户不存在或未注册推送令牌"); } } else { // 广播推送:获取所有用户令牌,排除发送者 const usersSnapshot = await admin.firestore().collection("users").get(); usersSnapshot.forEach(doc => { const uid = doc.id; const token = doc.data().fcmToken; if (uid !== senderUid && token) { targetTokens.push(token); } }); } if (targetTokens.length === 0) { throw new functions.https.HttpsError("no-recipients", "没有找到有效的接收者"); } // 构建FCM通知 payload const payload = { notification: { title: title, body: body }, data: { senderUid: senderUid // 可选:传递发送者ID,方便客户端处理 } }; // 发送通知 try { const response = await admin.messaging().sendToDevice(targetTokens, payload); functions.logger.log("通知发送成功,响应:", response); return { success: true, message: `已推送给 ${targetTokens.length} 个设备` }; } catch (error) { functions.logger.error("通知发送失败:", error); throw new functions.https.HttpsError("internal", "推送过程出错", error); } });
场景验证说明
- 广播推送场景:当用户A发送通知且
targetUid为null时,云函数会遍历所有用户的令牌,排除A自己的令牌后推送给B、C等其他用户,A不会收到通知提醒。 - 定向推送场景:当A指定
targetUid为B的UID时,云函数只会获取B的令牌并推送,仅B能收到通知。
内容的提问来源于stack exchange,提问作者Jon Doe
相关产品推荐
相关产品推荐

