8

在 Android 设备上注册/注销 GCM 消息时,我注意到一些奇怪的行为。从客户端设备的角度观察以下用例:

  1. 注册 GCM -分配的 ID A
  2. 注销
  3. 注册 GCM -分配ID B

如果在第 2 步之后,服务器尝试向 ID A发送消息,它将收到一个NotRegistered错误,正如文档中所记录的和预期的那样。

但现在奇怪的是:在第 3 步之后,ID AB都是有效 ID!这两个 ID 都会触发设备上的 Intent 接收器,从而向应用程序发送两条消息。

这种行为是预期的还是我做错了什么?

这是我的注册和注销代码,从onCreate()我的应用程序上启动的第一个活动触发:

 public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     unregister(getApplicationContext());
     register(getApplicationContext());
}


/** Registers this device for GCM messages */
public static void register(Context context) {
    GCMRegistrar.checkDevice(context);
    GCMRegistrar.checkManifest(context);
    String regId = GCMRegistrar.getRegistrationId(context);
    if (regId.equals("")) {
        GCMRegistrar.register(context, SENDER_ID);
    } else {
        storeRegId(regId); // Also notifies back-end
    }
}

public void unregister(Context context) {
    GCMRegistrar.unregister(context);
}

注意 1:我只包含了 unregister()-call 用于调试目的。我的应用程序通常保持“终身”注册状态(我也想在暂停和终止时接收 GCM 消息),但我仍然想找出这种行为的原因,因为我不确定取消注册是否是唯一的情况ID 被重新生成。如果用户卸载并重新安装应用程序怎么办?我想要一个防弹系统——我的用户永远不会收到两次相同的 GCM 消息。

注意 2:问题与此非常相似,只是我确实getApplicationContext()按照答案建议进行了注册。

4

2 回答 2

4
  1. 当您取消注册时,您应该将旧的注册 ID 发送到您的服务器并将其从您的数据库中删除。

  2. 假设您未能执行第 1 步,如果在注册并获得新注册 ID 后您发送带有旧注册 ID 的消息,则来自 Google 的响应将包含一个规范注册 ID(即新注册 ID)。此响应表明您的服务器应删除旧的注册 ID 并仅使用新的注册 ID。

于 2013-05-01T15:39:42.717 回答
1

我遇到了类似的问题,并且相信我已经将正在发生的事情拼凑起来并制定了一个混合解决方案。不幸的是,它仍然不是防弹的,尽管它适用于我的情况(稍后会详细介绍)。

以下是我相信您所看到的:

  • 情况 1:您的第 3 方服务器在您的第 2 步之后但在第 3 步之前发布一条 GCM 推送消息(即您的服务器已发送设备 ID-A 的消息并收到未注册的情况)。根据 Google 的文档,您的 GCM 设备客户端报告说没有为该消息配置广播接收器(因为它当前已被卸载)。如您所料,这具有从 GCM 服务中取消注册 ID-A 的效果。

    这是一个SO 帖子,描述了此案例的 GCM 注销过程。

  • 情况 2:您的应用程序已被卸载然后重新安装在设备上,而在此期间没有 GCM 推送消息。在这种情况下,分配了一个新的 GCM ID,但 GCM 服务永远不会提醒缺少广播接收器,因此两个 ID 仍然有效,并且它们都可以交付给设备。这被 GCM 服务报告为重复的 registration_id。

在这两种情况下,GCM 服务都会报告问题,并且可以在事后处理清理工作。

有关 GCM 服务反馈的非常好的解释,请参阅此SO 帖子

不幸的是,如果您希望确保只传递一次消息,事后可能为时已晚。经过一番搜索,我想我必须得出结论,不能完全肯定地防止这种情况,但你可以做得更好一点。我建议您还管理 3rd 方服务器上的注销,而不是期望 GCM 服务专门处理它。我通过确保每个新设备发送/保存一个唯一的设备 ID 以及 GCM 分配的 ID(即 pair )来做到这一点。然后,如果同一设备因任何原因(即)被分配了一个新 ID,第 3 方服务器可以识别该案例并停止使用 ID-A,而不是等待 GCM 服务在之后提醒您注意重复。重复交付。

现在,为什么我不特别喜欢那个解决方案?几个原因:

  1. 对于已经存在于野外的实例,没有迁移路径——我们必须假设这些 id 可能保持有效,直到我们发现其他情况。除非通过应用程序更新(我无法强制),否则我不能强迫他们在我的第 3 方服务器上重新注册他们的 GCM id。
  2. 对于那些经过应用程序更新的设备,他们可以将他们的 deviceId 和当前GCM ID 传输到我的第 3 方服务器,但他们不知道任何可能在卸载/重新安装周期中丢失的 ID。正是那些“丢失”的 ID 可能会在未来造成麻烦——但如果您使用上面那个 SO 链接中描述的服务反馈,那么只有一次。
  3. 确定唯一的 deviceId 本身就是有问题的。只需在 StackOverflow 上搜索有关唯一 Android 设备 ID 的讨论,即可查看...
于 2015-06-03T21:39:27.247 回答