Firebase(FCM)如何获取令牌


92

这是我第一次使用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中获得令牌。但最后,我找到了一种方便的方法只需使用调试模式安装示例应用程序,您就可以在首次安装时获取令牌。

但是我不知道为什么安装它时它无法打印日志。可能与移动系统有关。

然后为什么我不能收到通知。FirebaseMessagingService.onMessageReceived没有调用sendNotification


如果日志被点击,它将在示例应用程序中显示带有令牌的令牌
Shubhank

不,示例应用程序说。如果我按下按钮,它将仅在logcat中显示令牌。但是我在logcat。@ shubhank中找不到任何东西
wyx

取消注释此行 String refreshedToken = FirebaseInstanceId.getInstance().getToken(); Log.d(TAG, "Refreshed token: " + refreshedToken);
Gaurav

Answers:


120

最快的原型

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

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>

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

最快但已弃用

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

当您使用比版本17.xx更旧的Firebase库时,它仍然可以正常工作


6
但是第二种方法仅在清除共享首选项之前有效。如果清除了应用程序数据并且该字符串值丢失了怎么办?由于没有令牌,Android不会调用“ onNewtoken()” 。但是,我们如何请求令牌?它到处都说“只使用onNewToken()”,但是该方法仅在有令牌时才运行。假设该方法已经运行,但是我们不必费心存储令牌。稍后,我们执行检查,并发现未设置令牌,然后该怎么办?如何触发FCM再次告诉我令牌?
JeneralJames


1
您可以使用FirebaseInstanceId.getInstance().getInstanceId()而不是FirebaseInstanceId.getInstance().getToken(),查看此答案
Vadim Kotov

24

重要信息。

如果Google Play服务已挂起或未运行,则fcm返回令牌= null

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

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

是的,但是这种情况经常发生
Hoang Duc Tuan Tun

令牌被提取一次后(最有可能在内存中)被缓存。因此,这意味着您需要一次获取它或让Firebase以某种方式为您重新发行另一个令牌。有关如何手动获取的信息,请参见此处stackoverflow.com/a/51630819/2102748
milosmns

20

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

在我的FirebaseMessagingService实例中:

public class FirebaseCloudMessagingService extends FirebaseMessagingService {

    ...

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

    ...

}

请记住,令牌是按设备分配的,并且无论您的登录逻辑如何,Firebase都可以更新令牌。因此,如果您具有登录和注销功能,则必须考虑其他情况:

  1. 当新用户登录时,您需要将令牌绑定到新用户(将其发送到服务器)。因为令牌可能会在旧用户会话期间更新,并且服务器不知道新用户的令牌。
  2. 用户注销后,您需要取消绑定令牌。因为用户不应该再收到通知/消息。

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

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

祝好运!


尝试获取OnSuccess之外的值时会给出null。
DragonFire '19

登录/注销功能与Push消息无关,这是一个特定的业务用例。例如,您可能希望通过一些营销/促销通知来定位已注销的用户,以使他们重新登录到应用程序,在这种情况下,您将需要FCM令牌。但是就获得令牌而言,答案是正确的。
milosmns

@milosmns,关于市场营销/促销通知,您是正确的。仍然需要指示令牌状态。简单的解决方案是将绑定令牌存储在某种历史表中,然后使用这些过去的标记,以鼓励使用以重新登录。
rzaaeeff

嗯,我不确定您实际上可以重用同一令牌多长时间,以及何时确切使它失效。这值得研究,因为我猜想一旦令牌变为无效,就需要清除此历史记录/缓存/持久性表。
milosmns

@milosmns,在Firebaseland中,令牌不会过期,而会被更新。当您使用FCM API触发任何与令牌相关的活动时,将验证提供的令牌。如果令牌无效,您将收到错误:MissingRegistration或错误:InvalidRegistration。:你可以在这里找到更多的错误代码firebase.google.com/docs/cloud-messaging/...
rzaaeeff

13

根据文档

将GCM客户端应用迁移到FCM

onTokenRefresh()

仅在更新InstanceID令牌时调用

因此,只有在将应用程序安装到设备上时,它才会在第一次调用。

因此,建议您手动卸载您的应用,然后尝试再次运行

肯定你会得到令牌


2
不重新安装,请手动将其卸载,然后运行项目,
Gaurav

取消注释此行 String refreshedToken = FirebaseInstanceId.getInstance().getToken(); Log.d(TAG, "Refreshed token: " + refreshedToken);
Gaurav

1
@Gaurav,第二次登录后如何获得令牌?onTokenRefresh不调用每个登录名。如何在登录屏幕中获取令牌?
delavega66

3
@ de_la_vega_66,你必须保存您的令牌在第一次登录
拉夫

您的扩展FirebaseInstanceIdService并具有onTokenRefresh()回调方法的Service必须在清单文件中注册:<service android:name =“ com.mypackage.name.MyInstanceIdService” android:exported =“ true”> <intent-filter> <action android:name =“ com.google.firebase.INSTANCE_ID_EVENT” /> </ intent-filter> </ service>
Kirill Karmazin

9

试试这个。你为什么用RegistrationIntentService

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

    private void registerToken(String token) {

    }
}

8

此行应为您提供Firebase FCM令牌。

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

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


它返回空值
Kishan Solanki

7

代替这个:

    // [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()如果要从服务器发送推送通知,则需要调用方法来更新服务器上的令牌。

更新:

在以下情况下会生成(onTokenRefresh()称为)新的Firebase令牌:

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

我必须删除实例ID FirebaseInstanceId.getInstance()。deleteInstanceId(),但收到服务错误,
Hardik9850 2016年

2
您需要FirebaseInstanceId.getInstance().deleteInstanceId()在另一个线程中运行
rockar06'3

5

同时,不要忘记在清单文件中包含此令牌以接收令牌ID

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

4

firebase-messaging:17.1.0和新的FirebaseInstanceIdService已过时,你可以得到onNewTokenFirebaseMessagingService类作为解释https://stackoverflow.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

4

该方法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()));

3

如果正在使用firebase的某些auth函数,则可以使用以下方法获取令牌:

//------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()



1

对于那些降落在这里的人,请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>

1
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();

            }
        });


-9
Settings.Secure.getString(getContentResolver(),
                     Settings.Secure.ANDROID_ID);

该代码是获取设备的android ID,而不是firebase令牌。
Syed Afeef
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.