安卓Firebase云函数通知

3

我已经成功设置了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,然后发送通知。 - Ajinkya S
请展示一些Node.js的代码示例,我是新手。 - Dexter Fury Kombat Zone
1个回答

8

根据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数组或者只需要使用tokens? - Dexter Fury Kombat Zone
1
不,您不能使用uid向设备发送通知。我们有这样的情况,即一个用户拥有两个设备,或者有时用户的FCM令牌会更改(例如,如果用户删除应用程序数据)。每次它都会获得一个新值,包括在Android中第一次调用onTokenRefresh()方法时,这就是为什么我们实现了将FCM令牌发送到我们的服务器/数据库的逻辑,该逻辑位于onTokenRefresh()方法内部。 - Ramiz Ansari
非常感谢,经过反复尝试,我终于让它正常工作了...再次感谢... - Dexter Fury Kombat Zone
让我们在聊天中继续这个讨论 - Ramiz Ansari
@UrielFrankel 一个用户可以拥有多个设备,而令牌代表一个设备,因此每个用户有多个令牌。 - Ramiz Ansari
显示剩余9条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接