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


78

У документах 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?

Відповіді:


137

Це цікаве питання.

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 змінив демонстраційний додаток, щоб використовувати новий інтерфейс. Вони оновлюють реєстраційний ідентифікатор, встановлюючи термін дії для значення, яке зберігається локально програмою. Коли програма запускається, вони завантажують свій локально збережений реєстраційний ідентифікатор. Якщо термін дії "закінчився" (що в демонстраційній версії означає, що він був отриманий від 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 знову змінив демонстраційний додаток (два дні тому). Цього разу вони видалили логіку, згідно з якою реєстраційний ідентифікатор закінчується через 7 днів. Тепер вони оновлюють реєстраційний ідентифікатор лише тоді, коли з’являється нова версія встановленого додатка.

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

Для повноти, ось слова Костіна Манолаша (взято звідси ), розробника Google, який бере участь у розробці GCM, з цього приводу:

"Періодичне" оновлення ніколи не відбувалося, і оновлення реєстрації не входить до нової бібліотеки GCM.

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

Пропозиція / обхідне рішення полягає у створенні власного випадкового ідентифікатора, наприклад, збереженого як спільна перевага. Під час кожного оновлення програми ви можете завантажувати ідентифікатор та потенційно новий реєстраційний ідентифікатор. Це також може допомогти відстежувати та налагоджувати оновлення та зміни реєстрації на стороні сервера.

Це пояснює поточну реалізацію офіційного додатка GCM Demo. com.google.android.c2dm.intent.REGISTRATIONніколи не слід обробляти при використанні GoogleCloudMessagingкласу для реєстрації.


Я думаю, що ви правильно вказали свою відповідь і що будь-які зміни в regid можуть бути оброблені відповідями php або jsp на сервері програм проекту. Настав час, коли Google оновив свій демонстраційний код клієнта / сервера в комплекті з SDK!
NickT

Схоже, що документи Google застаріли. Клас GCMBaseIntentService при реалізації має onUnregistered, що викликається. Чи називається це, коли реєстраційний ідентифікатор оновлюється, не вказано. У розділі "Початок роботи" на GCM навіть не згадується GCMBaseIntentService, але він включений у зразок коду. Google дійсно повинен очистити свої документи.
AndroidDev

@AndroidDev Так, їхні документи на даний момент трохи брудні. Однак вони стверджують, що існує кілька способів реалізації GCM. Початок роботи показує новий спосіб, але він згадує (на кроці 3), що існує інший спосіб, і посилання на нього. GCMBaseIntentServiceдосі згадується на сторінці Використання допоміжних бібліотек GCM .
Еран

19
+1 для редагування (24.04.2014) старі запитання та відповіді на SO ввели в оману і витратили мій час ... бажаю, щоб усі опублікували редагування своїх старих відповідей, які більше не діють
Харшад Ранганатан,

2
Нам знадобиться редагувати GCM 3.0. developers.google.com/cloud-messaging/android/start
Коулаун,

6

Читаючи новий API InstanceID, я знайшов більше інформації про те, коли маркер може змінитися:

Ваш додаток може запитувати маркери у службі ідентифікатора екземпляра за потреби, використовуючи метод getToken (), і, як і InstanceID, ваш додаток також може зберігати маркери на вашому власному сервері. Усі маркери, видані у вашій програмі, належать до ідентифікатора інстанції програми.

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

Детальніше:

Служба ідентифікатора екземпляра періодично ініціює зворотні виклики (наприклад, кожні 6 місяців), вимагаючи, щоб ваша програма оновила свої маркери. Він також може ініціювати зворотні дзвінки, коли:

  • Є проблеми безпеки; наприклад, проблеми SSL або платформи.
  • Інформація про пристрій більше не дійсна; наприклад, резервне копіювання та відновлення.
  • В іншому випадку це впливає на службу ідентифікатора екземпляра.

Джерела:

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

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


2

Після очищення тонн оманливих відповідей у ​​мережі, включаючи 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.

З вищезгаданого посилання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.