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

Android设备间通知推送实现及Firebase Cloud Functions报错排查

解决Firebase Cloud Functions错误+Android用户间通知推送实现

一、修复Cloud Functions中的TypeError问题

你遇到的Cannot read property 'pharmacien_id' of undefined错误主要有两个明确的原因,我帮你逐一排查并修正:

1. 文档路径中的空格导致参数解析失败

看你写的监听路径:"Pharmaciens/{pharmacien_id} /Commandes/{commande_id}" —— 在{pharmacien_id}后面多了一个空格,这会让Firebase无法正确识别路径参数,自然就找不到pharmacien_id了,这是最直接的诱因。

2. Firebase Functions版本的参数结构变化

在较新的Firebase Functions版本中,onWrite的回调参数已经从旧版的event改为(change, context),原来的event.params已经迁移到context.params里。旧写法在新版本环境下会直接导致event.params为undefined。

修正后的完整代码

'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');

// 新版本不需要传入functions.config().firebase,initializeApp会自动完成初始化
admin.initializeApp(); 

exports.sendCommandes = functions.firestore
  .document("Pharmaciens/{pharmacien_id}/Commandes/{commande_id}") // 移除路径中的空格
  .onWrite((change, context) => { // 使用新版参数结构
    const pharmacien_id = context.params.pharmacien_id;
    const commande_id = context.params.commande_id;
    console.log(`pharmacien_id: ${pharmacien_id} | commande_id: ${commande_id}`);
    
    // 函数需要返回Promise或null,避免云端执行超时
    return null; 
  });

二、Android用户间通知推送的实现步骤

要实现Android设备间的用户定向通知推送,核心是结合FCM(Firebase Cloud Messaging)和Firestore存储用户令牌,具体步骤如下:

1. 把FCM集成到Android项目

确保你的Android项目已经正确配置Firebase和FCM:

  • 在Firebase控制台为项目添加Android应用,下载google-services.json放到项目根目录。
  • 在模块级build.gradle中添加FCM依赖(建议用最新版本):
    implementation 'com.google.firebase:firebase-messaging:23.4.0'
    

2. 存储用户的FCM令牌

用户打开APP时,获取他们的FCM令牌并保存到Firestore的用户文档中(比如Pharmaciens/{userId}下新增fcmToken字段):

// 在Android代码中获取并保存令牌
FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
    if (!task.isSuccessful) {
        Log.w("FCM", "获取FCM令牌失败", task.exception)
        return@addOnCompleteListener
    }
    // 获取到的FCM令牌
    val token = task.result
    // 将令牌写入当前登录用户的Firestore文档
    FirebaseFirestore.getInstance()
        .collection("Pharmaciens")
        .document(currentUserId) // 替换为当前用户的ID
        .update("fcmToken", token)
        .addOnSuccessListener { Log.d("FCM", "令牌保存成功") }
        .addOnFailureListener { e -> Log.w("FCM", "令牌保存失败", e) }
}

3. 在Cloud Functions中触发推送逻辑

当目标事件触发(比如新增订单)时,从Firestore获取目标用户的FCM令牌,调用FCM接口发送通知:

// 延续之前的sendCommandes函数,添加推送逻辑
exports.sendCommandes = functions.firestore
  .document("Pharmaciens/{pharmacien_id}/Commandes/{commande_id}")
  .onWrite(async (change, context) => {
    const pharmacienId = context.params.pharmacien_id;
    
    // 1. 从Firestore获取目标用户的FCM令牌
    const userDoc = await admin.firestore().collection("Pharmaciens").doc(pharmacienId).get();
    if (!userDoc.exists) {
        console.log("未找到用户文档");
        return null;
    }
    const fcmToken = userDoc.data().fcmToken;
    if (!fcmToken) {
        console.log("该用户未绑定FCM令牌");
        return null;
    }
    
    // 2. 构建通知内容
    const payload = {
        notification: {
            title: "新订单提醒",
            body: "你有一个新的订单需要处理",
            clickAction: "OPEN_ORDER_ACTIVITY" // 点击通知要打开的Activity
        },
        token: fcmToken
    };
    
    // 3. 发送通知
    try {
        await admin.messaging().send(payload);
        console.log("通知发送成功");
        return null;
    } catch (error) {
        console.error("发送通知失败:", error);
        return null;
    }
});

4. Android端接收并展示通知

创建一个继承自FirebaseMessagingService的类,处理通知的接收和展示:

class MyFirebaseMessagingService : FirebaseMessagingService() {
    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
        // 解析通知内容并展示
        remoteMessage.notification?.let {
            sendNotification(it.title, it.body)
        }
    }
    
    private fun sendNotification(title: String?, body: String?) {
        // 点击通知打开订单页面
        val intent = Intent(this, OrderActivity::class.java)
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
        val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
        
        // 适配Android O及以上的通知渠道
        val channelId = "order_notification_channel"
        val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        val notificationBuilder = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle(title)
            .setContentText(body)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent)
        
        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)
        }
        
        notificationManager.notify(0, notificationBuilder.build())
    }
}

最后别忘了在AndroidManifest.xml中注册这个服务:

<service
    android:name=".MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

内容的提问来源于stack exchange,提问作者yoyo guen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:49:20