GCM SERVICE_NOT_AVAILABLE на Android 2.2 - программирование
Подтвердить что ты не робот

GCM SERVICE_NOT_AVAILABLE на Android 2.2

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

Я пишу приложение, которое использует GoogleCloudMessaging, используя новые сервисы Google Play. Я реализовал его, используя рекомендации, представленные на веб-сайте Android, и мой источник содержит много ошибок и кода обработки, например, чтобы установить или обновить службы Google Play. Код регистрации GCM также реализует экспоненциальную отсрочку как 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.

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

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

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

4b9b3361

Ответ 1

У меня возникла такая же проблема. GCM отлично работает на моем планшетном ПК под управлением Android 4.04, но всегда получил SERVICE_NOT_AVAILABLE на моем смартфоне под управлением Android 2.3.

Я нашел следующее обходное решение, которое не использовало (насколько мне известно) любые устаревшие классы. Добавьте в свой манифест действие "com.google.android.c2dm.intent.REGISTRATION" в GCMBroadcastReceiver. Это позволит получить register_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, я могу обрабатывать register_id в своем GCMBroadcastReceiver, и я могу отправлять сообщения на свой смартфон. Странно, но это работает для меня.

Ответ 2

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

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

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

Ответ 3

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

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

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

Ответ 4

Прочитав сообщение из 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

Ответ 5

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

Ответ 6

Итак, есть еще одна вещь, чтобы следить за тем, что это подтолкнуло меня. Я работал в эмуляторе + с тестовым приложением, но потом у меня возникли проблемы с его развертыванием на реальных устройствах.
Постоянно получал ошибку 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.

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

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();

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

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

.execute();

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

Ответ 7

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

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

Ответ 8

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

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 получит идентификатор регистрации без проблем.

Ответ 9

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