首页 \ 问答 \ GCM推送通知的问题(Issues with GCM Push Notifications)

GCM推送通知的问题(Issues with GCM Push Notifications)

关于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时都会执行“GCM-Check”(因此,在onCreate方法期间)。

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

类似的错误

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

您可以看到"failure":1"results":[{"error":"NotRegistered"}]

正如谷歌文档所说,环回通过让服务器删除链接到有缺陷的RegistrationId的设备的记录来做出反应。 可理解。

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

设备应用程序不会处理新的注册。

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

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


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

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

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

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


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

在我开发的其他使用GCM的应用程序中,我已经用不同的方式解决了,例如让用户点击按钮或阅读服务器发送的一些特殊短信,然后启用GoogleCloudMessaging.unregister()起初,最后是GoogleCloudMessaging.register()


那么,请求原谅这样的文本墙,你是如何解决这个NotRegistered的事情的?

感谢您的努力和阅读时间,并希望在回答:)


for my first question on StackOverflow I'm gonna ask about Google Cloud Messaging service, and in particular Loopback's implementation.

So, I'm developing an app and started to work on a different branch to introduce Loopback's push notification handling and it's various tools for REST Api. Even if this topic is gonna cover strictly Loopback's way to handle GCM, the question is also related to the original way as is described on Google docs.

So, the main idea behind GCM's kick-off is to check whether the device is registered or not.

This is done by a simple check on a SharedPreferences variable, a name used to store our RegistrationID value.

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

If this is found, the device has to notify the server, communicating the token. Else, a registration to GCM has to be done. Once this is done, the device notifies the server. ( registerInBackground(installation) will eventually call saveInstallation(installation) after retrieving RegistrationId )

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

If communication is successful, the device saves RegistrationId using SharedPreferences as described above. (NOTE : getDeviceToken() is Loopback's way to handle via API the value in SharedPreferences)

Let's say this "GCM-Check" is being done every time my MainActivity is being created (so, during the onCreate method).

We also know GCM is sometimes messy, and wants to refresh my app's RegistrationId or some other stuff that, to be honest, is not completely clear to me right now. In short terms, GCM invalidates the token of my app. This causes an error-message when the server send a push-notification using the Token bound to my device-app.

An error similar to

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

You can see, "failure":1 and "results":[{"error":"NotRegistered"}]

Loopback reacts just as Google docs say, by having the server remove the record of the device linked to the faulty RegistrationId . Comprehensible.

Back to our device. Launching my app again and loading MainActivity, causes the same "GCM-check" procedure. This time the app can find RegistrationId using SharedPreferences, and can directly notify the server, which creates a record with the given RegistrationId.

No new registration is being handled by the device-app.

You can see the loop in here. Device will have no knowledge of it's token invalidity and will continue to tell the server the same data, which will keep sending information to the wrong registrationId, thus removing it after receiving the related error.

The problem is that the app has to rely on data which is created once and never gets modified. To remove the old data I should send a notification to the device, which is obviously not possible as I can't reach it from GCM. Other solutions possible is notify the user by sending an email or sms, and ask him to click a button for example, but I'd rather have a more "automated" approach to the problem.


A VERY BAD SOLUTION I'VE FOUND

As to my knowledge the only error-info is returned from GCM to the server during a push-notification, I've made a little hack on the device.

The idea is simple: create a POST request to GCM Servers, using the headers my server should use to authenticate. This causes the error to be given to the device itself, which can parse the JSON and notice what happened. From here the app can forge a new registration process, fixing the issue.

What is bad about this? The fact that to authenticate the device as the server, I have to hard-code the ServerKey and distribute it in every app. The ServerKey should be used only on the server, making this solution a very bad idea.


This being said, the idea of simply letting the device know its state using a SharedPreference value is not so great, as it would only tell me if I ever registered at least once, without letting me know my current status.

On other apps I've developed which use GCM just as well, I've solved in different ways, like having a Button to be clicked by the user or reading some specials SMS send by the server, which then enable GoogleCloudMessaging.unregister() at first and eventually GoogleCloudMessaging.register()


So, asking for forgiveness for such a wall-of-text, how have you solved this NotRegistered thing?

Thanks for your effort and time in reading and, hopefully, in answering : )


原文:https://stackoverflow.com/questions/28945783
更新时间:2023-11-06 21:11

最满意答案

您正在向现有单元格添加多个事件处理程序。 这就是为什么我更喜欢使用普通的.onclick属性的原因之一。

无论如何,要解决此问题,您可以只将事件应用于新单元格,或者在添加事件时向它们添加属性,然后在再次添加事件之前检查该属性。


You are adding multiple event handlers to existing cells. This is one reason why I prefer to use just the plain old .onclick property.

Anyway, to solve this issue you can either only apply the event to the new cells, or add an attribute to them when you do add an event, then check that attribute before adding the event again.

相关问答

更多
  • 由于某些浏览器(取决于DOCTYPE)能够容忍onClick="something();" 属性......它似乎已经分散了一些,甚至在JavaScript不起作用的问题上,因为这个问题很重要。 此外,具体到stackoverflow ...在问题中使用它的人...以及,大多数时候他们不会问一个问题,如果他们的代码工作:) Because some browsers (depending on the DOCTYPE) are tolerant of the inline onClick="somethin ...
  • 假设您只想计算用户点击的元素,那么该方法应该更像这样: function calc(element, r, t) { element.innerHTML = r+t } 而方法调用ofc将是: 例如,请看这个小提琴。 http://jsfiddle.net/m9wkr0vz/ 为了允许更复杂的计算而不为每个组合提供方法,您可以使用javascripts能力来评估给定的表达式: fun ...
  • 事件处理程序仅绑定到当前选定的元素; 它们必须在代码进行事件绑定调用时存在于页面上。 由于readmore anchor是动态创建的,因此您需要使用事件委派 。 您必须使用.on()使用委托事件方法。 使用 /*removes truncation and shows the hidden "Read Less" link in content*/ $(".article").on('click', '.readmore', function () { $(this).parents('div'). ...
  • 您正在向现有单元格添加多个事件处理程序。 这就是为什么我更喜欢使用普通的.onclick属性的原因之一。 无论如何,要解决此问题,您可以只将事件应用于新单元格,或者在添加事件时向它们添加属性,然后在再次添加事件之前检查该属性。 You are adding multiple event handlers to existing cells. This is one reason why I prefer to use just the plain old .onclick property. Anyway, ...
  • event.preventDefault(); 而不是event.stopPropagation(); 触发器仅在点击元素上点击。 在jsFiddle演示。 event.preventDefault(); instead of event.stopPropagation(); triggers onclick on the clicked element only. A demo at jsFiddle.
  • 你应该删除分号: ; 从功能。 例如: onclick="card14()" you should delete the semicolon: ; from the function. for example: onclick="card14()"
  • 这个问题是因为第一次点击执行chooseMap函数,然后附加事件处理程序。 第二次点击然后执行在这些事件处理程序中分配的代码。 要修复和改进您的代码,请删除内联onclick属性并使用jQuery来附加您的事件。 尝试这个:
    ...
  • 你的isClick逻辑对我来说没有意义。 如果isclick为真,那么不是总是运行这个介绍,而是立即启动mainactivity,为什么不具备是否在mainactivity中进行介绍的逻辑。 主要活动中的这种情况: protected void onCreate(Bundle savedInstanceState) { SharedPreferences appPreferences = PreferenceManager.getDefaultSharedPreferences(this); ...
  • 当你设置一个onclick属性时; 浏览器将引用到您设置的节点,让我们调用此引用button ,然后执行转换 onclick="/* code */" 至 button.onclick = function (event) {eval(/* code */);}; 当一个点击事件发生时,这个函数可以被认为是像这样被调用的 button.onclick.call(button, click_event); button的上下文,因此this是button 。 它包含在它自己的函数中,因此如果某些内容是v ...

相关文章

更多

最新问答

更多
  • 获取MVC 4使用的DisplayMode后缀(Get the DisplayMode Suffix being used by MVC 4)
  • 如何通过引用返回对象?(How is returning an object by reference possible?)
  • 矩阵如何存储在内存中?(How are matrices stored in memory?)
  • 每个请求的Java新会话?(Java New Session For Each Request?)
  • css:浮动div中重叠的标题h1(css: overlapping headlines h1 in floated divs)
  • 无论图像如何,Caffe预测同一类(Caffe predicts same class regardless of image)
  • xcode语法颜色编码解释?(xcode syntax color coding explained?)
  • 在Access 2010 Runtime中使用Office 2000校对工具(Use Office 2000 proofing tools in Access 2010 Runtime)
  • 从单独的Web主机将图像传输到服务器上(Getting images onto server from separate web host)
  • 从旧版本复制文件并保留它们(旧/新版本)(Copy a file from old revision and keep both of them (old / new revision))
  • 西安哪有PLC可控制编程的培训
  • 在Entity Framework中选择基类(Select base class in Entity Framework)
  • 在Android中出现错误“数据集和渲染器应该不为null,并且应该具有相同数量的系列”(Error “Dataset and renderer should be not null and should have the same number of series” in Android)
  • 电脑二级VF有什么用
  • Datamapper Ruby如何添加Hook方法(Datamapper Ruby How to add Hook Method)
  • 金华英语角.
  • 手机软件如何制作
  • 用于Android webview中图像保存的上下文菜单(Context Menu for Image Saving in an Android webview)
  • 注意:未定义的偏移量:PHP(Notice: Undefined offset: PHP)
  • 如何读R中的大数据集[复制](How to read large dataset in R [duplicate])
  • Unity 5 Heighmap与地形宽度/地形长度的分辨率关系?(Unity 5 Heighmap Resolution relationship to terrain width / terrain length?)
  • 如何通知PipedOutputStream线程写入最后一个字节的PipedInputStream线程?(How to notify PipedInputStream thread that PipedOutputStream thread has written last byte?)
  • python的访问器方法有哪些
  • DeviceNetworkInformation:哪个是哪个?(DeviceNetworkInformation: Which is which?)
  • 在Ruby中对组合进行排序(Sorting a combination in Ruby)
  • 网站开发的流程?
  • 使用Zend Framework 2中的JOIN sql检索数据(Retrieve data using JOIN sql in Zend Framework 2)
  • 条带格式类型格式模式编号无法正常工作(Stripes format type format pattern number not working properly)
  • 透明度错误IE11(Transparency bug IE11)
  • linux的基本操作命令。。。