在GoogleCloudMessaging API中,如何处理注册ID的续订或到期?

5
作为这个问题的答案,如何找出注册IDGoogleCloudMessaging API中何时失效? 我已经阅读了几个类似主题的问题的答案:GCM注册ID是否过期?Google Coud Mesaging(GCM)和registration_id到期,我怎么知道?。那些问题的问题在于那里的答案是针对C2DM或旧的GCM API的,该API使用GCMRegistrar而不是GoogleCloudMessaging API。之前的两种方法已经过时。 我将尝试逐步解决我的困惑/问题:

1)启用GCM 标题下,第二点中提到:

谷歌可能会定期刷新注册ID,因此您应该在设计 Android 应用程序时理解 com.google.android.c2dm.intent.REGISTRATION 意图可能被调用多次。您的 Android 应用程序需要能够相应地响应。

注册 ID 将持续到 Android 应用明确注销自己,或者直到谷歌刷新您的 Android 应用的注册 ID 为止。每当应用程序收到一个带有 registration_id 额外信息的 com.google.android.c2dm.intent.REGISTRATION 意图时,它应该保存该 ID 以供将来使用,将其传递给第三方服务器以完成注册,并跟踪服务器是否已完成注册。如果服务器未能完成注册,则应重试或从 GCM 注销。

2) 如果是这种情况,那么我应该在BroadcastReceiver中处理意图并再次发送register()请求以获取新的注册ID。但问题在于在同一个页面下的ERROR_MAIN_THREAD标题下,它说: GCM方法是阻塞的。您不应该在主线程或广播接收器中运行它们。

3) 我还了解到当注册ID更改时有其他两种情况(如在保持注册状态同步标题下的高级主题中提到):应用程序更新和备份与恢复。我已经在打开应用程序时处理它们了。

4) 在GCMRegistrar API中,GCMBaseIntentService内部曾经有一个回调onRegistered()方法,当设备注册时会调用它。我曾在这里持久化注册ID并发送给第三方服务器。

但是,现在我应该如何处理注册ID的更新或续订,以及如何持久化并发送到第三方服务器呢?

可能是我读错了还是漏掉了什么。非常感谢您的帮助。

更新

即使在Handling registration ID changes in Google Cloud Messaging on Android线程中,也没有提到如何处理Google定期刷新ID的问题?


可能是这个问题的重复 - https://dev59.com/LmQn5IYBdhLWcg3wa2uV#16839326 - Eran
2个回答

4

我将分享我在应用程序中实施的方法

@Override
protected void onRegistered(Context context, String registrationId) {
     Log.i(TAG, "Device registered: regId = " + registrationId);
     //displayMessage(context, getString(R.string.gcm_registered));
     //ServerUtilities.register(context, registrationId);
     //1. Store this id to application Prefs on each request of device registration
     //2. Clear this id from app prefs on each request of device un-registration  
     //3. Now add an if check for new registartion id to server, you can write a method on server side to check if this reg-id matching for this device or not (and you need an unique identification of device to be stored on server)
     //4. That method will clear that if id is matching it meanse this is existing reg-id, and if not matching this is updated reg-id.
     //5. If this is updated reg-id, update on server and update into application prefs.
}

你也可以这样做。
if reg_id exists_into prefrences then
    if stored_id equals_to new_reg_id then
        do nothing
    else
        say server to reg_id updated
        update prefrences with new id
    end if
else
    update this id to application prefs
    say server that your device is registered
end if

但是问题出现在当用户清除应用程序数据时,您将丢失当前的注册ID。

新API示例更新 感谢Eran及其回答Handling registration ID changes in Google Cloud Messaging on Android

谷歌已经改变了他们的演示应用程序以使用新接口。他们通过在应用程序本地设置过期日期来刷新注册ID的值。当应用程序启动时,它们会加载本地存储的注册ID。如果它已“过期”(在演示中意味着它是在7天前从GCM接收到的),则再次调用gcm.register(senderID)

这并不能处理假设情况,即为长时间未启动的应用程序刷新了注册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;
}

谢谢你的回答,Pankaj。你是在GCMBaseIntentService服务内完成的吗?当我使用GCMRegistrar时,我也像你一样使用了这个意图服务。 - Shobhit Puri
嘿,你是在问GCM吗?我认为它还没有被弃用。而且我不确定你在谈论哪个API。可以分享文档链接吗? - Pankaj Kumar
哦,是的,你说得对。因此,你应该实现一个接收器来处理你的消息。如果你阅读gcm-client-lib的代码并形成自己的想法,那将会很棒。我现在没有足够的时间进行研究和开发,所以我不能做。但是当我有时间时,我也会更新这个答案。好吗? - Pankaj Kumar
哦,我明白了。好的,我会继续那个想法,并且如果我能解决的话会发布出来。 - Shobhit Puri
是的,你说得对,为此你可以实现我的第一个或第二个算法,它们都应该能够正常工作...我对此非常有信心。我只是对新 API 的使用感到困惑,而你现在已经理解了。所以尝试实现算法的逻辑吧,你会做好的。祝你好运。 - Pankaj Kumar
显示剩余7条评论

1
只是补充一下Pankaj的答案:

这个例子(Google的入门文档)没有处理一个假设情况,即当Google为长时间未启动的应用程序刷新注册ID时。在这种情况下,应用程序将不会意识到变化,第三方服务器也不会。确实如入门文档中所述的那样。因此,开发人员需要自己处理。
答案还说,他们通过在本地存储的值上设置过期日期来刷新注册ID。当应用程序启动时,它们会加载其本地存储的注册ID。如果它已经“过期”,则再次调用gcm.register(senderID)。问题在于示例中的注册ID的七天本地到期是为了避免设备向第三方服务器发送注册,但服务器却丢失它。它不能处理从Google服务器刷新ID的情况。
架构概述页面标题为“启用GCM”的第二个点中,它说:“请注意,Google可能会定期刷新注册ID,因此您应该设计您的Android应用程序,理解com.google.android.c2dm.intent.REGISTRATION意图可能会被多次调用。您的Android应用程序需要能够相应地响应。”因此,为了处理这个问题,你应该有一个广播监听器,可以处理com.google.android.c2dm.intent.REGISTRATION意图,Google会在需要刷新注册ID时将其发送到应用程序。
问题的另一部分提到“问题是,在广播侦听器内部,我不能再次调用Push ID的注册。这是因为文档说:GCM方法是阻塞的。您不应该在主线程或广播接收器中运行它们。”我认为这个问题与陈述完全不同。当你注册一个广播接收器时,它将包含来自Google的新注册ID的Intent。我不需要在Broadcast监听器中再次调用gcm.register()方法。
希望这能帮助某些人理解如何处理注册ID的更新。

这是一个谦虚的请求,如果您要对答案进行负面评价,请在评论中进一步解释。这将有助于我改进答案,并让我了解您对答案内容的看法。尽管之前的答案有所帮助,但并没有真正回答/解决困惑,所以我再次回答了它。如果您认为答案中有任何批评意见,请务必说出来。这将更清晰地解释更多概念。再次感谢! - Shobhit Puri
1
我不确定为什么这个被踩了。它非常清晰和有帮助。我给你点赞。 - KyleT
无论你写了什么,都没有回答问题,而且你在旧API和新API之间感到困惑。要么使用旧的,要么使用新的。 - Gaurav Singla

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接