【问题标题】:Android Firebase cloud function notificationAndroid Firebase 云功能通知
【发布时间】:2025-12-02 17:15:01
【问题描述】:

我已设法设置 Firebase 云功能以向主题发送通知。问题是它会发送给包括发件人在内的所有用户,我该如何设置我的云功能,以便它不会向发件人显示通知?请帮忙?以下是如何发送到主题

exports.sendNotesNotification = functions.database.ref('/Notes/{pushId}')
    .onWrite(event => {
        const notes = event.data.val();

        const payload = {
                notification: {

                    username: notes.username,
                    title: notes.title,
                    body: notes.desc

                }

            }

            admin.messaging().sendToTopic("New_entry", payload)
            .then(function(response){
                console.log("Successfully sent notes: ", response);
            })
            .catch(function(error){
                console.log("Error sending notes: ", error);
            });
        }); 

【问题讨论】:

  • 您必须知道发件人的 fcm id。当您将其发送给所有人时,只需检查并排除发件人的 fcm id,然后发送通知
  • 请展示代码示例是 nodejs 的新手。

标签: android firebase push-notification google-cloud-functions


【解决方案1】:

根据 firebase 的文档,对于公开且时间不紧迫的通知,应使用主题发送通知。在您的情况下,通知是不公开的,并且由于发件人也订阅了该特定主题,他也会收到通知。 因此,如果您想避免向发件人发送通知,您必须从您的主题中取消订阅该发件人。

或者更好的解决方案是您应该使用 FCM 令牌将通知发送到单个设备。 用于发送 FCM 令牌通知的 node.js 代码是

admin.messaging().sendToDevice(<array of tokens>, payload);

你可以从你安卓的 FirebaseInstanceIdService 的 onTokenRefresh() 方法获取设备令牌。

 @Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
        // TO DO: send token to your server or firebase database
}

更新:

将 firebase 令牌存储到您的数据库现在您应该像这样构建您的数据库

   -users
      |-user1uid
      |   |-name //your choice
      |   |-email //your choice
      |   |-fcmTokens
      |        |-valueOftoken1:true
      |        |-valueOftoken2:true
   -notes
      |  |-notesId
      |      |-yourdata
      |      |-createdBy:uidofUser  //user who created note
      |
   -subscriptions       //when onWrite() will trigger we will use this to get UID of all subscribers of creator of "note". 
      |      |-uidofUser    
      |           |-uidofSubscriber1:true //user subscribe to notes written. by parent node uid
      |           |-uidofSubscriber2:true

这里将令牌保存在数据库中是onTokenRefresh()的代码

 @Override
        public void onTokenRefresh() {
            // Get updated InstanceID token.
            String refreshedToken = FirebaseInstanceId.getInstance().getToken(); //get refreshed token
            FirebaseAuth mAuth = FirebaseAuth.getInstance();
            FirebaseUser user = mAuth.getCurrentUser(); //get currentto get uid
            if(user!=null){
            DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference().child("users").child(user.getUid()); // create a reference to userUid in database
            if(refreshedToken!=null) //
              mDatabase.child("fcmTokens").child(refreshedToken).setValue(true); //creates a new node of user's token and set its value to true.
            else
              Log.i(TAG, "onTokenRefresh: token was null");
    }
    Log.d(tag, "Refreshed token SEND TO FIREBASE: " + refreshedToken);
    }

当为该用户创建新令牌时,上述代码将在用户的 fcmTokens 中创建新节点。

这里是检索用户令牌并向这些令牌发送通知的 node.js 部分。 为此

exports.sendNotesNotification = functions.database.ref('/Notes/{pushId}')
    .onWrite(event => {

        const notes = event.data.val();
        const createdby = notes.createdBy;
        const getAllSubscribersPromise = admin.database().ref(`/subscriptions/${createdby}/`).once('value'); // retrieving subscribers 

         const payload = {
                notification: {

                    username: notes.username,
                    title: notes.title,
                    body: notes.desc

                }

            }

        return getAllSubscribersPromise.then(result => {
        const userUidSnapShot = result; //results will have children having keys of subscribers uid.
        if (!userUidSnapShot.hasChildren()) {
          return console.log('There are no subscribed users to write notifications.'); 
        }
        console.log('There are', userUidSnapShot.numChildren(), 'users to send notifications to.');
        const users = Object.keys(userUidSnapShot.val()); //fetched the keys creating array of subscribed users

        var AllFollowersFCMPromises = []; //create new array of promises of TokenList for every subscribed users
        for (var i = 0;i<userUidSnapShot.numChildren(); i++) {
            const user=users[i];
            console.log('getting promise of user uid=',user);
            AllFollowersFCMPromises[i]= admin.database().ref(`/users/${user}/fcmToken/`).once('value');
        }

        return Promise.all(AllFollowersFCMPromises).then(results => {

            var tokens = []; // here is created array of tokens now ill add all the fcm tokens of all the user and then send notification to all these.
            for(var i in results){
                var usersTokenSnapShot=results[i];
                console.log('For user = ',i);
                if(usersTokenSnapShot.exists()){
                    if (usersTokenSnapShot.hasChildren()) { 
                        const t=  Object.keys(usersTokenSnapShot.val()); //array of all tokens of user [n]
                        tokens = tokens.concat(t); //adding all tokens of user to token array
                        console.log('token[s] of user = ',t);
                    }
                    else{

                    }
                }
            }
            console.log('final tokens = ',tokens," notification= ",payload);
            return admin.messaging().sendToDevice(tokens, payload).then(response => {
      // For each message check if there was an error.
                const tokensToRemove = [];
                response.results.forEach((result, index) => {
                    const error = result.error;
                    if (error) {
                        console.error('Failure sending notification to uid=', tokens[index], error);
                        // Cleanup the tokens who are not registered anymore.
                        if (error.code === 'messaging/invalid-registration-token' || error.code === 'messaging/registration-token-not-registered') {
                            tokensToRemove.push(usersTokenSnapShot.ref.child(tokens[index]).remove());
                        }
                    }
                    else{
                        console.log("notification sent",result);
                    }
                });

                return Promise.all(tokensToRemove);
            });

            return console.log('final tokens = ',tokens," notification= ",payload);
        });





            });
        }); 

我还没有检查 node.js 部分,如果您还有问题,请告诉我。

【讨论】:

  • 谢谢,看起来不错会试一试,但我也可以使用 uid 数组还是只需要使用令牌?
  • 您的代码也出现此错误错误:解析函数触发器时发生错误。 C:\Users\Dexter\AppData\Local\Temp\fbfn_11128qrnTKRceWFWR\index.js:64 admin.messaging().sendToDevice(, payload) ^
  • 不,您不能使用 uid 向设备发送通知。我们会遇到 1 个用户拥有 2 个设备或有时用户 FCM 令牌更改(例如,如果用户删除应用数据)的情况。每次它获得一个新值时,包括第一次在 android 中调用 onTokenRefresh() 方法,这就是为什么我们在 onTokenRefresh() 方法中实现将 FCM 令牌发送到我们的服务器/数据库的逻辑。
  • 好的,谢谢我设法获得令牌,并像这样将当前用户令牌添加到 ArrayList 最终 ArrayList list = new ArrayList();然后在我的应用程序 list.add(SharedPrefManager.getInstance(getApplicationContext()).getToken()) 的 cmets 活动中发送消息;如何将令牌作为列表发送到节点?以便我向令牌列表发送通知?如果可以,请提供帮助...因为这个 admin.messaging().sendToDevice(, payload);给出错误
  • 我的令牌数组我的意思是它在 javascript 代码而不是 android 代码中。我已经更新了我的答案并解释了一切,希望对您有所帮助。随便问什么