Подтвердить что ты не робот

Google Cloud Messaging - сообщения, которые иногда не принимаются, пока не изменилось состояние сети

Во время работы над небольшим проектом, который интегрируется с GCM, я наткнулся на немного странную проблему.

Несколько раз, когда я начинаю наблюдать за журналом, чтобы узнать, получены ли сообщения, сообщения не появляются до тех пор, пока я не изменил состояние сети (IE первоначально на WiFi, если я отключу WiFi и перейду к Mobile Data, сообщения поступают нормально). После того, как я изменил состояние сети, сообщения начнут поступать совершенно нормально, и то же самое произойдет, как только я изменю состояние сети до того, что было раньше (в данном случае, WiFi), сообщения продолжают получать сообщения.

Сам проект включает в себя возможность запускать при загрузке (запускает GCMBaseIntentService при загрузке), что опять отлично работает, и я уверен, что приложение/служба запущено, поскольку я вручную запустил приложение, когда эта проблема (который также проверяет, работает ли служба, и если она не запускает его и проверяет, зарегистрирована ли она).

Кто-нибудь еще сталкивается с этой проблемой или имеет какие-либо указания относительно того, как я могу это решить? Я не вижу ничего полезного в журнале между сообщениями времени, которые не принимаются и когда они (после изменения состояния сети). Я прошел через документы GCM и не вижу никаких упоминаний о сообщениях, которые не принимаются из-за тайм-аута (самого устройства) или любых параметров конфигурации, которые могут повлиять на это.

Оцените любую помощь - я могу предоставить источник, если это необходимо, хотя он вряд ли отклоняется от демонстрационного приложения, представленного в android-sdk.

4b9b3361

Ответ 1

Я тоже это заметил. Хотя я не врывался в фактический код, здесь я понимаю, почему это происходит.

GCM (и большинство служб обмена сообщениями) работает, поддерживая долгоживущий сокет, открытый для сервера push-объявлений Google. Сокет остается открытым, отправляя сообщения "heartbeat" между телефоном и сервером.

Иногда состояние сети может меняться, и этот сокет будет поврежден (потому что IP-адрес устройства изменяется, например, с 3g на Wi-Fi). Если сообщение появляется до того, как сокет будет восстановлен, то устройство не получит сообщение немедленно.

Повторное подключение происходит только тогда, когда телефон уведомляет о сбое сокета, что происходит только тогда, когда он пытается отправить сообщение с пульсом.

Опять же, просто мое основное понимание того, как это работает и почему это происходит, и я мог ошибаться.

Ответ 2

Существует множество причин задержки сообщений GCM. Если сообщение начнет поступать после изменения состояния сети или включения/выключения режима полета - наиболее вероятной причиной является сеть, которая закрывает соединение, не отправляя FIN/RST.

GCM поддерживает долговременное соединение - и восстанавливается, если он знает, что соединение было нарушено. Предполагается, что маршрутизатор /AP/NAT отправит FIN или RST для завершения TCP-соединения - так что GCM и серверы будут знать, что соединение мертво.

Однако количество маршрутизаторов и мобильных операторов этого не делает, и тогда GCM нужно полагаться на сердцебиение, ~ 15 минут на Wi-Fi, больше на мобильных устройствах. Существует компромисс между временем автономной работы/использованием сети и частотой пульса.

Ответ 3

В соответствии с вашим комментарием в приведенном выше ответе и в соответствии с моим опытом с уведомлениями о push-канале GCM нет никакой причины, что если сеть (подключение к Интернету) доступна, вы не должны получать push-уведомления. Я всегда проверяю наличие подключения к Интернету перед запуском приложения для push-уведомления, как это, попробуйте проверить это, если это правда, вы должны получать push-уведомления

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

Ответ 4

Итак, если @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
    }

Мое решение хорошее?

Ответ 5

в классе 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" />разрешение в вашем файле манифеста.

это должно сделать трюк...