it-swarm.com.ru

Обработка изменений регистрационного идентификатора в Google Cloud Messaging в Android

В документах по Google Cloud Messaging говорится:

Приложение Android должно сохранить этот идентификатор для последующего использования (например, для проверки onCreate (), если он уже зарегистрирован). Обратите внимание, что Google может периодически обновлять регистрационный идентификатор, поэтому вам следует разработать свое приложение Android с учетом того, что намерение com.google.Android.c2dm.intent.REGISTRATION может вызываться несколько раз. Ваше приложение Android должно иметь возможность отвечать соответствующим образом.

Я регистрирую свое устройство, используя следующий код:

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

Класс GoogleCloudMessaging инкапсулирует процесс регистрации. Итак, как я должен обрабатывать com.google.Android.c2dm.intent.REGISTRATION, поскольку внутренняя обработка выполняется классом GoogleCloudMessaging?

77
AndroidDev

Это интересный вопрос.

Google рекомендует вам перейти на новый процесс регистрации:

Приложение Android, работающее на мобильном устройстве, регистрируется для получения сообщений, вызывая регистр метода GoogleCloudMessaging (senderID ...). Этот метод регистрирует приложение для GCM и возвращает регистрационный идентификатор. Этот оптимизированный подход заменяет предыдущий процесс регистрации GCM.

Заметка с надписью Google may periodically refresh the registration ID появляется только на странице, на которой все еще показан старый процесс регистрации, поэтому возможно, что эта заметка больше не актуальна.

Если вы хотите быть в безопасности, вы все равно можете использовать старый процесс регистрации. Или вы можете использовать новый процесс, но дополнительно иметь код, который обрабатывает намерение com.google.Android.c2dm.intent.REGISTRATION, чтобы убедиться, что вы застрахованы, если Google все же решит обновить регистрационный идентификатор.

Тем не менее, я никогда не сталкивался с таким обновлением, и даже когда у меня действительно было изменение в регистрационном идентификаторе (обычно в результате отправки уведомления после удаления приложения и последующей его переустановки), старый регистрационный идентификатор все еще работал (в результате чего канонический регистрационный идентификатор, отправленный в ответе от Google), так что никакого вреда не было.

РЕДАКТИРОВАТЬ (06.06.2013):

Google изменил их Demo App , чтобы использовать новый интерфейс. Они обновляют регистрационный идентификатор, устанавливая дату истечения срока действия для значения, сохраняемого локально приложением. Когда приложение запускается, они загружают свой локально сохраненный регистрационный идентификатор. Если срок его действия истек (что в демоверсии означает, что он был получен от GCM более 7 дней назад), они снова вызывают gcm.register(senderID).

Это не относится к гипотетическому сценарию, в котором 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;
}

РЕДАКТИРОВАТЬ (14.08.2013):

Google изменил их Demo App еще раз (два дня назад). На этот раз они удалили логику, которая считает, что срок действия регистрационного идентификатора истек через 7 дней. Теперь они обновляют регистрационный идентификатор только тогда, когда установлена ​​новая версия приложения.

РЕДАКТИРОВАТЬ (24.04.2014):

Для полноты изложения приведем слова Костина Манолаха (взято из здесь ), разработчика Google, занимающегося разработкой GCM:

"Периодическое" обновление никогда не происходило, и обновление регистрации не включено в новую библиотеку GCM.

Единственная известная причина изменения регистрационного идентификатора - старая ошибка приложений, автоматически незарегистрированных, если они получают сообщение при обновлении. Пока эта ошибка не исправлена, приложения все равно должны вызывать register () после обновления, и пока в этом случае может измениться идентификатор регистрации. Вызов unregister () явно также изменяет регистрационный идентификатор.

Предложение/обходной путь заключается в создании собственного случайного идентификатора, сохраненного, например, в качестве общего предпочтения. При каждом обновлении приложения вы можете загружать идентификатор и потенциально новый регистрационный идентификатор. Это также может помочь в отслеживании и отладке обновлений и изменений регистрации на стороне сервера.

Это объясняет текущую реализацию официального демонстрационного приложения GCM. com.google.Android.c2dm.intent.REGISTRATION никогда не должен обрабатываться при использовании класса GoogleCloudMessaging для регистрации.

137
Eran

Читая новый API InstanceID, я нашел больше информации о том, когда токен может измениться:

Ваше приложение может запрашивать токены из службы ID экземпляра по мере необходимости, используя метод getToken (), и, подобно InstanceID, ваше приложение может также хранить токены на вашем собственном сервере. Все токены, выпущенные для вашего приложения, принадлежат InstanceID приложения.

Токены являются уникальными и безопасными, но вашему приложению или службе идентификатора экземпляра может потребоваться обновить токены в случае проблемы безопасности или когда пользователь удаляет и переустанавливает ваше приложение во время восстановления устройства . Ваше приложение должно реализовать прослушиватель для ответа на запросы обновления токена от службы Instance ID.

Больше деталей:

Служба Instance ID периодически инициирует обратные вызовы (например, каждые 6 месяцев), запрашивая, чтобы ваше приложение обновляло свои токены. Он также может инициировать обратные вызовы, когда:

  • Есть проблемы с безопасностью; например, проблемы с SSL или платформой.
  • Информация об устройстве больше не действительна; например, резервное копирование и восстановление.
  • В противном случае это влияет на службу Instance ID.

Источники:

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

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

6
marius bardan

После очистки тонны вводящих в заблуждение ответов по сети, включая SO, единственное место, где я нашел полный ответ, было отмечено ответом Эрана и здесь :

Хотя автоматическое обновление регистрации может произойти, а может и не произойти, 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