GCM推送通知问题

3

对于我在StackOverflow上的第一个问题,我想问关于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(即在onCreate方法期间)时都进行“GCM-Check”。
我们也知道,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的记录。
设备应用程序不处理新的注册。
你可以在这里看到循环。设备将不知道它的令牌无效性,并继续向服务器发送相同的数据,服务器将继续向错误的RegistrationId发送信息,因此在收到相关错误后将其删除。
问题是应用程序必须依赖于一次创建而永远不会修改的数据。要删除旧数据,我应该向设备发送通知,但显然无法从GCM到达它。其他可能的解决方案是通过发送电子邮件或短信通知用户,并要求他例如单击按钮,但我更希望采用更“自动化”的方法来解决问题。

我找到的一个非常糟糕的解决方案

据我所知,唯一的错误信息是在推送通知期间从GCM返回到服务器的,因此我对设备进行了一些小修改。

这个想法很简单:创建一个POST请求到GCM服务器,使用服务器应该使用的标头进行身份验证。这会导致错误被发送到设备本身,它可以解析JSON并注意到发生了什么。从这里,应用程序可以伪造一个新的注册过程,修复问题。

这有什么不好的地方? 事实上,为了将设备验证为服务器,我必须硬编码ServerKey并在每个应用程序中分发它。ServerKey应该仅在服务器上使用,使这个解决方案成为一个非常糟糕的想法。


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

在我开发的其他应用程序中,同样使用GCM,我采用了不同的解决方案,例如提供一个供用户点击的按钮或读取服务器发送的某些特殊短信,然后首先启用 GoogleCloudMessaging.unregister(),最终启用GoogleCloudMessaging.register()


那么,关于这个冗长的问题,你是如何解决这个“NotRegistered”问题的?

感谢您花费时间阅读和回答:)


不仅要检查SharedPreferences中是否存在令牌,还应该检查该令牌所属的应用程序版本是否与正在运行检查的当前版本匹配(这是来自Google文档的)。如果不匹配,则应请求有效的令牌(实际上可能是相同的,但不能保证)。现在,您可能还想检查PACKAGE_REPLACED广播(以防您没有在每次安装测试时递增清单中的版本,我非常有罪),然后还应请求新的令牌。 - Cruceo
我必须承认,在这个Loopback应用程序配置期间,我没有处理AppVersion检查(在Loopback的文档中没有描述,所以我认为其SDK不需要),而我在其他提到的应用程序上有处理。是的,感觉就像你所说的那样,我也有罪。但是你能告诉我更好的方法吗?这个不断测试部署阶段是如何让我遇到这个问题的?这个NotRegistered错误并不总是出现,而是相当不稳定和零散的。我确实看到了正确卸载应用程序的原因,但对于包替换/更新...并不是很清楚。 - FrancescoC
我确实理解应用程序进行适当卸载的原因,但对于包替换/更新...并不是很清楚。为了更好地澄清自己,就像谷歌要求的那样,在应用程序更新后,RegistrationId必须得到更新。但是测试/调试安装(因为这是你所说的PACKAGE_REPLACED广播的情况)如何创建这样的情况呢? - FrancescoC
我同意,它是完全零散的。有时在PACKAGE_REPLACED之后的新请求返回相同的密钥; 有时不会。在这些之间发生了什么使它变得奇怪?天啊,我真希望知道,并且我希望我对此有更多信息。但这就是为什么我提到尝试捕获该广播的一部分:在发生这种情况时强制进行检查应确保您始终获得新的有效信息(如果可用,则在版本检查不通过时)。 - Cruceo
再次问候Guardanis。我已经将您的建议放到测试阶段,并且感觉这是解决我的问题的好方法。如果您想将您的评论发布为答案,我很乐意将其标记为已接受:) - FrancescoC
谢谢 :) 我还花了一些时间对其进行了更多的编辑,因为我在答案中有更多的空间,所以希望我在那里做得更好 XD - Cruceo
1个回答

1
作为对我的评论的补充,因为这有所帮助并且我在这里有更多的空间:
不仅要检查令牌是否存在于您的SharedPreferences中,还应检查该令牌所属的应用程序版本是否与当前运行检查的版本匹配(这是Google文档中的建议)。
如果设备版本不匹配,则应请求有效令牌(实际上可能是相同的,但不能保证)。现在,您可能还想检查PACKAGE_REPLACED广播(以防您没有在每次安装测试时递增清单中的版本,这是我非常有罪的事情),如果触发,也应强制您请求新令牌。
至于为什么有时会更改令牌,有时不会更改:我完全同意,这是完全不规律的,不能帮助感觉像我们不知道的东西正在发生。

有时候,PACKAGE_REPLACED 后的新请求会返回相同的键;有时候不会。在这两者之间发生了什么使它变得奇怪?天啊,我真希望知道,并且我希望我有更多关于它的信息。但这就是我提到尝试捕获广播的原因之一:当事件发生时强制进行检查应该确保您始终获取新的有效请求(如果可用),即使版本检查在不应通过时也是如此。

希望这有所帮助~


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