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. Я читал, что эта ошибка может быть вызвана неправильно настроенным временем, но время установлено на автоматическое. Телефон не смоделирован и работает под управлением самсунг стокового ПЗУ.
Я также попытался перезагрузить устройство и переустановить Сервисы Google Play без удачи. Любая помощь по этому вопросу будет принята с благодарностью.
РЕДАКТИРОВАТЬ: Я попытался реализовать GCM, используя старый gcm.jar и GCMRegistrar, и он закончил работать на устройстве. Однако я вряд ли считаю это хорошим решением проблемы, так как Google прекратил поддерживать этот метод.
EDIT2: см. Принятый ответ.
9 ответов
Я испытал ту же проблему. GCM отлично работает на моем планшете под управлением Android 4.04, но всегда получал SERVICE_NOT_AVAILABLE на моем смартфоне под управлением Android 2.3.
Я нашел следующий обходной путь, не используя (насколько я знаю) устаревшие классы. Добавьте действие "com.google.android.c2dm.intent.REGISTRATION" к GCMBroadcastReceiver в своем манифесте. Это позволит получить регистрационный идентификатор на вашем 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 может получить регистрационный идентификатор:
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, я могу обработать регистрационный_идентификатор в моем GCMBroadcastReceiver и могу отправлять сообщения на свой смартфон. Довольно странно, но у меня это работает.
Эта ошибка также произошла со мной, но это произошло потому, что я пытался зарегистрироваться в GCM через брандмауэр моей компании. И в документации я нашел:
"Примечание. Если в вашей организации есть брандмауэр, который ограничивает трафик в Интернет или из Интернета, его необходимо настроить, чтобы разрешить подключение к GCM, чтобы устройства Android могли получать сообщения. Открываемые порты: 5228, 5229 и 5230. GCM обычно использует только 5228, но иногда использует 5229 и 5230. GCM не предоставляет конкретные IP-адреса, поэтому вы должны разрешить брандмауэру принимать исходящие подключения ко всем IP-адресам, содержащимся в блоках IP, перечисленных в ASN Google 15169."
Как только я открыл порты или попробовал из другой сети, это работало.
SERVICE_NOT_AVAILABLE может быть вызвано старым или отсутствующим GooglePlayServices. Используйте GooglePlayServicesUtil, чтобы проверить версию и, если неправильно, перенаправить на рынок, чтобы пользователь мог установить ее вручную - это исправит SERVICE_NOT_AVAILABLE, а также получит все улучшения и исправления ошибок (и новые ошибки:-).
Если вы не можете сделать это - нет смысла использовать register(), метод ожидает, что соответствующий сервис воспроизведения получит результат. Он генерирует ту же самую трансляцию для обратной совместимости. Использование намерения REGISTER напрямую или устаревшая библиотека продолжит работать - я бы предложил использовать намерение, GCMRegistrar привязан к старой реализации в GoogleServicesFramework (у него есть вызов intent.setPackage(GSF_PACKAGE)), поэтому он не может извлечь выгоду от любых исправлений.
Наличие последней версии GCM - с помощью GooglePlayServicesUtil для работы с устройствами, которые не получили автоматическую установку - может помочь не только для регистрации.
После прочтения поста от marnaish, я попробовал код ниже, и я успешно получил свою активность, чтобы получить регистрацию. Просто добавьте это:
<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
Если отмеченный ответ не работает для вас (как это было для меня), проверьте человека перед вашим устройством, возможно встряхните его и затем включите интернет-соединение. Работал на меня;-)
Без интернета вы получаете то же исключение, и я провел весь день в погоне за сложными проблемами с сервисом....
Я знаю, что это старый пост, но у меня была та же проблема, когда все было настроено правильно. Ошибка SERVICE_NOT_AVAILABLE, продолжал появляться. Перейдя в настройки => apps => Google Play-сервисы, очистив кеш и удалив данные, все заработало.
Итак, есть еще одна вещь, чтобы следить за тем, что сбило меня с толку. У меня все работало нормально в эмуляторе + с тестовым приложением, но потом возникли проблемы с его развертыванием на реальных устройствах.
Последовательно получал ошибку 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();
"Умный / читерский" способ блокировать асинхронные результаты вне потока.
Оказывается, именно это и является причиной проблемы. Как только я только что:
.execute();
Позвольте этому пройти и заставили алгоритм / код работать с отчетностью и без необходимости регистрации идентификатора сразу, тогда это было хорошо. Мне даже не нужен был ручной приемник вещания, он просто работал как надо.
В настоящее время, пока Google не исправит эту ошибку или кто-то не предоставит лучшее решение, я использую гибридное решение, в котором он будет использовать Сервисы Google Player в первые несколько раз (с экспоненциальным откатом), но впоследствии переключится на GCMRegistrar.
У меня была такая же проблема, но это происходило на всех устройствах. У меня ушло навсегда, чтобы найти свою проблему, но я подумал, что опубликую ее, если она соответствует чьему-либо делу Вот упрощенная версия моей проблемы:
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 получит регистрационный идентификатор без проблем.