为什么我使用Google的云到设备消息服务,会得到多个活动Token?

7
我刚为我的Android应用程序添加了C2DM功能。
目前,如果在我的应用程序中启动C2DM,将发生以下情况:
1. 我的应用程序发送注册Intent 2. 我的应用程序接收到答案广播 3. 从Intent中检索设备令牌并将其发送到我的服务器 从那时起,一切都正常运作。客户端可以接收推送通知等。 如果发生以下情况,就会出现问题: 4. 用户删除应用程序而不禁用推送(完全删除它而不仅仅是更新) 5. 用户重新安装应用程序
如果在第5步之后发送推送通知,我的应用程序仍然会接收此通知。 似乎从先前安装中检索的令牌仍然处于活动状态,并重新连接到应用程序的新实例。
这导致了以下问题:
用户重新安装我的应用程序但不打算接收推送通知,则无法从服务中删除自己,因为应用程序的新实例无法取消注册旧令牌。
这是C2DM系统中的一个错误还是我的设置有问题?

我按照Berdon的建议做了以下事情:

仅用于测试目的,每次启动我的应用程序时启动未注册的意图。发送未注册的意图后,我的服务器不会向我的应用程序发送任何推送通知。这似乎起到了作用,但是如果我现在进入C2DM设置屏幕并为我的应用程序打开推送通知,则所有旧令牌都会重新激活,并且我会收到当前安装的应用程序中没有注册的信息。

下一个更新

看来我不是唯一遇到这个问题的人:

Android C2DM:同一设备和应用程序的重复消息

我希望Google以某种方式管理那些令牌,使得在发放新令牌后,来自同一设备的旧令牌被禁用。我还期望,在发送未注册的意图后,该应用程序和该设备的所有令牌都被标记为无效或从Google服务器永久删除。如果这是Google针对特殊用例的设计决策,我不明白,请给我指点。


我正在尝试自己实现C2DM。我的方法是确保用户在我的应用服务器上注册。如果他们卸载了应用,将会“禁用”他们在我的应用服务器上的账户,如果他们重新安装,则必须重新注册(重新启用)他们在我的应用服务器上的账户。这样,即使令牌有效,您也可以控制何时以及是否向他们推送通知。 - John J Smith
@John 你如何知道用户卸载了你的应用程序? - Janusz
3个回答

4
我们现在找到了一个解决方案,应该适用于大多数情况。服务器将C2DM注册ID作为数据字段添加到每个C2D消息中。现在,只有当消息中的标记和存储在pref文件中的标记匹配时,设备才会显示通知。这样,我们可以保证不会为以前安装获取的设备令牌显示消息。如果标记不匹配,则说明我们找到了一个不再活跃的旧标记。我们现在将自己的Web服务器上的标记标记为非活动状态,以防止服务器发送更多不必要的C2D消息。这个解决方案使我们能够只显示相关数据,而无需存储唯一的用户ID。

这样我们就可以保证不会显示之前安装获取的设备令牌的消息。但是当我们卸载应用程序时,保存在Pref中的令牌也会消失。那么最好的保存令牌的方法是什么? - anticafe
令牌已保存在后端。如果用户重新安装应用程序并激活推送,他将获得一个新的令牌,但旧的令牌也会接收到推送。我只知道新的令牌,通过发送旧的令牌与推送一起,我能够过滤所有发送到“错误”令牌的消息。现在,我可以从消息中提取错误的令牌并将其从我们的后端中删除。 - Janusz

3
在我的C2DM实现中,每个用户的设备令牌都保存在数据库中,与他们的UDID和应用程序的包名称(以及其他信息)相关联。UDID和包名称组成主键,这意味着该表可以列出来自同一设备(UDID)的多个应用程序。当用户运行特定的应用程序时,设备令牌被记录下来,如果他们卸载并重新运行应用程序,则新的设备令牌将覆盖旧的设备令牌。我们还有列来记录是否为特定应用程序/设备组合激活推送,以及用户启用/禁用哪些类型的推送消息。
当需要为特定应用程序发送推送时,没有任何UDID会注册超过一次(因为这两个字段组成主键),因此只使用最新的设备令牌。此外,我们的查询仅返回启用推送消息的行。
这个解决方案应该可以解决你的问题,因为它可以防止你向两个设备令牌发送推送。希望这可以帮助到你!

我认为你的解决方案是唯一的方法,但我希望能够避免生成除设备令牌以外的东西来识别我的用户。你如何获得UDID的有效值? - Janusz
1
最终的TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE); String deviceID = tm.getDeviceId();您需要READ_PHONE_STATE权限。此外,在研究该主题时,我刚刚了解到getDeviceId()仅适用于手机,因此不适用于平板电脑。请参见https://dev59.com/CnE95IYBdhLWcg3wadOq - Robert Peacock
回复Robert Peacock对Janusz的回复...如果可以的话,我建议使用Android_ID而不是getDeviceId。请参见下面的Stackoverflow链接,了解一个返回ID的最佳方法的优秀例程。https://dev59.com/_2445IYBdhLWcg3wAFi0 - RickR

1
更像是一个意外的“特性”。您可能考虑在应用程序的“第一次运行”(第一次运行)时发出注销请求,以防止发生这种情况。
更新 您可以通过使用collapse_key(或您自己创建的任何内容)作为标识符来区分不同的C2DM消息。在注册、注销和消息之后更新它,并将其传递给设备。

我尝试过了,但似乎只有在我没有注册新令牌的情况下,该令牌才无效。 - Janusz
你做对了吗?http://code.google.com/android/c2dm/#unregistering 无论如何,在注销后,如果用户选择不接收C2DM,则只需忽略任何到达的消息-这处理了注销实际上存在错误的情况-顺便说一句,我没有亲眼观察到。 - Austin Hanson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接