处理多个设备、同一用户的 GCM 注册 ID
Posted
技术标签:
【中文标题】处理多个设备、同一用户的 GCM 注册 ID【英文标题】:handling GCM registration ID's for multiple devices, same user 【发布时间】:2014-08-05 13:18:58 【问题描述】:这是许多应用程序面临的常见情况,但我正在努力了解如何实施:
假设我的应用程序是一个具有当前登录用户的社交网络。 我想为他当前使用我的应用登录的所有设备向该用户发送 GCM 消息。
这意味着我的服务器为每个用户保存了他所有注册 ID 的列表 - 他的每台设备都有一个。
问题:我怎样才能唯一地跟踪他的每一台设备? seems there is no reliable way to get specific device identifier
没有为每个唯一设备存储注册 ID - 我不知道如何管理它。
当用户卸载/注销并在之后获取新的注册 id 时,事情会变得一团糟,假设要替换现有的已知 id 之一,但是其中哪一个呢??
如果我只想向特定设备而不是所有设备发送消息,事情会变得更加成问题......
请帮助我了解我缺少什么,以及为同一用户处理多个设备注册 ID 的正确方法是什么。
【问题讨论】:
我不明白你在问什么。是的,服务器保存了所有的注册ID,有什么问题? @XaverKapeller:这意味着如果用户注销并使用相同的用户和设备重新登录 1000 次,那么我的服务器会向谷歌云发送 999 个冗余 ID?? 为注册到您的服务器的每个设备创建一个 UUID。您无需担心设备唯一键。创建 UUID 后,将其保存到共享首选项,并且用户的 reg id 更改随时将其发送到具有保存的 UUID 的服务器 @TalKanel 不,谷歌处理了大部分。如果有变化,您只需删除多余的并插入新的。你真的不必担心这个。 @TalKanel 我刚才正在写一个答案,演示如何处理这个问题。 【参考方案1】:在使用 GCM 时,Google 会为您处理几乎所有繁重的工作。他们提供了一种简单的方法来始终使注册 ID 保持最新。每条发送的消息都有一个名为canonicalRegistrationId
的额外字段。如果该字段中有 id,则注册 id 已更改并需要更新。此字段存在于每条消息中,每次发送时,您都必须检查该字段。如果有新的canonicalRegistrationId
,那么您应该尽快更新registrationId。旧的可能会继续工作一段时间,但不知道什么时候失效。
例如,在 Google App Engine 后端中,处理注册 ID 变化的代码如下所示:
// We want to send a message to some devices
// Get registered devices and then loop through them
List<RegistrationRecord> records = ofy().load().type(RegistrationRecord.class).limit(10).list();
for(RegistrationRecord record : records)
// Send the message to one device
Result result = sender.send(msg, record.getRegId(), 5);
// If the messageId is not null, then the message has been sent successfully
if (result.getMessageId() != null)
log.info("Message sent to " + record.getRegId());
// Check for canonical message id
// If it is not null, then the registrationId has changed
String canonicalRegId = result.getCanonicalRegistrationId();
if (canonicalRegId != null)
// The registrationId has changed! We need to update it in the database
log.info("Registration Id changed for " + record.getRegId() + " updating to " + canonicalRegId);
record.setRegId(canonicalRegId);
ofy().save().entity(record).now();
else
... // Irrelevant error handling
所以你要做的很简单:每次发送消息时,检查是否有canonicalRegistrationId
,如果有,则将旧的registrationId更新为规范的。
【讨论】:
但是你可能会有多个 RegistrationRecord 持有相同的注册 ID。对吗? 因为如果您的“foreach”迭代看到一条具有规范 id 的记录,该记录实际上与创建前一条记录后客户端提供时生成的其他记录相同.. 我知道注册ID是唯一的。我提到可能会发生以下扫描: 1)电话生成新的注册 id = [x],并将此 id 发送到服务器。 2)服务器创建RegistrationRecord,它的注册id = [x]。 3) 手机由于某种原因获取新的注册id = [y],并将其发送到服务器。 4)服务器存储新的RegistationRecord,它的注册id = [y]。 5)服务器迭代所有注册记录,当调用 regId [x] 的 sender.send() 方法时,它得到响应 canonicalRegId = [y]。 6)根据您的代码-服务器将此记录注册ID更改为[y]。现在您将有两条记录,其中包含 regId = [y]。我哪里错了?? @TalKanel 是对的,如果注册 ID 发生了变化,那么可能是客户端通知了服务器,服务器将其添加到列表中。因此,您的代码中的解决方案应该很简单:删除旧的注册 ID 并添加新的仅当它尚不存在时。【参考方案2】:Google 支持设备群发消息。参考这个链接:https://developers.google.com/cloud-messaging/notifications#managing_device_groups
要处理多个用户,您可以为该用户创建一个组并将注册 ID 添加到该组。要创建群组,请向https://android.googleapis.com/gcm/notification发送如下请求:
Content-Type:application/json Authorization:key=API_KEY project_id:SENDER_ID
"operation": "create", "notification_key_name": "appUser-Chris", "registration_ids": ["4", "8", "15", "16", "23", "42"]
此 API 会返回一个通知密钥作为响应,您可以将其存储在您的数据库中,然后用于向该组发送通知。随后,每当用户登录到其他设备时,您都可以获得该设备的reg_id
并将其添加到组中。要将注册 ID 为 51 的设备添加到 appUser-Chris
,您可以发送以下请求:
"operation": "add", "notification_key_name": "appUser-Chris", "notification_key": "aUniqueKey", "registration_ids": ["51"]
当用户退出设备时,您可以从组中删除reg_id
。
向群组发送通知与向注册 ID 发送通知相同。
我在这里观察到的一个问题是,如果您在创建组时未能将notification_key
存储到您的数据库中,那么您将无法再次获取它。并且无法再次为同一 notification_key_name
创建新组。解决此问题的方法是明智地选择您的notification_key_name
。因此,当您未能存储notification_key
并再次尝试创建具有相同noitification_key_name
的组时,您将收到错误消息。在这种情况下,您只需更改该用户的notification_key_name
并创建一个新组。希望这会有所帮助。
【讨论】:
【参考方案3】:我认为您必须获取设备 IMEI 编号并将其保存到您的服务器,并使用注册 ID 并且当用户使用其他设备重新注册他自己时,然后获取检查 IMEI 号码将其替换为旧设备。主要的事情现在在旧设备中上升检查发送 IMEI 号和消息,如果 IMEI 号匹配则没有问题,否则阻止应用程序。并通知用户...
就是这样……
【讨论】:
是否有可能某些 Wi-Fi 平板电脑没有 IMEI? @hanamj :是的,这是可能的。以上是关于处理多个设备、同一用户的 GCM 注册 ID的主要内容,如果未能解决你的问题,请参考以下文章
Android GCM 一台设备有多个registrationid