处理FCM设备组的刷新令牌

我正试图通过Node.js服务器在我的Android应用程序中实现Firebase云消息传递,并且我已经陷入了一个用例。

我看到了使用注册令牌创建设备组的Firebase教程,以便在登录相同用户的情况下向所有设备发送消息/通知,我不明白当其中一个注册令牌被onTokenRefresh()方法刷新时会发生什么。

如何区分要更改的令牌,因为所有令牌都属于同一个用户?

更新:

好的,所以现在我又陷入了另一个阻塞用例。 我正在创建一个由我的服务器中的用户ID标识的用户组。 如果用户立即卸载并重新安装应用程序而另一个用户登录设备,如果我在之前的用户组上调用gcm消息,则此设备仍会收到该消息。

gcm是否有任何方法可以识别发送通知的设备是否已登录?如果是,是否使用与该组相同的用户登录?

所以我一直在考虑如何使用这种情况。 首先,让我们在调用onRefreshToken()时放入实例:

这不会被频繁调用 ,需要进行密钥轮换并处理实例ID更改,原因如下:

  • 应用程序删除实例ID
  • 应用程序在新设备上恢复
  • 用户卸载/重新安装应用程序
  • 用户清除应用数据

猜猜一下,你可以说’onTokenRefresh()`将在上面发生之后被调用,如果设备在线( 当然它必须在线以获得新的令牌 )。 所以我猜这是我如何继续这个场景:

首先,在注册时,我会保存注册令牌并将其与另一个标识符配对,假设我的App Server 中有一个deviceId( 因为我们处于具有多个设备的用户的场景中 )。

因此,假设我添加了3个注册令牌,这些令牌也与他们的deviceIds配对。 我将它们全部添加到设备组。

现在说其中一个设备触发onTokenRefresh() ,我会立即向我的App Server发送一个删除请求,用于当前与该deviceId配对的注册令牌(您还应该在它连接到的任何设备组中将其删除) ),用新的替换它,然后将其重新添加到相应的设备组。

这是我能想到的最简单的方式。 这里的关键是您将注册令牌与另一个标识符配对,并使用它来查找您需要替换的注册令牌。

我现在使用这种方法。 在我的数据库中,我创建一个带有设备ID的节点

 deviceId: { uid1: deviceId, uid2: deviceId, uid3: deviceId } 

订阅用户的另一个节点接收通知

 newsSubscriber: { uid1: [array of subscribers], uid2: [array of subscribers], uid3: [array of subscribers] } 

当我可以通过我的nodejs脚本发送通知时,我获得保存在newsSubscriber节点中的所有用户,并且对于任何用户,我获得了他的deviceId,并将其放入设备数组中以发送通知。 只有一个问题,我现在读到,在这种模式下,只有20个设备限制

但我认为这是一个很好的方法,可以为任何用户提供相应的deviceId,因为当我在我的应用程序中使用注销或登录时,我可以为任何用户更改相应的deviceId,以便在用户和设备之间保持一致。

如果绕过20个设备的限制会发生什么情况我将相同的通知发送到20个设备的不同组?

还有另一种使用Cloud Firebasefunction解决此问题的方法。

如何区分要更改的令牌,因为所有令牌都属于同一个用户?

使用Firebasefunction,您不必。 在onTokenRefresh()中,您将新令牌发送到服务器。

例如:

用户有3个设备,每个设备都有一个已发送到服务器的令牌。

*** deviceTokenA / B / C表示令牌的UID …我们不知道它们是什么,或者它们属于哪个设备。

 UserId: Device Tokens: deviceTokenA: true, deviceTokenB: true, deviceTokenC: true, 

现在,用户位于触发deviceTokenA的设备上。 令牌被刷新,并且调用onTokenRefresh(),将令牌发送到该集合。

 onTokenRefresh() { String refreshedToken = FirebaseInstanceId.getInstance().getToken(); sendTokenToServer(refreshedToken); } sendTokenToServer(String refreshedToken) { // send to Firebase or Firestore Database, put in the Device_Tokens collection. } 

现在,您将在该集合中拥有4个令牌。

  UserId: Device Tokens: deviceTokenA: true, // this one has been "unregistered" deviceTokenB: true, deviceTokenC: true, deviceTokenD: true, // this one has been registered. 

deviceTokenA不再适用,因为它已刷新,并且不再附加到实际设备。

在查看设备令牌时,我们仍然不知道哪些是好的,哪些是坏的,以及哪些令牌属于哪个设备。 没关系!

因此,然后创建一个forEach循环,获取每个令牌,然后向每个令牌发送FCM,FCM可以告诉我们哪些令牌已成功发送。 其中一个将返回错误。 如果它返回一个错误,说明令牌是坏的,我们就可以捕获错误并删除该令牌,因此不会再次调用它。

 // outside for Each loop var promiseHolder = []; // create a forEach loop, iterating through the collection of deviceTokens // within that loop, put: let innerPromise = admin.messaging().send(message) .then(response => { console.log('notification sent success: ' + response); }) .catch((error) => { console.log('Error sending notification: ' + error); // if the error == bad token message, then Delete the Token. if (error == 'Error: Requested entity was not found.') { console.log('you matched the error, token doesn't work, handle here.'); //delete the old token return admin.firestore()doc(`users/${userID}/device_tokens/${token_id}`).delete(); } } // still within forEach loop promiseHolder.push(innerPromise); // end the forEach Loop, and outside forEachLoop put: return Promise.all(promiseHolder);