Firebase FCM强制onTokenRefresh()被调用

Tar*_*ury 107 android firebase-cloud-messaging

我正在将我的应用程序从GCM迁移到FCM.

当新用户安装我的应用程序时,onTokenRefresh()会自动调用该应用程序.问题是用户尚未登录(无用户ID).

如何onTokenRefresh()在用户登录后触发?

Pri*_*nce 168

onTokenRefresh()每当生成新令牌时,都会调用该方法.安装应用程序后,它将立即生成(正如您所发现的那样).当令牌发生变化时也会调用它.

根据FirebaseCloudMessaging指南:

您可以将通知定位到单个特定设备.在应用程序首次启动时,FCM SDK会为客户端应用程序实例生成注册令牌.

截图

来源链接:https: //firebase.google.com/docs/notifications/android/console-device#access_the_registration_token

这意味着令牌注册是每个应用程序.听起来您希望在用户登录后使用令牌.我建议您将onTokenRefresh()方法中的令牌保存到内部存储或共享首选项.然后,在用户登录后从存储中检索令牌,并根据需要向您的服务器注册令牌.

如果要手动强制onTokenRefresh(),可以创建IntentService并删除令牌实例.然后,当您调用getToken时,onTokenRefresh()将再次调用该方法.

示例代码:

public class DeleteTokenService extends IntentService
{
    public static final String TAG = DeleteTokenService.class.getSimpleName();

    public DeleteTokenService()
    {
        super(TAG);
    }

    @Override
    protected void onHandleIntent(Intent intent)
    {
        try
        {
            // Check for current token
            String originalToken = getTokenFromPrefs();
            Log.d(TAG, "Token before deletion: " + originalToken);

            // Resets Instance ID and revokes all tokens.
            FirebaseInstanceId.getInstance().deleteInstanceId();

            // Clear current saved token
            saveTokenToPrefs("");

            // Check for success of empty token
            String tokenCheck = getTokenFromPrefs();
            Log.d(TAG, "Token deleted. Proof: " + tokenCheck);

            // Now manually call onTokenRefresh()
            Log.d(TAG, "Getting new token");
            FirebaseInstanceId.getInstance().getToken();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    private void saveTokenToPrefs(String _token)
    {
        // Access Shared Preferences
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        SharedPreferences.Editor editor = preferences.edit();

        // Save to SharedPreferences
        editor.putString("registration_id", _token);
        editor.apply();
    }

    private String getTokenFromPrefs()
    {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        return preferences.getString("registration_id", null);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 即使onTokenRefresh()被记录在用户面前,而不是做在本地存储,工作被调用时,你可以检索使用FirebaseInstanceId.getInstance().为gettoken()的令牌,并将其发送到服务器的用户登录注册 (除非您想在本地存储它以从服务器中删除旧令牌) (26认同)
  • FireBase很聪明,它会调用onTokenRefresh()方法,只有当没有令牌(它被删除或第一次被调用)或其他事情发生并且令牌已被更改时.如果有人想调用onTokenRefresh可以删除令牌,然后调用FirebaseInstanceId.getInstance().getToken().操作FirebaseInstanceId.getInstance().deleteInstanceId()需要在AsyncTask或新的Thread中,它不能在MainThread上! (10认同)
  • 为什么要将令牌保存到共享首选项 - 如果您可以调用[FirebaseInstanceId.getInstance().getToken()](https://firebase.google.com/docs/reference/android/com/google/firebase/iid/FirebaseInstanceId)在任何时候获得它的价值? (5认同)
  • 为什么不直接调用FirebaseInstanceId.getToken? (3认同)

pRa*_*NaY 17

尝试实现FirebaseInstanceIdService获取刷新令牌.

访问注册令牌:

您可以通过扩展FirebaseInstanceIdService来访问令牌的值.确保已将服务添加到清单中,然后getToken在上下文中调用onTokenRefresh,并记录如下所示的值:

     @Override
public void onTokenRefresh() {
    // Get updated InstanceID token.
    String refreshedToken = FirebaseInstanceId.getInstance().getToken();
    Log.d(TAG, "Refreshed token: " + refreshedToken);

    // TODO: Implement this method to send any registration to your app's servers.
    sendRegistrationToServer(refreshedToken);
}
Run Code Online (Sandbox Code Playgroud)

完整代码:

   import android.util.Log;

import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;


public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {

    private static final String TAG = "MyFirebaseIIDService";

    /**
     * Called if InstanceID token is updated. This may occur if the security of
     * the previous token had been compromised. Note that this is called when the InstanceID token
     * is initially generated so this is where you would retrieve the token.
     */
    // [START refresh_token]
    @Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
        Log.d(TAG, "Refreshed token: " + refreshedToken);

        // TODO: Implement this method to send any registration to your app's servers.
        sendRegistrationToServer(refreshedToken);
    }
    // [END refresh_token]

    /**
     * Persist token to third-party servers.
     *
     * Modify this method to associate the user's FCM InstanceID token with any server-side account
     * maintained by your application.
     *
     * @param token The new token.
     */
    private void sendRegistrationToServer(String token) {
        // Add custom implementation, as needed.
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里看到我的答案.

EDITS:

您不应该自己启动FirebaseInstanceIdService.

当系统确定需要刷新令牌时,将调用它.应用程序应调用getToken()并将令牌发送到所有应用程序服务器.

这不会被频繁调用,需要进行密钥轮换并处理实例ID更改,原因如下:

  • 应用程序删除实例ID
  • 应用程序在新设备用户上恢复
  • 卸载/重新安装应用程序
  • 用户清除应用数据

系统将限制所有设备上的刷新事件,以避免使用令牌更新使应用程序服务器过载.

尝试以下方式:

你可以在主线程的任何地方调用FirebaseInstanceID.getToken()(无论是服务,AsyncTask等),在本地存储返回的令牌并将其发送到您的服务器.然后无论何时 onTokenRefresh()调用,你都会再次调用 FirebaseInstanceID.getToken(),获取一个新令牌,并将其发送到服务器(可能还包括旧令牌,以便您的服务器可以删除它,将其替换为新的令牌) .

  • 我确实实现了FirebaseInstanceIdService,问题是用户安装应用后几乎立即调用了onTokenRefresh()。我需要在执行登录/注册后调用它 (2认同)

归档时间:

查看次数:

116188 次

最近记录:

5 年,11 月 前