处理Android上的Google Cloud Messaging中的注册ID更改

And*_*Dev 77 android push-notification google-cloud-messaging

在Google Cloud Messaging的文档中,它指出:

Android应用程序应该存储此ID以供以后使用(例如,如果已经注册,则检查onCreate()).请注意,Google可能会定期刷新注册ID,因此您应该设计Android应用程序,并了解可能会多次调用com.google.android.c2dm.intent.REGISTRATION意图.您的Android应用程序需要能够做出相应的响应.

我使用以下代码注册我的设备:

GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
String regID = gcm.register(senderID);
Run Code Online (Sandbox Code Playgroud)

GoogleCloudMessaging类封装了注册过程.那么我想如何处理com.google.android.c2dm.intent.REGISTRATION,因为处理是由GoogleCloudMessaging类在内部完成的?

Era*_*ran 137

这是一个有趣的问题.

Google建议您切换到新的注册流程:

运行在移动设备上的Android应用程序通过调用GoogleCloudMessaging方法寄存器(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):

谷歌改变了他们的演示应用程序以使用新界面.他们通过在应用程序本地持久保存的值上设置到期日期来刷新注册ID.当应用程序启动时,它们会加载本地存储的注册ID.如果它"过期"(在演示中意味着它是在7天前从GCM收到的),他们gcm.register(senderID)再次打电话.

这不适用于Google针对尚未启动很长时间的应用更新注册ID的假设方案.在这种情况下,应用程序将不会知道更改,第三方服务器也不会.

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;
}
Run Code Online (Sandbox Code Playgroud)

编辑(08.14.2013):

谷歌再次改变他们的演示应用程序(两天前).这次他们删除了7天后认为注册ID过期的逻辑.现在,只有在安装了新版本的应用程序时,他们才会刷新注册ID.

编辑(04.24.2014):

为了完整起见,以下是Costin Manolache(取自此处)的话,这是一位参与GCM开发的Google开发人员,关于此事:

"周期性"刷新从未发生过,新的GCM库中不包含注册刷新.

注册ID更改的唯一已知原因是,如果应用程序在升级时收到消息,则会自动取消注册.在修复此错误之前,应用程序仍需要在升级后调用register(),到目前为止,注册ID可能会更改.显式调用unregister()通常也会更改注册ID.

建议/解决方法是生成您自己的随机标识符,例如保存为共享首选项.在每次应用升级时,您都可以上传标识符和可能的新注册ID.这也可以帮助跟踪和调试服务器端的升级和注册更改.

这解释了官方GCM演示应用程序的当前实现. com.google.android.c2dm.intent.REGISTRATION在使用GoogleCloudMessaging类注册时永远不应该处理.

  • +1编辑(04.24.2014)旧的SO问题和答案被误导并浪费了我的时间...希望每个人都发布一个编辑他们的旧答案,这些答案不再有效 (19认同)
  • 我们需要编辑GCM 3.0.https://developers.google.com/cloud-messaging/android/start (2认同)

mar*_*dan 6

阅读新的InstanceID API,我发现有关令牌可能更改的更多信息:

您的应用可以根据需要使用getToken()方法从Instance ID服务请求令牌,并且像InstanceID一样,您的应用也可以在您自己的服务器上存储令牌.发给您应用的所有令牌都属于该应用的InstanceID.

令牌是唯一且安全的,但是在安全问题或用户在设备恢复期间卸载并重新安装应用时,您的应用或Instance ID服务 可能需要刷新令牌.您的应用必须实现侦听器以响应来自Instance ID服务的令牌刷新请求.

更多细节:

Instance ID服务定期启动回调(例如,每6个月),请求您的应用刷新其令牌.它可能还会在以下情况下启动回调:

  • 存在安全问题; 例如,SSL或平台问题.
  • 设备信息不再有效; 例如,备份和还原.
  • 实例ID服务受到其他影响.

资料来源:

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

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