Android 2.2 上的 GCM SERVICE_NOT_AVAILABLE
Posted
技术标签:
【中文标题】Android 2.2 上的 GCM SERVICE_NOT_AVAILABLE【英文标题】:GCM SERVICE_NOT_AVAILABLE on Android 2.2 【发布时间】:2013-07-11 05:40:16 【问题描述】:我在 android 2.2 设备上调用 GoogleCloudMessaging.register() 时收到错误“SERVICE_NOT_AVAILABLE”。
我正在使用新的 Google Play 服务编写一个使用 GoogleCloudMessaging 的应用程序。我使用 Android 网站上提供的指南实现了它,我的源代码包含许多错误检查和处理代码,例如确保安装或更新 Google Play 服务。 GCM 注册代码还按照 google 的建议实现了指数退避,以实现处理 SERVICE_NOT_AVAILABLE 错误。
我已经在各种设备上测试了我的应用程序,包括 ICS、JB、Honey Comb 甚至 2.3.x 设备。 GCM 注册有效,我可以通过 GCM 向它发送消息。但是,在 2.2 设备上,即使有指数退避,我也会在 GoogleCloudMessaging.register() 调用中不断收到 SERVICE_NOT_AVAILABLE 错误。
确切地说,GCM 失败的设备是三星 SGH-I896,手机上有 2 个谷歌帐户。我读过这个错误可能是由错误配置的时间引起的,但时间设置为自动。手机未进行调制,正在运行三星股票 ROM。
我也尝试过重新启动设备以及重新安装 Google Play 服务,但都没有成功。对此问题的任何帮助将不胜感激。
编辑:我尝试使用旧的 gcm.jar 和 GCMRegistrar 实现 GCM,它最终在设备上运行。但是,我几乎不认为这是解决问题的好方法,因为 Google 已经停止支持这种方法了。
EDIT2:查看接受的答案。
【问题讨论】:
【参考方案1】:我遇到了同样的问题。 GCM 在运行 Android 4.04 的平板电脑上运行良好,但在运行 Android 2.3 的智能手机上总是收到 SERVICE_NOT_AVAILABLE。
我发现以下解决方法不使用(据我所知)任何已弃用的类。将操作“com.google.android.c2dm.intent.REGISTRATION”添加到清单中的 GCMBroadcastReceiver。这将使您能够在您的 GCMBroadcastReceiver 接收registration_id。
<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 错误,但我可以在我的 GCMBroadcastReceiver 中处理registration_id,并且可以向我的智能手机发送消息。很奇怪,但它对我有用。
【讨论】:
@marnaish - 你是在 google 的广播接收器类中还是在我们自己的广播接收器中编写的? 它是与接收消息的广播接收器相同的广播接收器。 “android:name”参数应该链接到你的广播接收器(我已经改变了它)。如果您按照教程@developer.android.com/google/gcm/gs.html 进行操作,您将获得 GcmBroadcastReceiver 类中的注册 ID。 @marnaish 好的,谢谢!但它仍然无法正常工作。仍然出错 哇...这出乎意料地有效。谢谢! @Sunil Mishra 您仍然会收到错误消息,但它会在 GcmBroadcastReceiver 的 onRecieve 方法中将注册 ID 返回给您。 我在下面添加了一个替代解决方案,请参阅***.com/a/19176015/816017【参考方案2】:这个错误也发生在我身上,但它确实是因为我试图通过我公司的防火墙在 GCM 中注册。在我发现的文档中:
"注意:如果您的组织有限制流量的防火墙 到 Internet 或从 Internet,您需要将其配置为允许 与 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 中的旧实现相关联(它调用了 intent.setPackage(GSF_PACKAGE)),因此它无法受益从任何修复。
拥有最新版本的 GCM - 通过使用 GooglePlayServicesUtil 处理未自动安装的设备 - 不仅有助于注册。
【讨论】:
我认为这是真的。与往常一样,由于 Google Play 没有正确进行搜索,所以有些混乱,但经过一番摆弄后,Google Play 工作了,现在 GCM 工作了。我认为是 Google Play 服务。【参考方案4】:阅读marnanish的帖子后,我尝试了下面的代码,我已经成功让我的Activity收到了注册。只需添加以下内容:
<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 Services(具有指数退避),但之后切换到 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();
一种“聪明/作弊”的方式来阻止异步离线结果。
事实证明,这就是导致问题的原因。 只要我有:
.execute();
让它通过,让算法/代码与报告一起工作,并且不需要立即注册 id,那就没问题了。我什至不需要手动广播接收器,它就可以正常工作。
【讨论】:
另外,这里有一个有趣的可能相关的问题/解决方案:***.com/questions/7109240/…【参考方案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();
当我使用 get() 添加带有返回的第二个 AsyncTask 时,我每次都会得到 GCM 'SERVICE_NOT_AVAILABLE',即使我仍然可以从 GcmBroadcastReceiver onReceive() 检索注册 ID。但是,当我运行时:
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 将毫无问题地收到注册 ID。
【讨论】:
【参考方案9】:我知道这是一篇旧帖子,但我遇到了同样的问题,但一切都设置正确。 SERVICE_NOT_AVAILABLE 错误,不断弹出。转到设置 => 应用程序 => Google Play 服务后,清除缓存并删除数据,它工作了。
【讨论】:
就我而言,这会将错误从SERVICE_NOT_AVAILABLE
更改为TIME_OUT
以上是关于Android 2.2 上的 GCM SERVICE_NOT_AVAILABLE的主要内容,如果未能解决你的问题,请参考以下文章