【问题标题】:Cloud Functions for Firebase: Not sending notification to all usersFirebase 的 Cloud Functions:不向所有用户发送通知
【发布时间】:2020-05-11 14:20:21
【问题描述】:

我已经使用 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 的图片。

【问题讨论】:

  • 发送到 Flutter 应用的代码与发送到 Android 应用的代码没有区别。如果未收到通知,则很可能是您捕获注册令牌的方式或处理来自 FCM 的消息的方式有所不同。
  • DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference().child("fcm-token"); String token = FirebaseInstanceId.getInstance().getToken(); Log.e("Test", "FCM Registration Token: " + token); if(!(this.getSharedPreferences("com.jk.jkjwellers",MODE_PRIVATE).getBoolean("FCMAdded",false))){ databaseReference.push().setValue(new Tokens(token)); this.getSharedPreferences("com.jk.jkjwellers",MODE_PRIVATE).edit().putBoolean("FCMAdded",true).apply(); }
  • 我正在使用此代码注册令牌。但是当我使用 if 条件时。令牌未在 firebase 上注册。当我将其删除时。当用户打开应用程序时。它用相同的令牌一次又一次地自我注册
  • 请不要在 cmets 中发布其他信息,而是编辑您的任务以包含它。
  • 注意-我刚刚尝试在 firebase 中手动输入令牌。当我将节点的名称与令牌相同并在节点内部时,我创建一个新的值名称,其令牌和值与令牌相同。然后我收到通知。 i.stack.imgur.com/hMRx7.png(Image链接)

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


【解决方案1】:

不确定,但尝试替换

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

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

【讨论】:

    【解决方案2】:

    根据您数据库中的provided screenshot,您数据库中/fcm-token下面的数据有两种不同的格式。

    当您手动添加数据时,您使用了以下格式:

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

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

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

    在您的 Cloud Functions 代码中,您使用 Object.keys(allToken.val()) 将存储在 /fcm-token 下的所有键收集到一个数组中,这将为您提供一个包含推送 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);
        }
      });
    

    【讨论】:

    • 客户端代码给了我 nullpointerException java.lang.RuntimeException: Unable to start activity ComponentInfo{com.jk.jkjwellers/com.jk.jkjwellers.ui.splashScreen.SplashScreenActivity}: java.lang.NullPointerException:无法在 child() 中为参数“pathString”传递 null
    • @tusharkumar 客户端代码是从您的问题中复制的。 FirebaseInstanceId#getToken() 显然已被弃用,所以我用现代方式更新了答案以获取令牌。
    • 更改客户端代码后。我以“SOmetoken:true”的形式获得了令牌但是当我从 node.js 获取令牌的价值时。它给了我非空字符串的错误。因为它没有子 fcmToken 或令牌。?请同时提供解决方案触发器。对不起这个问题。但这是我第一个使用 node.js 和 firebase 的程序。
    猜你喜欢
    • 2017-10-29
    • 2017-10-08
    • 2020-05-26
    • 2017-11-16
    • 1970-01-01
    • 2019-07-20
    • 2018-02-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多