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: см. принятый ответ.
Ответы
Ответ 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-сервисы, очистите кеш и удалите данные, он сработал.