Google Cloud Messaging - 在网络状态发生变化之前,有时无法收到消息

时间:2012-12-12 08:30:57

标签: android google-cloud-messaging android-networking

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

有些时候,当我开始观看日志以查看是否收到消息时,直到我更改了网络状态(IE最初在WiFi上,如果我关闭WiFi并转移到移动数据,消息)似乎没有出现消息消息很好)。在我改变了网络状态后,消息开始完全正常,一旦我将网络状态恢复到以前的状态(在这种情况下,WiFi),消息将继续接收,这同样适用。

项目本身包括启动时启动的功能(启动时启动GCMBaseIntentService),再次运行正常,我确信应用程序/服务正在运行,因为我在此问题时手动启动了应用程序发生(它还检查服务是否正在运行,如果它不运行它并检查它是否已注册)。

有没有其他人遇到过这个问题,或者有任何指示我如何解决这个问题?我没有看到在没有收到消息的时间和它们之间(在更改网络状态之后)之间的日志中有任何帮助。我已经浏览了GCM文档,并且看不到由于超时(在设备本身上)或任何可能影响它的配置选项而未收到消息的提及。

感谢任何帮助 - 如果需要,我可以提供来源,尽管它几乎不会偏离android-sdk中提供的演示应用程序。

5 个答案:

答案 0 :(得分:36)

我也注意到了这一点。虽然我没有深入研究实际的代码,但我理解为什么会这样。

GCM(以及大多数推送消息传递服务)的工作原理是将长期存储套件保持为Google的推送通知服务器。通过在电话和服务器之间发送“心跳”消息来保持套接字打开。

有时,网络状态可能会发生变化,此套接字将被破坏(因为设备的IP地址会发生变化,例如从3g变为wifi)。如果在重新建立套接字之前消息进入,则设备将不会立即收到消息。

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

再次,只是我对它如何运作及其发生原因的基本理解,我可能是错的。

答案 1 :(得分:20)

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

GCM维护一个长期连接 - 如果它知道连接断开,则重新连接。 路由器/ AP / NAT应该发送FIN或RST来终止TCP连接 - 因此GCM和服务器将知道连接已经死亡。

然而,许多路由器和移动运营商都没有这样做,然后GCM需要依靠心跳,在Wifi上大约需要15分钟,更多的是在移动设备上。在电池寿命/网络使用和心跳频率之间进行权衡。

答案 2 :(得分:1)

根据您在上述答案中的评论,并根据我对GCM推送通知的经验,没有任何理由如果网络(互联网连接)可用,您不应该收到推送通知我在运行应用程序之前始终检查互联网连接可用性对于这样的推送通知,请尝试检查这是否属实,您应该收到推送通知

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

答案 3 :(得分:0)

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

  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
    }

我的解决方案好吗?

答案 4 :(得分:-4)

在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" />   您在清单文件中的权限..

这应该可以解决问题...