web-dev-qa-db-ja.com

java.io.IOException:GCMクライアントのSERVICE_NOT_AVAILABLE

既存のAndroidアプリにgcmクライアントを実装したいので、 this チュートリアルに従って、次のコードを書きました。

public class RegisterForGCMAsyncTask extends AbstractSecureOperationTask {

...

@Override
protected Boolean doInBackground(String... params) {
    String token = authenticate();
    getRegId();
    if (TextUtils.isEmpty(registrationId)) {
        return false;
    }
    //
    try {
        URL url = convertToURLEscapingIllegalCharacters(String.format(Constants.REGISTER_URL,
                registrationId, userId, token));
        URLConnection connection = url.openConnection();
        InputStreamReader streamReader = new InputStreamReader(connection.getInputStream());
        JSONParser parser = new JSONParser();
        JSONObject rootObj = (JSONObject) parser.parse(streamReader);
        String status = rootObj.get("status").toString();
        if (status.equals("OK")) {
            return true;
        }
    } catch (ParseException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return false;
}

private void getRegId() {
    try {
        if (gcm == null) {
            gcm = GoogleCloudMessaging.getInstance(context);
        }
        registrationId = gcm.register(PROJECT_ID);
    } catch (IOException e) {
        Log.e(LOG_TAG, e.getMessage(), e);
    }
}
}

AndroidMainfest:

<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
      package="de.xxxxxxxx.xxxxxxxx"
      Android:versionCode="20140617"
      Android:versionName="2.0.0">

<uses-sdk
        Android:minSdkVersion="15"
        Android:targetSdkVersion="19"/>

<uses-permission Android:name="Android.permission.INTERNET"/>
<uses-permission Android:name="Android.permission.GET_ACCOUNTS"/>
<uses-permission Android:name="Android.permission.WAKE_LOCK"/>
<uses-permission Android:name="Android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission Android:name="Android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission Android:name="Android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission Android:name="com.google.Android.c2dm.permission.RECEIVE"/>
<uses-permission Android:name="com.google.Android.providers.gsf.permission.READ_GSERVICES"/>

<permission
        Android:name="de.xxxxxxxx.xxxxxxxx.permission.MAPS_RECEIVE"
        Android:protectionLevel="signature"/>
<uses-permission Android:name="de.xxxxxxxx.xxxxxxxx.permission.MAPS_RECEIVE"/>

<permission
        Android:name="de.xxxxxxxx.xxxxxxxx.permission.C2D_MESSAGE"
        Android:protectionLevel="signature"/>
<uses-permission Android:name="de.xxxxxxxx.xxxxxxxx.permission.C2D_MESSAGE"/>


<!-- Maps API needs OpenGL ES 2.0. -->
<uses-feature
        Android:glEsVersion="0x00020000"
        Android:required="true"/>

<application
        Android:allowBackup="true"
        Android:icon="@drawable/ic_launcher"
        Android:label="@string/app_name"
        Android:theme="@style/AppTheme">

    <activity
            Android:name="de.retterapps.Handyalarm.views.activities.MainActivity"
            Android:configChanges="orientation|screenLayout|screenSize|layoutDirection"
            Android:label="@string/app_name"
            Android:theme="@style/AppTheme">
        <intent-filter>
            <action Android:name="Android.intent.action.MAIN"/>

            <category Android:name="Android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>

    <receiver
            Android:name=".helper.gcm.GcmBroadcastReceiver"
            Android:permission="com.google.Android.c2dm.permission.SEND">
        <intent-filter>
            <action Android:name="com.google.Android.c2dm.intent.RECEIVE"/>
            <category Android:name="de.xxxxxxxx.xxxxxxxx"/>
        </intent-filter>
    </receiver>
    <service Android:name=".helper.gcm.GcmMessageHandler"/>

    <meta-data
            Android:name="com.google.Android.gms.version"
            Android:value="@integer/google_play_services_version"/>
    <meta-data
            Android:name="com.google.Android.maps.v2.API_KEY"
            Android:value="xxxxxxxx"/>
</application>

昨日はすべてうまくいき、私は登録IDを取得できました。しかし今、常にIOExceptionと言ってSERVICE_NOT_AVAILABLE

Samsung Galaxy S5とGenymotionエミュレーター(Android 4.1.2)でテストしましたが、常に同じ結果が得られます。誰かが問題を解決する方法を考えていますか?

編集する

ここに完全なスタックトレースがあります:

Java.io.IOException: SERVICE_NOT_AVAILABLE
    at com.google.Android.gms.gcm.GoogleCloudMessaging.register(Unknown Source)
    at de.retterapps.Handyalarm.helper.tasks.RegisterForGCMAsyncTask.getRegId(RegisterForGCMAsyncTask.Java:72)
    at de.retterapps.Handyalarm.helper.tasks.RegisterForGCMAsyncTask.doInBackground(RegisterForGCMAsyncTask.Java:43)
    at de.retterapps.Handyalarm.helper.tasks.RegisterForGCMAsyncTask.doInBackground(RegisterForGCMAsyncTask.Java:24)
    at Android.os.AsyncTask$2.call(AsyncTask.Java:287)
    at Java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.Java:305)
    at Java.util.concurrent.FutureTask.run(FutureTask.Java:137)
    at Android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.Java:230)
    at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1076)
    at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:569)
    at Java.lang.Thread.run(Thread.Java:856)
15
Robin

デバイスの時刻を確認してください。 Googleは間違った時間でデバイスを登録できません

27

この問題に遭遇したとき、私にとってうまくいったのは、Google Playアプリケーションを開くことでした。

デバイスの再起動後、GCM登録を試行する前に、少なくとも1回は起動する必要があるようです。

10
Tom Susel

これは奇妙なものです。 GCMコードをonCreate()メソッドの最後に移動して解決しました。

私の推測では、CGMに登録しようとした時点で、アプリのコンテキストは完全には作成されていません。有効なコンテキストが必要です。

アプリをエミュレータで実行している場合は、Google Play Serviceをインストールする必要があります。

最近、GoogleネイティブエミュレーターからGenyMotionエミュレーターに切り替えたところ、このエラーが発生しました。後で、GenyMotionの画像がGoogle Playサービスに付属していないことに気付きました。インストール後、問題は解決しました。

0
sishuo yang

昨日は自分で問題を解決しました。私はデモアプリケーションをフォローし、registerInBackground()メソッドのAsyncTaskを単純なJavaスレッドに変更しました。コードは次のとおりです。

private void registerInBackground() {
    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0:
                    Toast.makeText(context, getString(R.string.txt_gcm_registered), Toast.LENGTH_LONG).show();
                    break;
                case 1:
                    Toast.makeText(context, getString(R.string.error_register_gcm), Toast.LENGTH_LONG).show();
                    break;
            }
            super.handleMessage(msg);
        }

    };
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                if (gcm == null) {
                    gcm = GoogleCloudMessaging.getInstance(context);
                }
                regId = gcm.register(Constants.SENDER_ID);

                if (sendRegistrationIdToBackend(regId)) {
                    handler.sendEmptyMessage(0);
                } else {
                    handler.sendEmptyMessage(1);
                }

                storeRegistrationId(context, regId);
            } catch (IOException ex) {
                handler.sendEmptyMessage(1);
                Log.e(LOG_TAG, ex.getMessage(), ex);
            }
        }
    };
    new Thread(runnable).start();
}

現在は機能していますが、理由はわかりません。誰かが理由を説明できますか?ご協力いただきありがとうございます!

0
Robin