web-dev-qa-db-ja.com

GCM SERVICE_NOT_AVAILABLE on Android 2.2

Android 2.2デバイスでのGoogleCloudMessaging.register()呼び出しでエラー「SERVICE_NOT_AVAILABLE」が発生します。

新しいGooglePlay開発者サービスを使用してGoogleCloudMessagingを使用するアプリを作成しています。 Android Webサイトで提供されているガイドラインを使用して実装しました。ソースには、Google Play開発者サービスがインストールまたは更新されていることを確認するなど、エラーチェックと処理コードが多数含まれています。GCM登録コードまた、SERVICE_NOT_AVAILABLEエラーを処理するために実装するように提案されているように、指数バックオフをgoogleとして実装します。

私は、ICS、JB、Honey Comb、さらには2.3.xデバイスを含むさまざまなデバイスでアプリケーションをテストしました。 GCM登録が機能し、GCM経由でメッセージを送信できます。ただし、2.2デバイスでは、指数バックオフが設定されていても、GoogleCloudMessaging.register()呼び出しでSERVICE_NOT_AVAILABLEエラーが継続的に発生します。

GCMが失敗しているデバイスは、正確にはSamsung SGH-I896であり、電話には2つのGoogleアカウントがあります。このエラーは時間の設定ミスが原因である可能性があることを読みましたが、時間は自動に設定されています。電話機はモデレートされておらず、samsungストックROMを実行しています。

また、デバイスを再起動したり、GooglePlay開発者サービスを再インストールしたりしました。この問題に関するヘルプは大歓迎です。

編集:古いgcm.jarとGCMRegistrarを使用してGCMを実装しようとしましたが、デバイスで動作することになりました。しかし、グーグルがこの方法のサポートを停止したので、私はこれが問題の良い解決策であるとはほとんど考えていません。

EDIT2:受け入れられた答えを参照してください。

16
idunnololz

私は同じ問題を経験しました。 GCMは、Android 4.04を実行しているタブレットでは正常に動作しますが、Android 2.3を実行しているスマートフォンでは常にSERVICE_NOT_AVAILABLEを受信します。

次の回避策では、(私が知る限り)非推奨のクラスを使用しないことがわかりました。マニフェストのGCMBroadcastReceiverにアクション「com.google.Android.c2dm.intent.REGISTRATION」を追加します。これにより、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を処理でき、スマートフォンにメッセージを送信できます。かなり奇妙ですが、それは私にとってはうまくいきます。

52
marnaish

このエラーは私にも発生しましたが、会社のファイアウォールを介してGCMに登録しようとしたために発生しました。そして私が見つけたドキュメントで:

「注:組織にインターネットとの間のトラフィックを制限するファイアウォールがある場合、Androidデバイスがメッセージを受信できるようにするには、GCMとの接続を許可するようにファイアウォールを構成する必要があります。ポート開くには、5228、5229、および5230があります。GCMは通常5228のみを使用しますが、5229および5230を使用する場合もあります。GCMは特定のIPを提供しないため、ファイアウォールがに含まれるすべてのIPアドレスへの発信接続を受け入れるようにする必要がありますGoogleの15169のASNにリストされているIPブロック。」

ポートを開くか、別のネットワークから試してみると、機能しました。

5
Edison Spencer

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で

2
Erik Zivkovic

SERVICE_NOT_AVAILABLEは、古いまたは欠落しているGooglePlay開発者サービスが原因である可能性があります。 GooglePlayServicesUtilを使用してバージョンを確認し、間違っている場合は市場にリダイレクトして、ユーザーが手動でインストールできるようにします。これにより、SERVICE_NOT_AVAILABLEが修正され、すべての改善とバグ修正(および新しいバグ:-)も取得されます。

これができない場合-register()を使用しても意味がない場合、メソッドは一致するプレイサービスが結果を取得することを期待します。下位互換性のために、同じブロードキャストを生成します。 REGISTERインテントを直接使用するか、廃止されたライブラリは引き続き機能します-インテントを使用することをお勧めします。GCMRegistrarはGoogleServicesFrameworkの古い実装に関連付けられているため(intent.setPackage(GSF_PACKAGE)への呼び出しがあります)、メリットはありません修正から。

自動インストールを取得しなかったデバイスを処理するためにGooglePlayServicesUtilを使用してGCMの最新バージョンを入手すると、登録だけでなく役立ちます。

2

同じ問題が発生しましたが、すべてのデバイスで発生していました。問題を見つけるのに永遠に時間がかかりましたが、他の人の場合と一致する場合に備えて投稿すると思いました。これが私の問題の簡略版です:

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()を使用してreturnを指定して2番目のAsyncTaskを追加すると、GcmBroadcastReceiver onReceive()から登録IDを取得できたとしても、毎回GCM'SERVICE_NOT_AVAILABLE 'を取得します。ただし、実行すると:

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を受け取ります。

0
MoreThanCarbon

それで、私をつまずかせたことに気をつけるべきもう一つのことがあります。エミュレーター+テストアプリケーションで正常に動作していましたが、実際のデバイスにデプロイする際に問題が発生しました。
常に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();

非同期のオフスレッド結果をブロックする「巧妙な/不正行為」の方法。

結局のところ、IS何が問題を引き起こしているのか。私がちょうど持っていたとたんに:

.execute();

それを通過させ、アルゴリズム/コードをレポートで機能させ、登録IDをすぐに必要としないようにすれば、問題はありませんでした。手動放送受信機も必要ありませんでしたが、正常に機能しました。

0
CasualT

これが古い投稿であることは知っていますが、すべてが正しくセットアップされていても、同じ問題が発生しました。 SERVICE_NOT_AVAILABLEエラーがポップアップし続けました。設定=>アプリ=> Google Play-サービスに移動し、キャッシュをクリアしてデータを削除すると、機能しました。

0
APvG

当分の間、Googleがこのバグを修正するか、誰かがより良い解決策を提供するまで、私はハイブリッドソリューションを使用しています。最初の数回はGoogle Player Servicesを使用しますが(指数バックオフあり)、その後GCMRegistrarに切り替えます。

0
idunnololz

マークされた答えがあなたのために機能しない場合(私にとってはそうでした)、あなたのデバイスの前にいる人をチェックし、多分それを振ってからインターネット接続を有効にしてください。私のために働いた;-)

インターネットがなければ、あなたは同じ例外を受け取り、私は午後をサービスの複雑な問題を追いかけて過ごしました。

0
philip