Незарегистрированная ошибка на сервере, сообщения FCM не получены на Android - PullRequest
0 голосов
/ 15 марта 2019

Я просмотрел все сообщения об ошибках "Not Registered" и не смог решить проблему.Я также связался со службой поддержки Firebase, к сожалению, я получил от них только URL-адреса официальной документации.

Наше приложение находилось в магазине некоторое время и успешно использовало GCM для уведомлений, когда приложение находится в фоновом режиме.Из-за устаревшего GCM мы сейчас пытаемся перейти на FCM.

Подведем итог: мы прошли шаги официальная миграция , изменили код в клиенте Android, обновили консоль Firebase, загрузили /добавлен google-services.json, а также адаптирован URL-адрес конечной точки на сервере приложений.

Теперь проблема, с которой мы сталкиваемся, заключается в следующем: приложение запрашивает токен с помощью FirebaseInstanceId singleton и успешно его получает.Этот токен мы затем отправляем на наш сервер приложений, который сохраняет его в БД.Затем сервер хочет отправить устройству Android сообщение с использованием метода Sender.sender(...), но получает печально известную ошибку «NotRegistered».Все это происходит в течение 10 секунд.

Мы попытали счастья на этих устройствах:

  • Эмулятор устройства Nexus 5X API 27 x86
  • Nexus 5X API 23
  • Pixel 2 API 28

Глядя на список причин, по которым возвращается ошибка NotRegistered, я могу прокомментировать следующее:

  1. Клиентское приложение отменяет регистрацию в FCM -> смы контролируем телефон. Я могу исключить этот пункт
  2. Удаление приложения -> то же самое здесь
  3. Срок действия регистрационного токена истекает -> возможно, но в течение 10 секунд?
  4. "Если клиентское приложение обновлено, но новая версия не настроена на получение сообщений "-> что это значит?Поскольку приложение могло получать сообщения раньше, я думаю, оно настроено на их получение.

Android-клиент

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.acme.app">

    <!-- permissions omitted for brevity -->

    <application
        android:name=".App"
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:largeHeap="true"
        android:theme="@style/AppTheme"
        tools:node="replace">

        <!-- Register AnalyticsReceiver and AnalyticsService to support background dispatching for Google Analytics on non-Google Play devices. -->
        <receiver
            android:name="com.google.android.gms.analytics.AnalyticsReceiver"
            android:enabled="true">
            <intent-filter>
                <action android:name="com.google.android.gms.analytics.ANALYTICS_DISPATCH" />
            </intent-filter>
        </receiver>

        <service
            android:name="com.google.android.gms.analytics.AnalyticsService"
            android:enabled="true"
            android:exported="false" />

        <service
            android:name=".gcm.MyGcmListenerService"
            android:exported="true"
            android:enabled="true">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />                
            </intent-filter>
        </service>
        <service android:name=".gcm.MyInstanceIDListenerService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
            </intent-filter>
        </service>
        <!-- this is need for the firebase messaging service. It should be included automatically, but somehow gets deleted by the AndroidManifest file merging. So we manually have to add it -->
        <service android:name="com.google.firebase.components.ComponentDiscoveryService">
            <meta-data
                android:name="com.google.firebase.components:com.google.firebase.iid.Registrar"
                android:value="com.google.firebase.components.ComponentRegistrar" />
        </service>

        <!-- omitted for brevity -->

        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />        
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_icon"
            android:resource="@drawable/notification_icon" />        
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_color"
            android:resource="@color/base_color" />
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="@string/default_notification_channel_id" />
    </application>

</manifest>

Код в Деятельности (сокращенно)

String token = FirebaseInstanceId.getInstance().getToken();
sendTokenToServer(token);
FirebaseMessaging.getInstance().subscribeToTopic("news");

Услуги

public class MyGcmListenerService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage message) {
        ...// never called
    }
}

Я знаю, чтоFirebaseInstanceIdService устарело, но я попробовал это также с новой версией, которая также не работает.

public class MyInstanceIDListenerService extends FirebaseInstanceIdService {
    @Override
    public void onTokenRefresh() {
        // never called...
        String token = FirebaseInstanceId.getInstance().getToken();
        sendTokenToServer(token);
    }
}

Клиент Android использует следующие зависимости:

    implementation "com.google.firebase:firebase-core:16.0.7"
    implementation "com.google.firebase:firebase-messaging:17.4.0"

Сервер приложений

На стороне сервера мы используем следующую библиотеку.Согласно документации и этому сообщению мы должны иметь возможность использовать ту же библиотеку только с адаптированным URL-адресом конечной точки (https://fcm.googleapis.com/fcm/send) без каких-либо дальнейших изменений:

com.google.gcm:gcm-server:1.0.0 

Уведомлениепостроен следующим образом:

private Message buildMessage(String title, String body, Map<String, String> attributes) {
    final Notification.Builder notificationBuilder = new Notification.Builder(null)
            .body(body)
            .title(StringUtils.trimToNull(title));
    final Message.Builder messageBuilder = new Message.Builder()
            .addData(KEY_BODY, body)
            .notification(notificationBuilder.build());

    if (!Strings.isNullOrEmpty(title)) {
        messageBuilder.addData(KEY_TITLE, title);
    }

    for (Map.Entry<String, String> attr : attributes.entrySet()) {
        messageBuilder.addData(attr.getKey(), attr.getValue());
    }
    return messageBuilder.build();
}

и отправлен с помощью этого вызова:

Result result = sender.send(message, deviceToken, retryCount);

if (result.getMessageId() == null) {
    if (ERROR_CODE_NOT_REGISTERED.equals(result.getErrorCodeName())) { // <-- returns NotRegistered
        // omitted
    } 
}

Консоль Firebase

Я загрузил отладку и выпустил SHA1sЯ также попытался отправить сообщение из консоли Firebase (Grow> Cloud Messaging> Уведомления), но на Android все еще нет сообщений.

Интересно, что у нас нет проблем с версией приложения для iOS, который также использует FCM. Сообщения с сервера приложений и с консоли Firebase приходят успешно. Однако приложение iOS никогда не использовало GCM.

Никаких подсказок? Что мы забыли? И спасибо, что прочитали здесь!

1 Ответ

0 голосов
/ 21 марта 2019

Так что это не было очевидно ... Я бился головой о стену в течение 3 дней, и этот пост привел меня на правильный путь. Следующая строка в manifest была проблемной частью:

tools:node="replace"

Это приводит к тому, что атрибуты в манифесте не объединяются, а заменяются, что приводит к тому, что важные автоматически генерируемые теги библиотекой firebase не включаются в окончательный файл manifest. Я просто удалил строку (и исправил некоторые незначительные проблемы, которые зависели от replace), чтобы исправить проблему.

Симптомом replace является следующее сообщение об ошибке

Убедитесь, что сначала вызвали FirebaseApp.initializeApp (Context)

обычно предлагаемое решение для этого (например, здесь ) - установка этой строки initializeApp где-то в начале кода. Это приводит к NPE времени выполнения при получении токена FCM. Это можно исправить с помощью еще одного хака, и вы получите приложение, которое компилирует и не выдает никаких ошибок, но также не получает никаких уведомлений (как описано в вопросе).

Итак, суть: будьте осторожны со слепым использованием принятых ответов на SO и попытайтесь понять основную проблему. Конечно, было бы полезно, если бы руководство по миграции firebase предоставило способ проверить, правильно ли были сгенерированы правильные фрагменты кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...