Android: токен Firebase вначале имеет значение null

Я использую FCM для предоставления уведомлений в своем приложении. Все работало хорошо, но теперь я понял, что, когда я устанавливаю свое приложение с помощью Android Studio (а не из GooglePlay), токен сначала пуст. Когда я закрываю приложение и перезапускаю его, токен больше не равен нулю. Что вызывает эту проблему и как ее избежать?

InstanceIDService:

public class InstanceIDService extends FirebaseInstanceIdService {

    @Override
    public void onTokenRefresh() {

        String token = FirebaseInstanceId.getInstance().getToken();
        registerToken(token);
    }

    private void registerToken(String token) {

        OkHttpClient client = new OkHttpClient();
        RequestBody body = new FormBody.Builder()
                .add("Token",token)
                .build();

        Request request = new Request.Builder()
                .url("url_to_registration_script")
                .post(body)
                .build();

        try {
            client.newCall(request).execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

В MainActivity:

FirebaseMessaging.getInstance().subscribeToTopic("topic");
String token = FirebaseInstanceId.getInstance().getToken();
Log.d("TOKEN", token);

Последний журнал возвращает null, когда приложение установлено и запускается в первый раз

Регистрация script:

 <?php 
 if (isset($_POST["Token"])) {

       $_uv_Token=$_POST["Token"];
       $conn = mysqli_connect("localhost","user","pass","db") or die("Error connecting");
       $q="INSERT INTO users (Token) VALUES ( '$_uv_Token') "
          ." ON DUPLICATE KEY UPDATE Token = '$_uv_Token';";

  mysqli_query($conn,$q) or die(mysqli_error($conn));
  mysqli_close($conn);
}
?>

Ответы

Ответ 1

токен извлекается асинхронно при первом запуске приложения. Вы должны подождать, пока onTokenRefresh() будет вызван в вашем FirebaseInstanceIdService до того, как будет доступен доступ к токену.

Ответ 2

удалите приложение из эмулятора и запустите его снова, чтобы снова вызвать метод onTokenRefreshed.

Чтобы проверить, что вы уже зарегистрированы, и вы просто хотите узнать токен FCM

String refreshedToken = FirebaseInstanceId.getInstance().getToken();

добавьте вышеприведенную строку в класс MyFirebaseMessagingService где угодно (в методе oncreate) и просто нажмите Toast или запустите файл refreshedToken.

Ответ 3

Просто замените:

String token = instanceID.getToken();

с:

String token = instanceID.getToken($SENDER_ID, "FCM");

и он будет работать.

Ответ 4

У меня была та же проблема. Я просмотрел много сообщений SO и других форумов, и я нашел решение, которое сработало для меня. В документации FCM используется этот метод для получения токена.

String refreshedToken = FirebaseInstanceId.getInstance().getToken();

Я нашел сообщение в Интернете (я прошу прощения, я не помню, какой из них я нашел некоторое время назад), который использовал этот метод вместо этого:

String refreshedToken = FirebaseInstanceId.getInstance().getToken() (String authorizedEntity, String scope);

Документация FCM описывает первый метод как:

Вернуть главный токен для проекта Firebase по умолчанию.

В то время как второй описывается как

Возвращает токен, который разрешает Entity выполнять действие от имени приложения, идентифицированного с помощью идентификатора экземпляра. Это похоже на токен OAuth2, за исключением того, что он применяется к экземпляру приложения вместо пользователя. Например, чтобы получить токен, который можно использовать для отправки сообщений в приложение через FirebaseMessaging, установите идентификатор отправителя и установите "FCM".

Я искал, почему первый вызов метода занимает больше времени, чтобы вернуть токен, но я еще не нашел ответа. Надеюсь, это поможет.

Ответ 5

Даже у меня была такая же проблема. Я дал инструкции Log для печати токена в onCreate моей активности запуска. Требуется время, чтобы обновить токен после удаления приложения. Вот почему вы получаете нуль. Вам нужно подождать немного, чтобы обновить токен.

Ответ 6

Иногда могут возникать проблемы с сетью, даже если интернет работает нормально... проверьте класс FirebaseInstancId определенный в файле Manifest в вашем проекте Android.

Ответ 7

Я только что упал в одной и той же проблеме, и именно так я ее исправил. Вызовите блок где-нибудь в методе onCreate() вашей деятельности. Я хочу отправить токен на свой сервер Parse, поэтому вы должны изменить его на основе ваших потребностей.

Это образец, который я выполнил.

private void subscribeUserToParse() {
        String deviceToken = FirebaseInstanceId.getInstance().getToken();
        if (TextUtils.isEmpty(deviceToken)) {
            Intent intent = new Intent(this, MyFirebaseInstanceIDService.class);
            startService(intent);
            return;
        }

        User user = UserUtil.retrieveUserFromDB(mRealm);
        String objectId = user.getParseObjectId();
        if (!TextUtils.isEmpty(objectId)) {
            ParseUtils.subscribeWithUsersObjectId(objectId, deviceToken);
        }
    }

Ответ 8

Самая большая проблема, с которой я столкнулся после написания правильного кода: не последняя версия сервисов google play в build- gradle, Поэтому всегда используйте версию google-play-services, показанную firebase при настройке диалога

Ответ 9

У меня была такая же проблема в устройстве Android 4.2. Итак, для решения проблемы сначала проверьте, есть ли у вашего сервиса в манифесте такой приоритет:

    <service
        android:name=".other.MyFirebaseInstanceIDService"
        android:exported="false">
        <intent-filter android:priority="1000">
            <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
        </intent-filter>
    </service>

Во-вторых, используйте широковещательное намерение, чтобы уведомить вашу MainActivity, которая изменила токен:

public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {

@Override
public void onTokenRefresh() {
    // Get updated InstanceID token.
    String refreshedToken = FirebaseInstanceId.getInstance().getToken();

    final Intent intent = new Intent("tokenReceiver");
    final LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
    intent.putExtra("token",refreshedToken);
    broadcastManager.sendBroadcast(intent);
}

Затем в MainActivity, в onCreate, добавьте это:

     @Override
protected void onCreate(Bundle savedInstanceState) {
...
LocalBroadcastManager.getInstance(this).registerReceiver(tokenReceiver,
            new IntentFilter("tokenReceiver"));
}

и в MainActivity добавьте новый BroadcastReceiver:

BroadcastReceiver tokenReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String token = intent.getStringExtra("token");

        if(token != null)
        {
            Log.e("firebase", String.valueOf(token));

            // send token to your server 
        }

    }
};

Ответ 10

Поскольку метод getToken() устарел, вы должны заменить его слушателем.

Просто замените String token = FirebaseInstanceId.getInstance().getToken(); следующим фрагментом кода:

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

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

Вы можете найти официальную документацию Google здесь: https://firebase.google.com/docs/cloud-messaging/android/client

И хороший средний пост также поможет вам: https://medium.com/@cdmunoz/fcm-getinstance-gettoken-in-android-is-now-deprecated-how-to-fix-it-3922a94f4fa4