web-dev-qa-db-ja.com

Android上のGoogle Cloud Messagingでの登録IDの変更の処理

Google Cloud Messagingのドキュメントには、次のように記載されています。

Androidアプリケーションは、後で使用するために(たとえば、onCreate()が既に登録されているかどうかを確認するために)このIDを格納する必要があります。 Googleは定期的に登録IDを更新する場合があるため、com.google.Android.c2dm.intent.REGISTRATIONインテントが複数回呼び出される可能性があることを理解して、Androidアプリケーションを設計する必要があります。 Androidアプリケーションはそれに応じて応答できる必要があります。

次のコードを使用してデバイスを登録します。

GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
String regID = gcm.register(senderID);

GoogleCloudMessagingクラスは、登録プロセスをカプセル化します。それでは、GoogleCloudMessagingクラスによって内部的に処理が行われるため、com.google.Android.c2dm.intent.REGISTRATIONをどのように処理するのでしょうか。

77
AndroidDev

それは興味深い質問です。

Googleでは、新しい登録プロセスに切り替えることをお勧めしています。

モバイルデバイスで実行されているAndroidアプリケーションは、GoogleCloudMessagingメソッドregister(senderID ...)を呼び出してメッセージを受信するように登録します。このメソッドは、GCMのアプリケーションを登録し、登録IDを返します。この合理化されたアプローチは、以前のGCM登録プロセスを置き換えます。

Google may periodically refresh the registration IDと書かれたメモは、古い登録プロセスがまだ表示されているページにのみ表示されるため、このメモはもはや関連性がない可能性があります。

安全にしたい場合は、古い登録プロセスを引き続き使用できます。または、新しいプロセスを使用できますが、com.google.Android.c2dm.intent.REGISTRATIONインテントを処理するコードを追加して、Googleが登録IDの更新を決定した場合に確実に対応できるようにします。

そうは言っても、そのような更新を経験することはなく、登録IDの変更(通常、アプリをアンインストールしてから再インストールした後に通知を送信した結果として)が発生した場合でも、古い登録IDは依然として正常に機能したため(Googleからの応答で正規の登録IDが送信されます)、害はありませんでした。

編集(06.06.2013):

Googleは、新しいインターフェイスを使用するように デモアプリ を変更しました。アプリによってローカルに保持される値に有効期限を設定することにより、登録IDを更新します。アプリが起動すると、ローカルに保存された登録IDを読み込みます。 「期限切れ」の場合(デモでは、7日以上前にGCMから受信したことを意味します)、彼らはgcm.register(senderID)を再度呼び出します。

これは、長時間起動されていないアプリの登録IDがGoogleによって更新されるという仮想シナリオを処理しません。その場合、アプリは変更を認識せず、サードパーティのサーバーも認識しません。

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);
    mDisplay = (TextView) findViewById(R.id.display);

    context = getApplicationContext();
    regid = getRegistrationId(context);

    if (regid.length() == 0) {
        registerBackground();
    }
    gcm = GoogleCloudMessaging.getInstance(this);
}

/**
 * Gets the current registration id for application on GCM service.
 * <p>
 * If result is empty, the registration has failed.
 *
 * @return registration id, or empty string if the registration is not
 *         complete.
 */
private String getRegistrationId(Context context) {
    final SharedPreferences prefs = getGCMPreferences(context);
    String registrationId = prefs.getString(PROPERTY_REG_ID, "");
    if (registrationId.length() == 0) {
        Log.v(TAG, "Registration not found.");
        return "";
    }
    // check if app was updated; if so, it must clear registration id to
    // avoid a race condition if GCM sends a message
    int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
    int currentVersion = getAppVersion(context);
    if (registeredVersion != currentVersion || isRegistrationExpired()) {
        Log.v(TAG, "App version changed or registration expired.");
        return "";
    }
    return registrationId;
}

/**
 * Checks if the registration has expired.
 *
 * <p>To avoid the scenario where the device sends the registration to the
 * server but the server loses it, the app developer may choose to re-register
 * after REGISTRATION_EXPIRY_TIME_MS.
 *
 * @return true if the registration has expired.
 */
private boolean isRegistrationExpired() {
    final SharedPreferences prefs = getGCMPreferences(context);
    // checks if the information is not stale
    long expirationTime =
            prefs.getLong(PROPERTY_ON_SERVER_EXPIRATION_TIME, -1);
    return System.currentTimeMillis() > expirationTime;
}

編集(2013年8月14日):

Googleが デモアプリ を再び変更しました(2日前)。今回は、登録IDが7日後に期限切れになると見なすロジックを削除しました。これで、新しいバージョンのアプリがインストールされたときにのみ登録IDが更新されます。

編集(04.24.2014):

完全を期すために、GCMの開発に携わったGoogle開発者であるCostin Manolacheの言葉( here から引用)を以下に示します。

「定期的な」更新は行われず、登録の更新は新しいGCMライブラリに含まれていません。

登録IDの変更の唯一の既知の原因は、アップグレード中にメッセージを受信した場合にアプリが自動的に登録解除されるという古いバグです。このバグが修正されるまで、アプリはアップグレード後にregister()を呼び出す必要があり、これまでのところ、登録IDはこの場合変更される可能性があります。通常、unregister()を明示的に呼び出すと、登録IDも変更されます。

提案/回避策は、たとえば共有設定として保存された独自のランダム識別子を生成することです。アプリをアップグレードするたびに、識別子と潜在的に新しい登録IDをアップロードできます。これは、サーバー側でのアップグレードと登録の変更の追跡とデバッグにも役立ちます。

これは、公式のGCMデモアプリケーションの現在の実装について説明しています。 GoogleCloudMessagingクラスを使用して登録する場合、com.google.Android.c2dm.intent.REGISTRATIONを処理しないでください。

137
Eran

新しいInstanceID APIを読んで、トークンがいつ変更されるかについての詳細を見つけました。

アプリは、必要に応じてgetToken()メソッドを使用してインスタンスIDサービスからトークンをリクエストできます。また、InstanceIDと同様に、アプリは独自のサーバーにトークンを保存できます。アプリに発行されるすべてのトークンは、アプリのInstanceIDに属します。

トークンは一意で安全ですが、アプリまたはインスタンスIDサービスは、セキュリティの問題が発生した場合、またはユーザーがデバイスの復元中にアプリをアンインストールおよび再インストールした場合にトークンを更新する必要がある場合があります。アプリは、インスタンスIDサービスからのトークン更新リクエストに応答するリスナーを実装する必要があります。

詳細:

インスタンスIDサービスは、定期的に(たとえば、6か月ごとに)コールバックを開始し、アプリがトークンを更新することを要求します。また、次の場合にコールバックを開始する場合があります。

  • セキュリティ上の問題があります。たとえば、SSLまたはプラットフォームの問題。
  • デバイス情報は無効になりました。たとえば、バックアップと復元。
  • それ以外の場合、インスタンスIDサービスが影響を受けます。

ソース:

https://developers.google.com/instance-id/

https://developers.google.com/instance-id/guides/Android-implementation

6
marius bardan

SOを含む大量の誤解を招く答えをネット上でスクラブした後、完全な答えを見つけた唯一の場所は、Eranの答えと here で述べたとおりでした。

自動登録の更新は行われる場合と行われない場合がありますが、googleは成功した応答を解析してcanocical_idsを処理する同様のアルゴリズムを説明しています。

If the value of failure and canonical_ids is 0, it's not necessary to parse the remainder of the response. Otherwise, we recommend that you iterate through the results field and do the following for each object in that list:

If message_id is set, check for registration_id:
If registration_id is set, replace the original ID with the new value (canonical ID) in your server database. Note that the original ID is not part of the result, so you need to obtain it from the list of code>registration_ids passed in the request (using the same index).
Otherwise, get the value of error:
If it is Unavailable, you could retry to send it in another request.
If it is NotRegistered, you should remove the registration ID from your server database because the application was uninstalled from the device or it does not have a broadcast receiver configured to receive com.google.Android.c2dm.intent.RECEIVE intents.
Otherwise, there is something wrong in the registration ID passed in the request; it is probably a non-recoverable error that will also require removing the registration from the server database. See Interpreting an error response for all possible error values.

前述のリンクから。

2
rahulserver