当前位置: 首页 > 知识库问答 >
问题:

调用Firebase FCM force onTokenRefresh()

齐泰
2023-03-14

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

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

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

共有3个答案

公冶高峯
2023-03-14

伙计们,它有非常简单的解决方案

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

注意:如果您的应用使用了由deleteInstanceID删除的令牌,您的应用将需要生成替换令牌。

不删除实例Id,只删除令牌:

String authorizedEntity = PROJECT_ID;
String scope = "GCM";
InstanceID.getInstance(context).deleteToken(authorizedEntity,scope);
朱炳
2023-03-14

尝试实现FirebaseInstancedService以获取刷新令牌。

访问注册令牌:

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

     @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);
}

完整代码:

   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.
    }
}

请看我的答案。

编辑:

你不应该自己启动FirebaseInstancedService。

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

这将不会被非常频繁地调用,因为密钥旋转和处理实例ID更改需要它,因为:

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

系统将在所有设备上限制刷新事件,以避免令牌更新导致应用服务器过载。

尝试以下方法:

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

怀经赋
2023-03-14

每当生成新令牌时,都会调用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);
    }
}

编辑

FirebaseInstancedService

公共类FirebaseInstancedService扩展了服务

此类已弃用。支持覆盖FirebaseMessagingService中的onNewToken。一旦实现,就可以安全地删除此服务。

onTokenReFresh()已弃用。在MyFirebase MessagingService中使用onNewToken()

public class MyFirebaseMessagingService extends FirebaseMessagingService {

@Override
public void onNewToken(String s) {
    super.onNewToken(s);
    Log.e("NEW_TOKEN",s);
    }

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    super.onMessageReceived(remoteMessage);
    }
} 

 类似资料:
  • 问题内容: 我正在开发一个需要与Video4Linux抽象交互的应用程序。该应用程序使用mono框架以C#开发。 我面临的问题是我无法P /调用系统调用。或者,更准确地说,我可以P /调用它,但是它崩溃严重。 extern声明如下: 到目前为止,一切都很好。 使用的实际例程如下: 以上所有代码似乎都不错。该类用于按照标头规范计算I / O请求代码(基本上,它遵循处声明的宏)。 该参数是一个结构,声

  • 我们正在尝试开发一个自调用的lambda来成批处理S3文件。lambda角色具有附加调用所需的策略。 以下是自调用lambda的代码: 其中是对同一个lambda的调用调用。其余的事情都按预期工作,只要调用堆栈出现在这个调用请求上,它就会超时: 这是记录到CloudWatch的堆栈跟踪:

  • 主要内容:1.概述,2. 消费者调用服务,3. 提供者提供服务1.概述 在 dubbo:// 协议的调用,一共分成三种: sync 同步调用 async 异步调用 oneway 单向调用 前两种比较好理解,都是基于 Request Response 模型,差异点在异步调用,服务消费者不阻塞等待结果,而是通过回调的方式,处理服务提供者返回的结果。 最后一种,基于 Message 模型,发起调用,而不关注等待和关注执行结果。 因此,从性能上:oneway > a

  • 通过io的requestAbs方法调用/调用/使用REST API的vertx实现。vertx。果心http。vertx-core-3.2.0中的HttpClient类。jar导致HTTP错误::302,响应数据为HTML Erro响应。 不确定requestAbs方法的行为,因为没有引发异常,也没有写入任何日志。此外,还随附了使用vertx JAR的此方法的源代码。如果方法实现有bug,是否有问

  • 如果我在我的应用程序中导航并使用HomeButton返回Android LaunchScreen,则会调用OnSpt()挂钩,这很好。如果我使用Android TaskManager导航回应用程序,则会调用OnResume()。如果我使用Hardware BackButton在我的应用程序中导航,那么也会调用OnSpt(),这很好,但如果我导航回我的应用程序,则会调用Mainactive中的OnC

  • 问题内容: 您何时在Java中调用super()?我在派生类的某些构造函数中看到了它,但是不是每个父类的构造函数都会自动调用吗?为什么需要使用超级? 问题答案: 如果您提供这样的课程: 或这个: 编译器将为此生成代码: 因此,严格来说,对“ super()”的调用始终存在。 在实践中,您仅应在要传递给父构造函数的参数处调用“ super(…)”。 调用“ super()”(没有参数)并没有错,但是

  • 一般来说,使用Unity引擎开发的项目中,其内存分配主要由三部分组成:程序代码、托管堆(Managed Heap)以及本机堆(Native Heap)。其中,对于目前绝大多数基于Unity引擎开发的项目而言,其托管堆是由Mono分配和管理的。“托管” 的本意是Mono可以自动地改变堆的大小来适应你所需要的内存,并且适时地调用垃圾回收(Garbage Collection)操作来释放已经不需要的内存

  • 与以往版本不同的是,SDK 不再内置具体 API 的逻辑,所有的 API 均交由开发者自行调用,以获取用户列表为例: $api = $app->getClient(); 两种调用方式 当前版本准备了两种调用方式:原始方式调用 和 链式调用,请根据你的喜好自行选择使用方式,效果一致。 方式一:原始方式调用 $response = $api->post('/cgi-bin/user/info/upd