Firebase(FCM)如何获取令牌

Posted

技术标签:

【中文标题】Firebase(FCM)如何获取令牌【英文标题】:Firebase (FCM) how to get token 【发布时间】:2016-10-13 17:33:30 【问题描述】:

这是我第一次使用 FCM。

我从firebase/quickstart-android 下载了一个示例并安装了 FCM 快速入门。但我无法从日志中获取任何令牌,即使在应用中点击 LOG TOKEN 按钮

然后我尝试使用 Firebase 控制台发送消息并设置为目标我的应用程序包名称。我收到了消息。

我想知道FCM可以用吗?GCM一切正常。

解决方案:

因为我不是 Android 开发人员,只是一名后端开发人员。所以我需要一些时间来解决它。在我看来,示例应用程序中存在一些错误。

代码:

RegistrationIntentService.java

public class RegistrationIntentService extends IntentService 

    private static final String TAG = "RegIntentService";


    public RegistrationIntentService() 
        super(TAG);
    

    @Override
    protected void onHandleIntent(Intent intent) 
        String token = FirebaseInstanceId.getInstance().getToken();
        Log.i(TAG, "FCM Registration Token: " + token);
    

MyFirebaseInstanceIDService.java

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);
//
        Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);
    
    // [END refresh_token]

    /**
     * Persist token to third-party servers.
     * <p>
     * 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.
    

在 MainActivity.java 中添加这个。

 Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);

完成上述操作后,你就得到了Logcat中的Token。但最后,我找到了一种方便的方式来获取它。只需使用调试模式安装示例应用程序,第一次安装时就可以获取令牌。

但是不知道为什么安装的时候不能打印日志。可能和手机系统有关。

然后为什么我无法收到通知。 FirebaseMessagingService.onMessageReceived 未调用 sendNotification

【问题讨论】:

如果日志被命中,它将在示例应用程序中显示令牌 不,示例应用程序说。如果我点击按钮,它只会在 logcat 中显示令牌。但我在 logcat 中一无所获。@ Shubhank 取消注释这行String refreshedToken = FirebaseInstanceId.getInstance().getToken(); Log.d(TAG, "Refreshed token: " + refreshedToken); 已弃用,因此请从此处更新。 ***.com/q/51123197/7703497 【参考方案1】:

最快且最适合原型制作

快速的解决方案是将其存储在 sharedPrefs 中,并将此逻辑添加到 MainActivity 或扩展 Application 的类中的 onCreate 方法中。

FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(this, instanceIdResult -> 
    String newToken = instanceIdResult.getToken();
    Log.e("newToken", newToken);
    getActivity().getPreferences(Context.MODE_PRIVATE).edit().putString("fb", newToken).apply();
);

Log.d("newToken", getActivity().getPreferences(Context.MODE_PRIVATE).getString("fb", "empty :("));

更清洁的方式

更好的选择是创建一个服务并保持类似的逻辑。首先创建新服务

public class MyFirebaseMessagingService extends FirebaseMessagingService 

    @Override
    public void onNewToken(String s) 
        super.onNewToken(s);
        Log.e("newToken", s);
        getSharedPreferences("_", MODE_PRIVATE).edit().putString("fb", s).apply();
    

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

    public static String getToken(Context context) 
        return context.getSharedPreferences("_", MODE_PRIVATE).getString("fb", "empty");
    

然后将其添加到 AndroidManifest 文件中

<service
        android:name=".MyFirebaseMessagingService"
        android:stopWithTask="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
</service>

最后,您可以使用 Service MyFirebaseMessagingService.getToken(Context); 中的静态方法

最快但已弃用

Log.d("Firebase", "token "+ FirebaseInstanceId.getInstance().getToken());

当您使用比版本 17.x.x 更旧的 firebase 库时,它仍然可以工作

【讨论】:

但第二种方法仅在共享首选项被清除之前有效。如果清除了应用程序数据并且该字符串值丢失了怎么办? Android 不会调用“onNewtoken()”,因为没有 new 令牌。但是那么我们如何请求令牌呢?到处都说“只使用 onNewToken()”,但该方法仅在有 new 令牌时运行。假设该方法已经运行,但我们没有费心存储令牌。稍后我们执行检查,发现令牌没有设置,然后呢?如何触发 FCM 再次告诉我令牌? ***.com/questions/51125169/… 你可以用FirebaseInstanceId.getInstance().getInstanceId()代替FirebaseInstanceId.getInstance().getToken(),见this answer 我使用了第二种解决方案,并添加了 setToken() 方法,我在 BaseActivity -> onCreate() 中运行。【参考方案2】:

完整解决方案:

Firebase Android SDK 背后的团队稍微更改了 API。我已经实现了这样的“令牌到服务器”逻辑:

在我的 FirebaseMessagingService 实例中:

public class FirebaseCloudMessagingService extends FirebaseMessagingService 

    ...

    @Override
    public void onNewToken(String token) 
        // sending token to server here
    

    ...


请记住,令牌是每个设备的,无论您的登录逻辑如何,它都可以由 Firebase 更新。所以,如果你有登录和注销功能,你必须考虑额外的情况:

    新用户登录时,需要将token绑定到新用户(发送到服务器)。因为在旧用户会话期间可能会更新令牌,而服务器不知道新用户的令牌。 用户注销时,需要解除token绑定。因为用户不应该再收到通知/消息了。

使用新的 API,您可以像这样获取令牌:

FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() 
        @Override
        public void onSuccess(InstanceIdResult instanceIdResult) 
            String token = instanceIdResult.getToken();
            // send it to server
        
    );

祝你好运!

【讨论】:

试图在 OnSuccess 之外获取值是 null。 登录/注销功能与推送消息没有任何关系,这是一个特定的业务用例。例如,您可能希望通过一些营销/促销通知来定位已注销的用户,以让他们重新登录应用程序,在这种情况下,您将需要 FCM 令牌。但就获取令牌而言,答案是正确的。 @milosmns,您在营销/促销通知方面是对的。仍然需要指示令牌状态。简单的解决方案是将未绑定的令牌存储在某种历史记录表中,然后使用那些过去的令牌来鼓励用户重新登录。 嗯,我不确定您实际上可以重复使用同一个令牌多长时间以及它何时失效。这值得调查,因为我猜你需要在令牌失效后清除这个历史/缓存/持久性表。 @milosmns,在 Firebaseland 中,令牌不会过期,而是会被更新。当您使用 FCM API 触发任何与令牌相关的活动时,将验证提供的令牌。如果令牌无效,您将收到 error:MissingRegistration 或 error:InvalidRegistration。您可以在此处找到更多错误代码:firebase.google.com/docs/cloud-messaging/…【参考方案3】:

FirebaseInstanceId 类及其方法getInstanceId 也已弃用。所以你必须使用FirebaseMessaging 类,它是getToken 方法。

FirebaseMessaging.getInstance().getToken().addOnSuccessListener(token -> 
        if (!TextUtils.isEmpty(token)) 
            Log.d(TAG, "retrieve token successful : " + token);
         else
            Log.w(TAG, "token should not be null...");
        
    ).addOnFailureListener(e -> 
        //handle e
    ).addOnCanceledListener(() -> 
        //handle cancel
    ).addOnCompleteListener(task -> Log.v(TAG, "This is the token : " + task.getResult()));

getToken() 方法已弃用。你可以改用getInstanceId()

如果您想在请求instanceId(token) 时处理结果,请检查此代码。

FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(instanceIdResult -> 
        if (instanceIdResult != null) 
            String token = instanceIdResult.getToken();
            if (!TextUtils.isEmpty(token)) 
                Log.d(TAG, "retrieve token successful : " + token);
            
         else
            Log.w(TAG, "instanceIdResult should not be null..");
        
    ).addOnFailureListener(e -> 
        //do something with e
    ).addOnCanceledListener(() -> 
        //request has canceled
    ).addOnCompleteListener(task -> Log.v(TAG, "task result : " + task.getResult().getToken()));

【讨论】:

这个答案需要更多的支持,它奏效了。谢谢【参考方案4】:

重要信息。

如果 google play 服务挂起或未运行, 然后 fcm 返回令牌 = null

如果播放服务正常工作,则FirebaseInstanceId.getInstance().getToken() 方法返回token

Log.d("FCMToken", "token "+ FirebaseInstanceId.getInstance().getToken());

【讨论】:

是的,但这种情况经常发生 令牌在被获取一次后被缓存(最有可能在内存中)。因此,这意味着您需要获取一次或让 Firebase 以某种方式为您重新发出另一个令牌。请参阅此处了解如何手动获取***.com/a/51630819/2102748 FirebaseInstanceId 已弃用 @Darcia14 请更新答案,当我是 android 开发者时,我得到了答案,请用最新的更新更新答案。谢谢 很老的答案。请更新。【参考方案5】:

根据文档

Migrate a GCM client app to FCM

onTokenRefresh()

仅在更新 InstanceID 令牌时调用

所以它只会在您将应用程序安装到您的设备时第一次调用。

所以我建议请手动卸载您的应用并尝试再次运行

你一定会得到TOKEN

【讨论】:

不重新安装,卸载手动运行项目, 取消注释这行String refreshedToken = FirebaseInstanceId.getInstance().getToken(); Log.d(TAG, "Refreshed token: " + refreshedToken); @Gaurav,第二次登录后如何获取令牌? onTokenRefresh 不调用每个登录。如何在登录屏幕中获取令牌? @de_la_vega_66 ,您必须在首次登录时存储您的令牌 扩展 FirebaseInstanceIdService 并具有 onTokenRefresh() 回调方法的服务必须在 Manifest 文件中注册:【参考方案6】:

此行应该为您提供 firebase FCM 令牌。

String token = FirebaseInstanceId.getInstance().getToken();
Log.d("MYTAG", "This is your Firebase token" + token);

执行 Log.d 将其打印到 android 监视器。

【讨论】:

它返回 null【参考方案7】:

试试这个。你为什么用RegistrationIntentService

public class FirebaseInstanceIDService extends FirebaseInstanceIdService     
    @Override
    public void onTokenRefresh()     
        String token = FirebaseInstanceId.getInstance().getToken();    
        registerToken(token);
    

    private void registerToken(String token) 

    

【讨论】:

【参考方案8】:

而不是这个:

    // [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);
//
        Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);
    
    // [END refresh_token]

这样做:

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

        // Implement this method to send token to your app's server
       sendRegistrationToServer(refreshedToken);

    
    // [END refresh_token]

还有一件事:

你需要调用sendRegistrationToServer()方法 如果您要发送推送,它将更新服务器上的令牌 来自服务器的通知。

更新:

在以下情况下生成新的 Firebase 令牌(调用onTokenRefresh()):

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

【讨论】:

我不得不删除实例 ID FirebaseInstanceId.getInstance().deleteInstanceId() 但得到一个服务错误, 你需要在另一个线程中运行FirebaseInstanceId.getInstance().deleteInstanceId()【参考方案9】:

同时不要忘记在你的清单文件中包含这个来接收令牌 id

<service
    android:name=".MyFirebaseInstanceIDService">
    <intent-filter>
        <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
    </intent-filter>
</service>

【讨论】:

【参考方案10】:

FirebaseInstanceId.getInstance().getInstanceId() 是deprecated。基于firebase document,您可以使用以下代码检索当前的注册令牌:

FirebaseMessaging.getInstance().getToken()
    .addOnCompleteListener(new OnCompleteListener<String>() 
        @Override
        public void onComplete(@NonNull Task<String> task) 
          if (!task.isSuccessful()) 
            Log.w(TAG, "Fetching FCM registration token failed", task.getException());
            return;
          

          // Get new FCM registration token
          String token = task.getResult();

          // Log and toast
          String msg = getString(R.string.msg_token_fmt, token);
          Log.d(TAG, msg);
          Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
        
    );

【讨论】:

【参考方案11】:

2020 年 11 月 12 日更新

当你使用'com.google.firebase:firebase-messaging:21.0.0'FirebaseInstanceIdis depreacted now

现在我们需要使用FirebaseInstallations.getInstance().getToken()FirebaseMessaging.getInstance().token

示例代码

FirebaseInstallations.getInstance().getToken(true).addOnCompleteListener 
            firebaseToken = it.result!!.token
        

// OR

FirebaseMessaging.getInstance().token.addOnCompleteListener 
            if(it.isComplete)
                firebaseToken = it.result.toString()
                Util.printLog(firebaseToken)
            
        

【讨论】:

我使用 FirebaseMessaging.getInstance().token 只是为了手动刷新 Token 以及 implementation platform('com.google.firebase:firebase-bom:26.2.0') 这是强制刷新令牌getToken(true),我不知道你为什么要刷新强制为真。【参考方案12】:

您可以使用此方法通过 firebase 获取设备令牌

 FirebaseMessaging.getInstance().getToken().addOnCompleteListener(new OnCompleteListener<String>() 
        @Override
        public void onComplete(@NonNull Task<String> task) 
            String deviceToken = task.getResult();
        
    );

【讨论】:

两种方式的结果都不同。你能解释一下吗? 第一个给出了一个由firebase操作和原始密钥令牌生成的冗长令牌,它在应用程序ID基础上生成令牌,您可以说是自定义令牌,但第二个是真正的设备令牌.最后一个长度短,区别在于定制和不定制, 第一个不是这个问题的答案,而且很容易产生误导。第二个是答案 是的@StefanoMtangoo,你说的是真的,这就是为什么我在上面写的第二个没问题,但火力基地提供了这两种方法,但我推荐第二种,我要删除第一种跨度> 删除它,因为它会造成不必要的痛苦并且不回答所提出的问题。剩下一个正确的答案应该足够恕我直言【参考方案13】:

firebase-messaging:17.1.0 和更新版本中,不推荐使用 FirebaseInstanceIdService,您可以在 FirebaseMessagingService 类上获取 onNewToken,如 https://***.com/a/51475096/1351469 中所述

但是,如果您想随时获取令牌,那么现在您可以这样做:

FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener( this.getActivity(),  new OnSuccessListener<InstanceIdResult>() 
  @Override
  public void onSuccess(InstanceIdResult instanceIdResult) 
    String newToken = instanceIdResult.getToken();
    Log.e("newToken",newToken);
  
);

【讨论】:

这个能不能返回,所以很多地方都可以使用同一个函数或者因为firebase的异步特性我们不得不复制粘贴【参考方案14】:

如果正在使用firebase的一些认证功能,你可以使用这个来获取令牌:

//------GET USER TOKEN-------
FirebaseUser mUser = FirebaseAuth.getInstance().getCurrentUser();
mUser.getToken(true)
        .addOnCompleteListener(new OnCompleteListener<GetTokenResult>() 
            public void onComplete(@NonNull Task<GetTokenResult> task) 
                if (task.isSuccessful()) 
                    String idToken = task.getResult().getToken();
                      // ...
                
            
        );

如果用户已登录,则运行良好。 getCurrentUser()

【讨论】:

【参考方案15】:

如果你使用的是 kotlin 和 co-routine 那么添加 kotlin coroutine play 图书馆

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:x.x.x'

使用这个简单的方法:

FirebaseMessaging.getInstance().token.await()

【讨论】:

【参考方案16】:

如果您使用上面的 'com.google.firebase:firebase-messaging:22.0.0'

用Kotlin方式获取FCM Token(Force):

FirebaseMessaging.getInstance().token.addOnCompleteListener  task: Task<String> ->
   if (!task.isSuccessful) 
     return@addOnCompleteListener
   

   pushToken = task.result
   Log.i("PUSH_TOKEN", "pushToken: $pushToken")

您可以通过 onNewToken 方法获取令牌。 (这个类必须实现)

class PushNotificationService: FirebaseMessagingService() 

    override fun onNewToken(token: String) 
        Log.e("PUSH_TOKEN", "Refreshed firebase token: $token")
    

您需要将 PushNotificationService 添加到 AndroidManifest.xml

<service
  android:name=".PushNotificationService"
  android:exported="false"
  tools:ignore="Instantiatable">
  <intent-filter>
    <action android:name="com.google.firebase.MESSAGING_EVENT" />
  </intent-filter>
</service>

【讨论】:

【参考方案17】:

试试这个

FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener(OnSuccessListener<InstanceIdResult>  instanceIdResult ->
             fcm_token = instanceIdResult.token

【讨论】:

【参考方案18】:

这是在 Activity (2021) 中获取 fcm 令牌的最新代码。

FirebaseMessaging.getInstance().getToken()
                .addOnCompleteListener(new OnCompleteListener<String>() 
                    @Override
                    public void onComplete(@NonNull Task<String> task) 
                        if (!task.isSuccessful()) 
                            Log.w(TAG, "Fetching FCM registration token failed", task.getException());
                            return;
                        
                        // Get new FCM registration token
                        String token = task.getResult();

                        Log.d(TAG, "fcm token : "+token);
                        
                    
                );

对于新的 Token,只需在 FirebaseMessagingService 扩展类中添加 newToken 方法即可。

@Override
    public void onNewToken(String token) 
        super.onNewToken(token);
        Log.d(TAG, token);
    

【讨论】:

【参考方案19】:

对于那些登陆这里的人,到目前为止FirebaseInstanceIdService 已被弃用,请改用:

public class MyFirebaseMessagingService extends FirebaseMessagingService 
    @Override
    public void onNewToken(String token) 
        Log.d("MY_TOKEN", "Refreshed token: " + token);

        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // Instance ID token to your app server.
        // sendRegistrationToServer(token);
    

并在 AndroidManifest 中声明

<application... >

<service android:name=".fcm.MyFirebaseMessagingService">
    <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>
</application>

【讨论】:

【参考方案20】:
FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() 
            @Override
            public void onComplete(@NonNull Task<InstanceIdResult> task) 
                if (!task.isSuccessful()) 
                    Log.w(TAG, "getInstanceId failed", task.getException());
                    return;
                

                // Get new Instance ID token
                String **token** = task.getResult().getToken();

            
        );

【讨论】:

【参考方案21】:

在挂起函数中获取 firebase 令牌的示例

override suspend fun sendTokenToServer() 
    try 
 
        val token = FirebaseMessaging.getInstance().token.await()
        Log.i("TAG", "token " + token)
     catch (exception:Exception) 

    

【讨论】:

【参考方案22】:

我会尽量简短。这是检索 Firebase 令牌的唯一不被弃用的方法:

FirebaseInstallations.getInstance().getToken(true).addOnCompleteListener(task ->  
   // get token 
   String token = task.getResult().getToken();      
)

【讨论】:

【参考方案23】:

使用以下代码获取最新的 firebase 版本 - 'com.google.firebase:firebase-messaging:22.0.0'

FirebaseMessaging.getInstance().getToken()
                        .addOnCompleteListener(task -> 

                            if (!task.isSuccessful()) 
                                //handle token error
                                return;
                            

                            strAppToken = task.getResult();

                        );

【讨论】:

【参考方案24】:

您可以在 Firebase (FCM) 中使用以下内容来获取令牌:

FirebaseInstanceId.getInstance().getToken();

【讨论】:

getToken() 方法已弃用!现在,最佳答案来自@rzaaeeff。【参考方案25】:

FirebaseInstanceId.getInstance().getInstanceId() 已弃用。 现在获取用户 FCM 令牌

 FirebaseMessaging.getInstance().getToken()
            .addOnCompleteListener(new OnCompleteListener<String>() 
                @Override
                public void onComplete(@NonNull Task<String> task) 
                    if (!task.isSuccessful()) 
                        System.out.println("--------------------------");
                        System.out.println(" " + task.getException());
                        System.out.println("--------------------------");
                        return;
                    

                    // Get new FCM registration token
                    String token = task.getResult();

                    // Log 
                    String msg = "GET TOKEN " + token;
                    System.out.println("--------------------------");
                    System.out.println(" " + msg);
                    System.out.println("--------------------------");

                
            );

【讨论】:

【参考方案26】:

颤振解决方案:

var token = await FirebaseMessaging.instance.getToken();

【讨论】:

【参考方案27】:
Settings.Secure.getString(getContentResolver(),
                     Settings.Secure.ANDROID_ID);

【讨论】:

该代码是获取设备的android ID,而不是firebase令牌。

以上是关于Firebase(FCM)如何获取令牌的主要内容,如果未能解决你的问题,请参考以下文章

为啥不获取 Android Firebase FCM 注册令牌?

在 React-Native 中获取 FCM 令牌

在Android中获取FCM消息令牌的正确方法是啥?

无法获取 FCM 注册令牌

Firebase 推送通知 - 如何跟踪用户 FCM 令牌?

Flutter:如何在 Flutter 中为 Firebase (FCM) 注册令牌订阅ToTopic