我在Android 2.2设备上的GoogleCloudMessaging.register()调用中收到错误“SERVICE_NOT_AVAILABLE”。
我正在编写一个使用新版Google Play服务使用GoogleCloudMessaging的应用。我使用Android网站上提供的指南实现了它,我的源代码包含大量错误检查和处理代码,例如确保安装或更新Google Play服务。 GCM注册码还实现了谷歌的指数退避,建议用来处理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,它最终在设备上工作。但是,由于谷歌已经停止支持这种方法,我几乎不认为这是一个很好的解决方案。
EDIT2:看到接受的答案。
答案 0 :(得分:52)
我遇到了同样的问题。 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,并且我可以向智能手机发送消息。很奇怪,但它对我有用。
答案 1 :(得分:5)
这个错误也发生在我身上,但确实是因为我试图通过我公司的防火墙在GCM中注册。在我发现的文档中:
“注意:如果您的组织有防火墙限制流量 进出Internet,您需要将其配置为允许 与GCM连接,以便您的Android设备接收 消息。要打开的端口是:5228,5229和5230.通常是GCM 仅使用5228,但有时使用5229和5230. GCM没有 提供特定的IP,因此您应该允许防火墙接受 到IP块中包含的所有IP地址的传出连接 在Google的ASN 15169中列出。“
一旦我打开端口或尝试从另一个网络,它就可以工作。
答案 2 :(得分:2)
SERVICE_NOT_AVAILABLE可能是由旧的或丢失的GooglePlayServices引起的。 使用GooglePlayServicesUtil检查版本以及是否错误重定向到市场,以便用户可以手动安装它 - 这将修复SERVICE_NOT_AVAILABLE并获得所有改进 和错误修复(以及新错误:-)。
如果你不能这样做 - 使用register()没有意义,该方法希望匹配的播放服务检索结果。它确实生成相同的广播,以实现向后兼容。直接使用REGISTER意图或不推荐使用的库将继续工作 - 我建议使用意图,GCMRegistrar绑定到GoogleServicesFramework中的旧实现(它调用了intent.setPackage(GSF_PACKAGE)),因此它无法受益从任何修复。
拥有最新版本的GCM - 使用GooglePlayServicesUtil处理未自动安装的设备 - 不仅可以帮助注册。
答案 3 :(得分:2)
在阅读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
中答案 4 :(得分:0)
目前,在Google修复此错误或有人提供更好的解决方案之前,我使用的是混合解决方案,它会在最初几次使用Google Player服务(指数退避),但之后会切换到GCMRegistrar。 / p>
答案 5 :(得分:0)
所以,还有另一件需要注意的事情就是把我绊倒了。 我在模拟器+测试应用程序中运行良好,但后来我在实际设备上部署它时遇到了问题 一直收到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,然后就可以了。我甚至不需要手动广播接收器,它只是应该工作。
答案 6 :(得分:0)
如果标记的答案对您不起作用(就像我一样),请检查设备前面的人,也许摇一摇,然后启用互联网连接。为我工作; - )
没有互联网,你会收到相同的例外情况,我花了整个下午追逐服务的复杂问题......
答案 7 :(得分:0)
我遇到了同样的问题,但它发生在所有设备上。我花了很长时间才找到我的问题,但我想我会发布它,以防它与其他人的情况相符。这是我的问题的简化版本:
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。
答案 8 :(得分:0)
我知道这是一个旧帖子,但我遇到了同样的问题,而一切都设置正确。 SERVICE_NOT_AVAILABLE错误一直在弹出。转到设置后=&gt; apps =&gt;
,谷歌播放服务,清除缓存并删除数据