GCMについてはすでに書かれています。 この記事の目的は何ですか?
そうです、彼らは書きました。 文字通り今週、Habréで記事GCMが公開されました-Google からのプッシュ通知の新しいサービス (Android向けのGoogle Cloud Messagingに慣れていない場合は、特に私の記事ではプロジェクトの作成プロセスについて説明していないため、この記事を読む前に読むことをお勧めします) GCMを使用)。 著者GCMが実際のアプリケーションで使用したかどうかはわかりませんが、私はしなければなりませんでした。 それが、前の記事で場所を見つけられなかったか、説明されなかった何かを説明したい理由です。 前の記事にコメント付きでこれらすべてを追加するために、私は不可能な仕事を恐れています。
必要な許可
ここではすべてが明らかです。インターネットにアクセスしなければGCMは必要ありません。<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
PowerManager.WakeLock
をキャプチャすることをおPowerManager.WakeLock
ます。 したがって、標準のGCMライブラリを使用する場合は、そのような許可を追加する必要があります。
要するに、作業のメカニズムは次のとおりです。アプリケーションは、ブロードキャスト要求を受信するためにサブスクライブします。 要求を受信すると、受信したIntentをGCMBaseIntentService
拡張するサービスの名前のクラス名(setClassName()
)にWakeLock
し、PowerManager.PARTIAL_WAKE_LOCK
フラグでWakeLock
をPowerManager.PARTIAL_WAKE_LOCK
ます(CPUのみがスリープ状態にならない、画面がスリープ状態になりません)、Intentをサービスとして起動します。onHandleIntent
サービスを終了すると、無料のWakeLock
ます。
彼らはこの許可を信じず、追加もしませんでしたが、最終的にこの例外が発生します。
java.lang.SecurityException: Neither user 10110 nor current process has android.permission.WAKE_LOCK.
<permission android:name="{ }.permission.C2D_MESSAGE" android:protectionLevel="signature" /> <uses-permission android:name="{ }.permission.C2D_MESSAGE" />
注:minSdkVersion
を16
以上(Jelly Bean以降のバージョン)に設定する場合、この許可は必要ありません(2年後、省略できることを望みます)。<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
登録コード(registationId)は変更されていますか?
サンプルアプリケーションのコードを考えてみましょう。
final String regId = GCMRegistrar.getRegistrationId(this); if (regId.equals("")) { // Automatically registers application on startup. GCMRegistrar.register(this, SENDER_ID); }
他の条件はないようです。 だから、変わらない? このリンクhttp://developer.android.com/intl/en/guide/google/gcm/adv.html#reg-stateをクリックすると、何が変更される可能性があるかがわかります。 次の2つのケースがあります。
- プログラム更新
- バックアップを作成してそこから復元する
プログラムの更新を確認するために、小さなヘルパークラスを作成しました。 誰かが役に立つかもしれません:
import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.preference.PreferenceManager; public final class ApplicationVersionHelper { public static final String APP_VERSION_PREFS = "application_version"; public static boolean isApplicationVersionCodeEqualsSavedApplicationVersionCode(Context context) { return getApplicationVersionCode(context) == getApplicationVersionCodeFromPreferences(context); } public static int getApplicationVersionCode(Context context) { PackageManager pm = context.getPackageManager(); PackageInfo packageInfo; int applicationVersion = 1; try { packageInfo = pm.getPackageInfo(context.getPackageName(), 0); applicationVersion = packageInfo.versionCode; } catch (NameNotFoundException ignored) { } return applicationVersion; } public static int getApplicationVersionCodeFromPreferences(Context context) { return context.getSharedPreferences(APP_VERSION_PREFS, Context.MODE_PRIVATE).getInt("application_version_code", 0); } public static void putCurrentPackageVersionInPreferences(Context context) { context.getSharedPreferences(APP_VERSION_PREFS, Context.MODE_PRIVATE).edit().putInt("application_version_code", getApplicationVersionCode(context)).commit(); } }
設定は
PreferenceManager.getDefaultSharedPreferences
からではなく、指定された設定ファイルから取得されることに注意してください。 これが行われる理由は、後で説明します。
ここで、GCMおよびサービスでの登録が成功した後、
putCurrentPackageVersionInPreferences
を呼び出す必要があり、登録確認コードは次のようになります。
final String regId = GCMRegistrar.getRegistrationId(this); if (regId.equals("") || !isApplicationVersionCodeEqualsSavedApplicationVersionCode(this)) { // Automatically registers application on startup. GCMRegistrar.register(this, SENDER_ID); }
バックアップの作成を処理するため(誰もがこの機能についてまったく知っているわけではありません。おもしろくなった場合は、 http://developer.android.com/intl/en/guide/topics/data/backup.htmlを読んでください)次の解決策を提案します:バックアップ時に定数
ApplicationVersionHelper.APP_VERSION_PREFS
名前で設定を保存しないでください。 そのため、名前付き設定ファイルが便利になりました:)その後、
isApplicationVersionCodeEqualsSavedApplicationVersionCode
はデータを復元するときに
false
を返し、登録要求を送信します。
GCMIntentServiceのハンドラー
GCMIntentService
(
GCMIntentService
から継承された
GCMBaseIntentService
)
いくつかのメソッドを再定義する必要があります。 簡単に言うと:
protected void onRegistered(Context context, String registrationId)
registrationId
をサーバーに転送する必要があります。protected void onUnregistered(Context context, String registrationId)
registrationId
をサーバーに転送します(多くのアプリケーションはこの機能を使用しません)protected void onMessage(Context context, Intent intent)
intent
protected void onDeletedMessages(Context context, int total)
public void onError(Context context, String errorId)
errorId
エラーコードでのデータ受信中の回復不能エラーprotected boolean onRecoverableError(Context context, String errorId)
errorId
エラーコードでのデータ受信中の回復可能なエラー。true
を返したtrue
、別の試行を行い、false
場合、試行を停止します。 このメソッドでsuper.onRecoverableError(context, errorId);
を返すことをお勧めしますsuper.onRecoverableError(context, errorId);
自分で掃除します!
登録プロセスを実行している場合は、忘れずにキャンセルし、メインアクティビティのonDestroyメソッドでGCMRegistrar.onDestroyを呼び出します。 以下がその方法です。
@Override protected void onDestroy() { if (registerTask != null) { registerTask.cancel(true); } try { CMRegistrar.onDestroy(this); } catch(Exception ignored) { } super.onDestroy(); }
ここでのregisterTask
は、非同期ジョブ(
AsyncTask
)です。
おわりに
アプリケーションでGCMを使用する前にhttp://developer.android.com/intl/en/guide/google/gcm/index.htmlを読んで(5つのポイントがあります)、質問がある場合(WAKE_LOCK許可について)、ソースコードに入ることを恐れないでください。