处理 FCM 设备组的刷新令牌
Posted
技术标签:
【中文标题】处理 FCM 设备组的刷新令牌【英文标题】:Handling refresh tokens for FCM device groups 【发布时间】:2017-03-01 14:43:53 【问题描述】:我正在尝试通过 Node.js 服务器在我的 android 应用程序中实现 Firebase 云消息传递,但我遇到了一个用例。
我看到了使用注册令牌创建设备组以向同一用户登录的所有设备发送消息/通知的 Firebase 教程,我不明白当其中一个注册令牌被 onTokenRefresh 刷新时会发生什么() 方法。
我将如何区分要更改的令牌,因为所有令牌都属于同一用户?
更新:
好的,所以现在我陷入了另一个阻塞用例。我正在创建一个由我的服务器中的用户 ID 标识的用户组。如果用户立即卸载并重新安装应用程序并且另一个用户在设备上登录,如果我在以前的用户组上调用 gcm 消息,该设备仍然会收到它。
gcm 有什么方法可以识别它发送通知的设备是否已登录,如果已登录,它是否使用与组相同的用户登录?
【问题讨论】:
【参考方案1】:还有另一种方法可以使用 Cloud Firebase Functions 解决此问题。
我将如何区分要更改的令牌,因为所有人都属于 给同一个用户?
使用 Firebase 函数,您不必这样做。在 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 不再适用,因为它已被刷新,并且不再附加到实际设备。
在查看设备Token时,我们仍然不知道哪些是好的,哪些是坏的,哪些令牌属于哪个设备。没关系!
那么,然后创建一个forEach循环,获取每个Token,然后给这些Token中的每一个发送一个FCM,FCM可以让我们知道哪些token发送成功了。其中之一将返回错误。如果它返回一个错误,说明令牌是错误的,我们可以捕获错误并删除该令牌,因此不会再次调用它。
// 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);
【讨论】:
您在admin.firestore()
之后缺少.
,并且在.catch
语句的末尾也缺少)
。没有它,我的代码将无法工作。【参考方案2】:
所以我一直在考虑如何处理这种情况。首先,让我们放入调用onRefreshToken() 的实例:
这不会被非常频繁地调用,它是密钥轮换和处理实例 ID 更改所必需的,原因如下:
应用删除实例 ID 应用已在新设备上恢复 用户卸载/重新安装应用程序 用户清除应用数据
你猜,你可以说'onTokenRefresh()`将在上述情况发生并且设备在线后被调用(当然它必须在线才能获得新令牌 em>)。所以我想这就是我将如何处理这个场景:
首先,在注册时,我会保存注册令牌并将其与另一个标识符配对,比如说一个 deviceId(因为我们处于一个用户拥有多个设备的场景)应用服务器。
假设我添加了 3 个注册令牌,它们也与它们的 deviceId 配对。我将它们全部添加到设备组中。
现在说其中一个设备触发了onTokenRefresh()
,我会立即向我的应用服务器发送一个删除请求,以获取当前与该 deviceId 配对的注册令牌(您还应该在任何设备组中将其删除)已连接),将其替换为新的,然后将其重新添加到相应的设备组中。
这是我能想到的最简单的方法。这里的关键是让您将注册令牌与另一个标识符配对,并使用它来查找您需要替换的注册令牌。
【讨论】:
@AL.你能告诉我你用什么作为 deviceId 吗? @amarok 我也有这个问题。请参阅:网络版 - ***.com/a/10747/3114383 安卓版:developer.android.com/reference/android/telephony/… 或 developer.android.com/reference/android/net/wifi/… 这个解决方案很有意义,但是你用什么来设置 deviceId? @JeffPadgett 现在,我仍然使用ANDROID_ID
,尽管它不再适用于 Android O 及更高版本。我还没有找到一个很好的替代品。
谢谢,我也在使用 ANDROID_ID。这是不可取的,但在这种情况下它似乎仍然有效。 Android 8.0 将对其进行修改并使其 ANDROID_ID 与应用签名密钥和设备组合相关联,这使用户更安全,但允许开发人员获得即使在卸载和重新安装后仍然存在的设备 ID。我认为只要我们不将其用于第 3 方、出售或用于广告跟踪,就可以。【参考方案3】:
目前我使用这种方法。在我的数据库中,我创建了一个带有设备 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 台设备的不同组发送相同的通知会发生什么?
【讨论】:
以上是关于处理 FCM 设备组的刷新令牌的主要内容,如果未能解决你的问题,请参考以下文章