既存の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)
デバイスの時刻を確認してください。 Googleは間違った時間でデバイスを登録できません
この問題に遭遇したとき、私にとってうまくいったのは、Google Playアプリケーションを開くことでした。
デバイスの再起動後、GCM登録を試行する前に、少なくとも1回は起動する必要があるようです。
これは奇妙なものです。 GCMコードをonCreate()メソッドの最後に移動して解決しました。
私の推測では、CGMに登録しようとした時点で、アプリのコンテキストは完全には作成されていません。有効なコンテキストが必要です。
アプリをエミュレータで実行している場合は、Google Play Serviceをインストールする必要があります。
最近、GoogleネイティブエミュレーターからGenyMotionエミュレーターに切り替えたところ、このエラーが発生しました。後で、GenyMotionの画像がGoogle Playサービスに付属していないことに気付きました。インストール後、問題は解決しました。
昨日は自分で問題を解決しました。私はデモアプリケーションをフォローし、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();
}
現在は機能していますが、理由はわかりません。誰かが理由を説明できますか?ご協力いただきありがとうございます!