Служба GCM недоступна на Android 2.2

Я получаю ошибку "SERVICE_NOT_AVAILABLE" на моем GoogleCloudMessaging.Регистрация () вызов на устройстве Android 2.2.

Я пишу приложение, которое использует GoogleCloudMessaging с помощью новых сервисов Google Play. Я реализовал его, используя рекомендации, представленные на веб-сайте Android, и мой источник содержит много ошибок проверки и обработки кода, таких как убедитесь, что службы Google Play установлены или обновлены. Регистрационный код GCM также реализует экспоненциальный backoff как google, как предложил один реализовать для обработки ошибки SERVICE_NOT_AVAILABLE.

я протестировал свое приложение на широком спектре устройств, включая ICS, JB, Honey Comb и даже 2.3.X устройств. Регистрация GCM работает, и я могу отправлять сообщения на него через GCM. Однако на устройстве 2.2 я постоянно получаю ошибку SERVICE_NOT_AVAILABLE на GoogleCloudMessaging.вызов register () даже с экспоненциальным отступлением на месте.

устройство, которое GCM сбой на Samsung SGH-I896, чтобы быть точным, и телефон имеет 2 учетные записи google на нем. Я читал, что эта ошибка может быть вызвана неправильной настройки времени, а время устанавливается автоматически. Телефон не модифицирован и работает под управлением Samsung stock ROM.

Я также попытался перезагрузить устройство, а также переустановить службы Google Play без везения. Любая помощь по этому вопросу будет очень признательна.

EDIT: я попытался реализовать GCM, используя старый gcm.банка и GCMRegistrar, и он закончил работу над устройством. Однако я вряд ли считаю это хорошим решением проблемы, поскольку Google перестала поддерживать этот метод afaik.

EDIT2: см. принятый ответ.

9 ответов


Я испытал ту же проблему. GCM отлично работает на моем планшете под управлением Android 4.04, но всегда получал SERVICE_NOT_AVAILABLE на моем смартфоне под управлением Android 2.3.

Я нашел следующее обходное решение, не используя (насколько я знаю) какие-либо устаревшие классы. Добавить действие " com.гуглить.андроид.c2dm.намерение.Регистрация " в gcmbroadcastreceiver в вашем манифесте. Это позволит получить registration_id в вашем GCMBroadcastReceiver.

<receiver
   android:name="YOUR_PACKAGE_NAME.GCMBroadcastReceiver"
   android:permission="com.google.android.c2dm.permission.SEND" >
      <intent-filter>
         <action android:name="com.google.android.c2dm.intent.RECEIVE" />
         <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

         <category android:name="YOUR_PACKAGE_NAME" />
      </intent-filter>
</receiver>

после этого ваш GCMBroadcastReceiver может получить registration_id:

public void onReceive(Context context, Intent intent) {
   String regId = intent.getExtras().getString("registration_id");
   if(regId != null && !regId.equals("")) {
      /* Do what ever you want with the regId eg. send it to your server */
   }
}

хотя я все еще получаю ошибку SERVICE_NOT_AVAILABLE, я могу обрабатывать registration_id в моем GCMBroadcastReceiver, и я могу отправлять сообщения на свой смартфон. Довольно странно, но для меня это работает.


эта ошибка также произошла со мной, но это произошло, потому что я пытался зарегистрироваться в GCM через брандмауэр моей компании. И в документации я нашел:

"Примечание: Если ваша организация имеет брандмауэр, который ограничивает движение или из интернета, вам нужно настроить его, чтобы разрешить подключение с GCM для того, чтобы ваши Android устройства, чтобы получить сообщения. Порты для открытия: 5228, 5229 и 5230. GCM типично использует только 5228, но иногда использует 5229 и 5230. МОЦ не укажите конкретные IP-адреса, поэтому вы должны разрешить брандмауэру принимать исходящие подключения ко всем IP-адресам, содержащимся в блоках IP перечислены в ASN Google от 15169."

Как только я открыл порты или попытался из другой сети, это сработало.


SERVICE_NOT_AVAILABLE может быть вызвано старой или отсутствующей GooglePlayServices. Используйте GooglePlayServicesUtil, чтобы проверить версию, и если неправильное перенаправление на рынок, чтобы пользователь мог вручную установить его - это исправит SERVICE_NOT_AVAILABLE, а также получить все улучшения и исправления ошибок ( и новые ошибки :-).

Если вы не можете этого сделать - нет смысла использовать register (), метод ожидает, что соответствующий сервис воспроизведения получит результат. Оно производит такую же передачу, для обратная совместимость. Использование намерения реестра напрямую или устаревшей библиотеки будет продолжать работать - я бы предложил использовать намерение, GCMRegistrar привязан к старой реализации в GoogleServicesFramework (у него есть вызов intent.setPackage (GSF_PACKAGE)), поэтому он не может извлечь выгоду из каких-либо исправлений.

наличие последней версии GCM-с помощью GooglePlayServicesUtil для работы с устройствами, которые не получили автоматическую установку - может помочь не только для регистрации.


после прочтения сообщения из marnanish, я попробовал код ниже, и я успешно получил свою деятельность, чтобы получить регистрацию. Просто добавьте это:

<activity
    android:name=".MyActivity"
    ... />
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
        <category android:name="your.package.here" />
    </intent-filter>
</activity>

в вашем AndroidManifest.в XML


в настоящее время, пока Google не исправит эту ошибку или кто-то не предоставит лучшее решение, я использую гибридное решение, где он будет использовать сервисы Google Player в течение первых нескольких раз (с экспоненциальным отступлением), но затем переключится на GCMRegistrar.


Итак, есть еще одна вещь, чтобы следить за тем, что меня споткнулся. У меня он отлично работал в emulator + с тестовым приложением, но потом у меня возникли проблемы с его развертыванием на реальных устройствах.
Последовательно получал ошибку SERVICE_NOT_AVAILABLE и прибегал к подходу, аналогичному ответу выше:

     IntentFilter filter = new IntentFilter("com.google.android.c2dm.intent.REGISTRATION");
     BroadcastReceiver receiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             Log.i(TAG, "Got into onReceive for manual GCM retrieval. "
             + intent.getExtras());
             String regId = intent.getStringExtra("registration_id");

             if (regId != null && !regId.isEmpty()) {
                 theResult.add(regId);
             } else {
                 theResult.add("");
             }
             lastDitchEffortComplete = true;
             }
         };
     cont.registerReceiver(receiver, filter);

этот вид-работал. Но получение этой информации заняло странно много времени, и в цикле ожидания, который у меня был, он мог получить ее только после Я сдалась и позволила всему идти своим чередом.

Это заставило меня подумать, что может быть другая причина для SERVICE_NOT_AVAILABLE msg.

это код, который я должен был сделать выборку/регистрация с помощью:

new AsyncTask<Void, Void, Void>() {
                final long timeSleep = 1000;

                @Override
                protected Void doInBackground(Void... params) {
                    GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(cont);
                    String registrationId = "";
                    int count = 0;
                    while (count < 1) {
                        try {
                            count++;
                            Log.i(TAG, "Starting GCM Registration Attempt #" + count);
                            registrationId = gcm.register(CLOUDAPPID);
                            rph.storeRegistrationId(registrationId);
                            return null;
                        } catch (IOException e) {
                            e.printStackTrace();
                        }

                        Log.w(TAG, "Registration failed.  Retrying in " + timeSleep + " ms.");
                        try {
                            Thread.sleep(timeSleep);
                        } catch (InterruptedException e) {
                        }
                    }

                    return null;
                }
            }.execute().get();

главное искать здесь последняя строка.

.execute.get();

" умный/обман " способ блокировать асинхронные результаты вне потока.

оказывается, именно это и вызывает проблему. Как только я имел:

.execute();

пусть он пройдет, и заставил алгоритм / код работать с отчетностью и не нуждаться в регистрационном идентификаторе сразу, тогда все было в порядке. Мне даже не нужен был ручной радиоприемник, он просто работал так, как должен.


Если отмеченный ответ не работает для вас (как это было для меня), проверьте человека перед вашим устройством, возможно, встряхните его, а затем включите подключение к интернету. Работал на меня; -)

без интернета вы получаете то же исключение, и я провел день, преследуя сложные проблемы с сервисом....


у меня была такая же проблема, но это происходит на всех устройствах. Мне потребовалась вечность, чтобы найти свою проблему, но я думал, что опубликую ее, если она соответствует чьему-то делу. Вот упрощенная версия моей проблемы:

public class Login extends Activity {
    Context context;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        context = getApplicationContext();

        //Get GCM registration id
        new GcmRegistrationAsyncTask().execute(context);

        Set<Tuple> timeline = new HashSet<Tuple>();
        try {
            //Get data from Redis database
            timeline = new RedisAsyncTask().execute(context).get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

когда я добавляю вторую AsyncTask с возвратом с помощью get (), я бы получал GCM 'SERVICE_NOT_AVAILABLE' каждый раз, даже если я все еще могу получить идентификатор регистрации из gcmbroadcastreceiver onReceive (). Однако, когда я беги:

public class Login extends Activity {
    Context context;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        context = getApplicationContext();

        new GcmRegistrationAsyncTask().execute(context);
        new RedisAsyncTask().execute(context);
    }
}

GCM получит идентификатор регистрации без проблем.


Я знаю, что это старый пост, но у меня была та же проблема, в то время как все было настроено правильно. Ошибка SERVICE_NOT_AVAILABLE продолжала появляться. После перехода в settings => apps => Google Play-servises и очистки кэша и удаления данных он работал.