GCM 推送通知的问题

Posted

技术标签:

【中文标题】GCM 推送通知的问题【英文标题】:Issues with GCM Push Notifications 【发布时间】:2015-03-09 15:28:28 【问题描述】:

对于关于 *** 的第一个问题,我将询问 Google Cloud Messaging 服务,尤其是 Loopback 的实现。

所以,我正在开发一个应用程序并开始在不同的分支上工作,以介绍 Loopback 的推送通知处理以及它是用于 REST Api 的各种工具。即使本主题将严格涵盖 Loopback 处理 GCM 的方式,该问题也与 Google 文档中描述的原始方式有关。

因此,GCM 启动背后的主要思想是检查设备是否已注册。

这是通过对 SharedPreferences 变量(用于存储我们的 RegistrationID 值的名称)的简单检查来完成的。

final LocalInstallation installation = new LocalInstallation(context, adapter);

如果找到,设备必须通知服务器,传送令牌。 否则,必须向 GCM 注册。 完成此操作后,设备会通知服务器。 (registerInBackground(installation) 在检索到 RegistrationId 后最终会调用saveInstallation(installation)

    if (installation.getDeviceToken() != null) 
        saveInstallation(installation);
     else 
        registerInBackground(installation);
    

如果通信成功,设备如上所述使用 SharedPreferences 保存 RegistrationId。 (注意:getDeviceToken() 是 Loopback 通过 API 处理 SharedPreferences 中的值的方式)

假设每次创建 MainActivity 时都会执行此“GCM-Check”(因此,在 onCreate 方法期间)。

我们也知道 GCM 有时会很混乱,并且想要刷新我的应用程序的 RegistrationId 或其他一些东西,老实说,我现在还不完全清楚。简而言之,GCM 使我的应用程序的令牌无效。当服务器使用绑定到我的设备应用程序的令牌发送推送通知时,这会导致错误消息。

类似的错误

"multicast_id":0123456789012345678,"success":0,"failure":1,"canonical_ids":0,"results":["error":"NotRegistered"]

你可以看到"failure":1"results":["error":"NotRegistered"]

Loopback 的反应就像 Google 文档所说的那样,让服务器删除与错误 RegistrationId 相关联的设备的记录。 可以理解。

回到我们的设备。再次启动我的应用程序并加载 MainActivity,会导致相同的“GCM-check”过程。这次应用可以使用 SharedPreferences 找到 RegistrationId,并可以直接通知服务器,服务器使用给定的 RegistrationId 创建一条记录。

设备应用程序没有处理新的注册。

你可以在这里看到循环。设备将不知道自己的token无效,并继续告诉服务器相同的数据,服务器会不断向错误的registrationId发送信息,从而在收到相关错误后将其删除。

问题在于应用程序必须依赖创建一次且永远不会被修改的数据。要删除旧数据,我应该向设备发送通知,这显然是不可能的,因为我无法从 GCM 访问它。其他可能的解决方案是通过发送电子邮件或短信通知用户,并要求他单击按钮,但我宁愿采用更“自动化”的方法来解决问题。


我发现了一个非常糟糕的解决方案

据我所知,在推送通知期间唯一的错误信息是从 GCM 返回到服务器的,我在设备上做了一些小改动。

这个想法很简单:向 GCM 服务器创建一个 POST 请求,使用我的服务器应该用来进行身份验证的标头。这会导致将错误提供给设备本身,它可以解析 JSON 并注意发生了什么。应用程序可以从这里创建一个新的注册流程,从而解决问题。

这有什么不好?事实上,要将设备验证为服务器,我必须对 ServerKey 进行硬编码并将其分发到每个应用程序中。 ServerKey 应该只在服务器上使用,这使得这个解决方案非常糟糕。


话虽如此,使用 SharedPreference 值简单地让设备知道其状态的想法并不是很好,因为它只会告诉我是否至少注册过一次,而不会让我知道我的当前状态。

在我开发的其他同样使用 GCM 的应用程序上,我以不同的方式解决了问题,例如让用户单击按钮或读取服务器发送的一些特殊 SMS,然后启用 @987654321起初@,最后GoogleCloudMessaging.register()


那么,为这样的文字墙请求宽恕,你是如何解决这个 NotRegistered 的事情的?

感谢您在阅读和回答时付出的努力和时间:)

【问题讨论】:

不只是检查令牌是否存在于 SharedPreferences 中,您可能还应该检查令牌用于的应用程序版本是否与正在运行检查的当前版本匹配(即来自谷歌的文档)。如果不是,您应该请求一个有效的令牌(实际上可能是相同的,但不能保证)。现在,您可能还想检查 PACKAGE_REPLACED 广播(以防您每次安装测试时都没有增加清单中的版本,我对此感到非常内疚),然后您还应该请求一个新令牌为。 我不得不承认,在此 Loopback 的应用程序配置期间,我没有处理 AppVersion 检查(Loopback 的文档中没有描述,所以我认为它的 SDK 不需要它),而我在另一个我提到的应用程序。是的,感觉就像我和你声称的一样有罪。但是你能不能更好地告诉我,不断的测试部署阶段是如何让我遇到这个麻烦的?这个 NotRegistered 错误不是总是弹出,而是实际上有点不稳定和零星。我确实看到了正确卸载应用程序背后的原因,但是对于包替换/更新......不是真的 I do see the reason behind a proper Uninstall of the app, but for package replace/updates ... not really :: 为了更好地澄清自己,正如 Google 要求的那样,即使在应用更新之后,RegistrationId 也必须更新。但是测试/调试安装(因为这是针对您谈到的 PACKAGE_REPLACED 广播)如何创建这样的案例? 我同意,这完全是零星的。有时 PACKAGE_REPLACED 之后的新请求返回相同的键;有时它不会。那些让它变得奇怪的人之间会发生什么?上帝,我很想知道,我希望我有更多的信息。但这就是我提到试图捕捉该广播的部分原因:在它发生时强制检查应该确保你总是得到一个新的有效的(如果版本检查不应该通过)如果它可用 你好,Guardanis。我已将您的建议带入测试阶段,感觉是解决我问题的好方法。如果您想发表您的评论作为答案,我很乐意将其标记为已接受:) 【参考方案1】:

作为我的 cmets 的附录,因为它有帮助,而且我在这里有更多空间:

不只是检查令牌是否存在于您的 SharedPreferences 中,您还应该检查该令牌所针对的应用版本是否与当前运行检查的版本相匹配(这是来自 Google 文档的建议)。

如果设备版本不匹配,您应该请求一个有效的令牌(实际上可能相同,但不能保证)。现在,您可能还想检查 PACKAGE_REPLACED 广播(以防您每次安装测试时都没有增加清单中的版本,我对此感到非常内疚),如果触发,也应该迫使您请求一个新的令牌。

至于为什么令牌有时会发生变化,有时不会:我完全同意这完全是零星的,并且不禁觉得发生了一些我们并不真正了解的事情。

有时 PACKAGE_REPLACED 之后的新请求返回相同的键;有时它不会。那些让它变得奇怪的人之间会发生什么?上帝,我很想知道,我希望我有更多的信息。但这就是我提到尝试捕获该广播的部分原因:在它发生时强制检查应该确保你总是得到一个新的有效的(如果版本检查不应该通过),如果它可用的话。

希望对你有帮助~

【讨论】:

以上是关于GCM 推送通知的问题的主要内容,如果未能解决你的问题,请参考以下文章

限制发送推送通知(防止垃圾邮件) - GCM

在 GCM 中未收到推送通知

GCM 推送通知的问题

发送少量通知后未从 GCM 收到推送通知

Android 从 GCM 迁移到 oneSignal 推送通知

使用 GCM、PHP 和 MySQL 的 Android 推送通知