Android 2.2上的GCM SERVICE_NOT_AVAILABLE

时间:2013-07-12 15:54:30

标签: android android-2.2-froyo google-cloud-messaging google-play-services service-not-available

我在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:看到接受的答案。

9 个答案:

答案 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;

,谷歌播放服务,清除缓存并删除数据