Firebase的云功能:不向所有用户发送通知

时间:2020-01-25 14:42:05

标签: node.js firebase firebase-realtime-database google-cloud-functions firebase-cloud-messaging

我用Firebase和Flutter应用创建了一个电子商务Android应用程序来更新Firebase节点。

我想在管理员更新汇率时向所有用户发送通知。

下面是我编写的使用Cloud Function将更新通知发送到所有注册令牌的代码,但是它仅将通知发送到Flutter应用程序,而不是两个应用程序。

我不知道我在做什么错。

这是我的功能代码:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

exports.helloWorld=functions.database.ref('Rates').onUpdate(evt =>{
    const payload={
        notification:{
            title:"Today's Rate",
            body :"Click here to see today's gold rate",
            badge: '1',
            sound: 'default'
        }
    }
    return admin.database().ref('fcm-token').once('value').then(allToken =>{
        if(allToken.val()){
            console.log('token available');
            const token = Object.keys(allToken.val());
            console.log(admin.messaging().sendToDevice(token, payload));
            return admin.messaging().sendToDevice(token, payload);
        }else{
            console.log('No Token Available');
            throw new Error("Profile doesn't exist")
        }
    });
});

这是我的Realtime Database Structure的图片。

2 个答案:

答案 0 :(得分:1)

基于数据库的provided screenshot,数据库中/fcm-token下的数据具有两种不同的格式。

手动添加数据时,使用的格式为:

{
  "fcm-token": {
    "someRegistrationToken": {
      "token": "someRegistrationToken"
    },
    "someOtherRegistrationToken": {
      "token": "someOtherRegistrationToken"
    }
    ...
  },
  ...
}

在“自动注册”条目中,您使用以下方式添加了令牌:

{
  "fcm-token": {
    "somePushId": {
      "fcmToken": "someRegistrationToken"
    },
    "someOtherPushId": {
      "fcmToken": "someOtherRegistrationToken"
    },
    ...
  },
  ...
}

在您的Cloud Functions代码中,您使用/fcm-tokenObject.keys(allToken.val())下存储的所有键收集到一个数组中,这将为您提供一个包含推送ID和FCM令牌混合的数组,这不是您所需要的想要,这就是为什么某些设备缺少通知的原因。

因此,简而言之,请选择一种或另一种格式。

临时解决方法

在现有的混合结构中,您可以使用以下内容,该内容将忽略用作密钥的内容,仅提取令牌:

return admin.database().ref('fcm-token').once('value').then(allTokensSnapshot => {
    if (allTokensSnapshot.exists()) {
        console.log('Tokens available');
        const tokenArray = [];
        allTokensSnapshot.forEach((tokenSnapshot) => {
            let token = tokenSnapshot.hasChild('fcmToken')
                ? tokenSnapshot.child('fcmToken').val()
                : tokenSnapshot.child('token').val();
            tokenArray.push(token);
        });

        return admin.messaging().sendToDevice(tokenArray, payload);
    } else {
        console.log('No tokens available');
        throw new Error('No tokens available');
    }
});

数据库展平

我个人将其弄平,以便您可以按原样使用代码,但这需要更改将令牌添加到数据库的方式:

数据库结构:

{
  "fcm-token": {
    "someRegistrationToken": true,
    "someOtherRegistrationToken": true,
    ...
  }
}

(如果需要,您也可以使用设备所有者的用户ID代替true

客户代码:

FirebaseInstanceId.getInstance().getInstanceId()
  .addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
    @Override
    public void onSuccess(InstanceIdResult result) {
      DatabaseReference allTokensRef = FirebaseDatabase.getInstance().getReference().child("fcm-token");

      String token = result.getToken();
      Log.e("Test", "FCM Registration Token: " + token);

      SharedPreferences preferences = this.getSharedPreferences("com.jk.jkjwellers", MODE_PRIVATE);
      if(!(preferences.getBoolean("FCMAdded", false))){
        allTokensRef.child(token).setValue(true);
        preferences.edit().putBoolean("FCMAdded",true).apply();
      }
    }
  })
  .addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception e) {
      Log.e("Test", "Failed to get FCM registration token", e);
    }
  });

答案 1 :(得分:0)

不确定,但是尝试更换

databaseReference.push().setValue(new Tokens(token));

使用

databaseReference.child(token).setValue(new Tokens(token));