コンソールへ移動

非推奨: gcm.register() による登録トークンの取得

登録状態の同期処理

次の 2 つの状況では register() の使用時に特別な注意が必要です。

  • クライアント アプリの更新
  • バックアップと復元

クライアント アプリの更新: クライアント アプリを更新するときは、既存の登録 ID が新しいバージョンで動作することが保証されないため、その ID を無効にする必要があります。おすすめの方法は、登録 ID を保存する際に現在のアプリのバージョンを格納し、クライアント アプリが起動された際に、この保存した値を現在のアプリのバージョンと比較することです。両者が一致しない場合は、保存されたデータを無効にして再度登録処理を開始します。

バックアップと復元: クライアント アプリをバックアップする際は、登録 ID を保存しないでください。登録 ID は、クライアント アプリの復元時まで有効のままであるとは限らず、登録 ID が無効であればクライアント アプリも無効な状態になるからです(つまり、アプリでは登録済みであると認識されるものの、GCM ではその登録 ID が保存されなくなるため、アプリでメッセージが取得されなくなります)。アプリが初めてインストールされるときのように、登録プロセスを開始する方法がおすすめです。

複数の送信者からのメッセージ受信

複数の送信者からメッセージを受信するには、クライアント アプリでアプリサーバーの送信者 ID をカンマで区切って指定し、register() を呼び出します。

クライアント アプリでの register() の実装

次のスニペットでは、サンプルアプリのメイン アクティビティである onCreate() メソッドで、アプリがすでに GCM とサーバーに登録されているかどうかをチェックします。

/**
 * Main UI for the demo app.
 */
public class DemoActivity extends Activity {

    public static final String EXTRA_MESSAGE = "message";
    public static final String PROPERTY_REG_ID = "registration_id";
    private static final String PROPERTY_APP_VERSION = "appVersion";
    private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;

    /**
     * Substitute you own sender ID here. This is the project number you got
     * from the API Console.
     */
    String SENDER_ID = "Your-Sender-ID";

    /**
     * Tag used on log messages.
     */
    static final String TAG = "GCMDemo";

    TextView mDisplay;
    GoogleCloudMessaging gcm;
    AtomicInteger msgId = new AtomicInteger();
    SharedPreferences prefs;
    Context context;

    String regid;

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

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

        context = getApplicationContext();

        // Check device for Play Services APK. If check succeeds, proceed with
        //  Firebase Cloud Messaging registration.
        if (checkPlayServices()) {
            gcm = GoogleCloudMessaging.getInstance(this);
            regid = getRegistrationId(context);

            if (regid.isEmpty()) {
                registerInBackground();
            }
        } else {
            Log.i(TAG, "No valid Google Play Services APK found.");
        }
    }
...
}

アプリでは getRegistrationId() を呼び出し、既存の登録トークンが共有プリファレンスに格納されているかどうかを確認します。

/**
 * Gets the current registration token for application on Firebase Cloud Messaging service.
 * <p>
 * If result is empty, the app needs to register.
 *
 * @return registration token, or empty string if there is no existing
 *         registration token.
 */
private String getRegistrationId(Context context) {
    final SharedPreferences prefs = getGCMPreferences(context);
    String registrationId = prefs.getString(PROPERTY_REG_ID, "");
    if (registrationId.isEmpty()) {
        Log.i(TAG, "Registration not found.");
        return "";
    }
    // Check if app was updated; if so, it must clear the registration ID
    // since the existing registration ID is not guaranteed to work with
    // the new app version.
    int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
    int currentVersion = getAppVersion(context);
    if (registeredVersion != currentVersion) {
        Log.i(TAG, "App version changed.");
        return "";
    }
    return registrationId;
}
...
/**
 * @return Application's {@code SharedPreferences}.
 */
private SharedPreferences getGCMPreferences(Context context) {
    // This sample app persists the registration ID in shared preferences, but
    // how you store the registration ID in your app is up to you.
    return getSharedPreferences(DemoActivity.class.getSimpleName(),
            Context.MODE_PRIVATE);
}

登録 ID が存在しなかったりアプリが更新されたりした場合、getRegistrationId() は空の文字列を返し、アプリが新しい登録 ID を取得する必要があることを示します。getRegistrationId() は次のメソッドを呼び出し、アプリのバージョンを確認します。

/**
 * @return Application's version code from the {@code PackageManager}.
 */
private static int getAppVersion(Context context) {
    try {
        PackageInfo packageInfo = context.getPackageManager()
                .getPackageInfo(context.getPackageName(), 0);
        return packageInfo.versionCode;
    } catch (NameNotFoundException e) {
        // should never happen
        throw new RuntimeException("Could not get package name: " + e);
    }
}

既存の有効な登録 ID がない場合、DemoActivity は以下の registerInBackground() メソッドを呼び出して登録を行います。GCM メソッドの register()unregister() はブロッキング メソッドであるため、バックグラウンド スレッドで実行する必要があります。このサンプルでは AsyncTask を使用してこれを行います。

/**
 * Registers the application with Firebase Cloud Messaging connection servers asynchronously.
 * <p>
 * Stores the registration ID and app versionCode in the application's
 * shared preferences.
 */
private void registerInBackground() {
    new AsyncTask() {
        @Override
        protected String doInBackground(Void... params) {
            String msg = "";
            try {
                if (gcm == null) {
                    gcm = GoogleCloudMessaging.getInstance(context);
                }
                regid = gcm.register(SENDER_ID);
                msg = "Device registered, registration ID=" + regid;

                // You should send the registration ID to your server over HTTP,
                // so it can use HTTP or CCS to send messages to your app.
                // The request to your server should be authenticated if your app
                // is using accounts.
                sendRegistrationIdToBackend();

                // For this demo: we don't need to send it because the device
                // will send upstream messages to a server that echo back the
                // message using the 'from' address in the message.

                // Persist the registration ID - no need to register again.
                storeRegistrationId(context, regid);
            } catch (IOException ex) {
                msg = "Error :" + ex.getMessage();
                // If there is an error, don't just keep trying to register.
                // Require the user to click a button again, or perform
                // exponential back-off.
            }
            return msg;
        }

        @Override
        protected void onPostExecute(String msg) {
            mDisplay.append(msg + "\n");
        }
    }.execute(null, null, null);
    ...
}

登録 ID を受信したら、それをサーバーに送信します。

/**
 * Sends the registration ID to your server over HTTP, so it can use HTTP
 * or CCS to send messages to your app. Not needed for this demo since the
 * device sends upstream messages to a server that echoes back the message
 * using the 'from' address in the message.
 */
private void sendRegistrationIdToBackend() {
    // Your implementation here.
}

ID の登録後、アプリでは storeRegistrationId() を呼び出し、今後の使用のために登録 ID を共有プリファレンスに格納します。これは登録 ID を永続化するための 1 つの方法ですが、ご自身のアプリでは別の方法を使用しても構いません。

/**
 * Stores the registration ID and app versionCode in the application's
 * {@code SharedPreferences}.
 *
 * @param context application's context.
 * @param regId registration ID
 */
private void storeRegistrationId(Context context, String regId) {
    final SharedPreferences prefs = getGCMPreferences(context);
    int appVersion = getAppVersion(context);
    Log.i(TAG, "Saving regId on app version " + appVersion);
    SharedPreferences.Editor editor = prefs.edit();
    editor.putString(PROPERTY_REG_ID, regId);
    editor.putInt(PROPERTY_APP_VERSION, appVersion);
    editor.commit();
}

登録の解除

クライアント アプリでは unregister() を使用して GCM の登録を解除できます。これにより、クライアント アプリが持つ GCM に関するすべての登録トークンが登録解除されます。この方法を使用して、クライアント アプリでのメッセージの受信を停止することができます。

登録 ID が完全に GCM から削除されるまで、しばらく時間がかかる可能性があります。そのため、メッセージがクライアント アプリに配信されないにもかかわらず、メッセージに有効な応答のメッセージ ID が与えられる場合があります。最終的には、登録 ID が削除されサーバーに NotRegistered エラーが返されますが、アプリサーバーには特に何の処理も要求されません(アプリが開発中かテスト中であるとき、この状況がよく発生します)。

登録エラーの処理

Android アプリは、メッセージを受信する前に FCM 接続サーバーに登録し、登録 ID を取得する必要があります。与えられた登録 ID が無期限に有効であるとは保証されないため、上記のコード スニペットで示したように、アプリでは最初に有効な登録 ID があるかどうかを必ず確認してください。

有効な登録 ID の有無を確認することに加えて、アプリでは登録エラー TOO_MANY_REGISTRATIONS を処理できるよう準備する必要があります。このエラーは、端末に含まれる GCM 登録済みのアプリの数が極端に多い場合に発生するものであり、平均的なユーザーには影響しないと考えられます。この状況を緩和するには、デバイスから他のクライアント アプリをいくつか削除して、新しいアプリ用の領域を空けるようユーザーに依頼してください。