Google Cloud Messaging – 在networking状态发生变化之前有时收不到消息

在开发一个与GCM集成的小项目时,我偶然发现了一个奇怪的问题。

有些时候,当我开始看日志,看看是否收到消息,消息似乎没有通过,直到我改变了networking状态(IE最初在WiFi上,如果我关掉WiFi,移动到移动数据,消息到达精细)。 在我改变了networking状态之后,消息开始得到完全正常,而且一旦我将networking状态改回到之前的状态(在这种情况下是WiFi),消息就继续被接收。

该项目本身包括启动的能力(启动时启动GCMBaseIntentService),这再次正常工作,我敢肯定,应用程序/服务正在运行,因为我已经手动启动应用程序,当这个问题发生时还检查服务是否正在运行,如果没有运行,检查是否已经注册。

有没有其他人遇到这个问题,或有任何指示,我该如何解决这个问题? 在没有收到消息的时间和收到消息的时间(更改networking状态之后)之间,我没有看到任何帮助。 我浏览过GCM文档,看不到任何由于超时(在设备本身上)而未收到消息,或任何可能影响此设置的configuration选项。

欣赏任何帮助 – 如果需要,我可以提供源代码,但它几乎不会偏离android-sdk中提供的演示应用程序。

我也注意到了这一点。 虽然我没有深入到实际的代码,这是我的理解为什么发生这种情况。

GCM(和大多数推送消息传递服务)通过为Google的推送通知服务器保持一个长期的套接字而工作。 通过在手机和服务器之间发送“心跳”消息,套接字保持打开状态。

偶尔,networking状态可能会改变,这个套接字将被打破(因为设备的IP地址发生了变化,例如从3G到WiFi)。 如果在套接字重新build立之前消息进入,那么设备将不会立即得到消息。

重新连接只发生在手机注意到套接字断开时,只有当它试图发送心跳消息时才会发生。

再次,就是我对它是如何工作的基本理解,以及为什么会发生,我可能是错的。

GCM消息延迟有很多原因。 如果在更改networking状态或打开/closures飞行模式之后信息开始到达,最可能的原因是networking在不发送FIN / RST的情况下closures连接。

GCM保持长久的连接 – 如果知道连接中断,则重新连接。 路由器/ AP / NAT应该发送FIN或RST来终止TCP连接 – 所以GCM和服务器将知道连接已经死亡。

然而,许多路由器和移动运营商不这样做,然后GCM需要依靠心跳,在WiFi上大约15分钟,而在移动上更多。 电池寿命/networking使用和心跳频率之间有一个折衷。

根据你在上面的回答中的评论和根据我的GCM推送通知的经验,没有任何理由,如果networking(互联网连接)可用,你不应该收到推送通知我总是检查互联网连接可用性之前运行推送通知的应用程序像这样尝试检查,如果这是真的,你应该收到推送通知

private boolean isNetworkAvailable() { ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); return activeNetworkInfo != null; } 

所以,如果@自我主义的思想是真的,我可以使用类似的东西:

  ConnectivityManager cm = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); if (null != activeNetwork) { if(activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) // here the network changed to Wifi so I can send a heartbeat to GCM to keep connection if(activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) //here the network changed to mobileData so I can send a heartbeat to GCM to keep connection } 

我的解决scheme好吗?

在GCMIntentSevice类中,当您从服务器接收消息时,onMessage方法被调用,所以在那个时候你可以做类似…

 PowerManager pm = (PowerManager) getApplicationContext() .getSystemService(Context.POWER_SERVICE); WakeLock wakeLock = pm.newWakeLock( (PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP),"TAG"); wakeLock.acquire(); 

你必须添加

清单文件中的<uses-permission android:name="android.permission.WAKE_LOCK" />权限

这应该做的伎俩… … –