【问题标题】:GCM SERVICE_NOT_AVAILABLE on Android 2.2Android 2.2 上的 GCM SERVICE_NOT_AVAILABLE
【发布时间】: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:查看接受的答案。

【问题讨论】:

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


    【解决方案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 返回给您。
    • 我在下面添加了一个替代解决方案,请参阅stackoverflow.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,那就没问题了。我什至不需要手动广播接收器,它就可以正常工作。

          【讨论】:

          【解决方案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
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-04-01
              • 1970-01-01
              相关资源
              最近更新 更多