服务器未注册错误,Android设备无法接收FCM消息

3
我查看了所有“未注册”错误的帖子,但无法解决问题。我也联系了Firebase支持,不幸的是他们只给我提供了官方文档的网址。
我们的应用程序已经在商店中运行了一段时间,并且在应用程序处于后台时成功使用GCM进行通知。由于GCM的弃用,我们目前正在尝试迁移到FCM。
简而言之:我们按照官方迁移步骤进行了official migration,更改了Android客户端中的代码,更新了Firebase控制台,下载/添加了google-services.json并调整了应用服务器上的终端点URL。
现在我们面临的问题如下: 应用程序使用FirebaseInstanceId单例请求令牌,并成功接收到令牌。然后,我们将此令牌转发到我们的应用程序服务器,该服务器将其保存在数据库中。然后,服务器想使用Sender.sender(...)方法向Android设备发送消息,但收到臭名昭著的“NotRegistered”错误。所有这些都发生在大约10秒内。
我们在这些设备上尝试了我们的运气:
  • 模拟器设备 Nexus 5X API 27 x86
  • Nexus 5X API 23
  • Pixel 2 API 28

查看list中返回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");

Services

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控制台
我上传了应用程序的调试和发布SHA1。我还尝试从Firebase控制台发送消息(Grow> Cloud messaging> Notifications),但Android上仍然没有收到消息。
有趣的是,我们的iOS应用程序版本没有任何问题,它也使用FCM。来自应用程序服务器和Firebase控制台的消息都成功到达。但是,iOS应用程序从未使用过GCM。
有什么线索吗?我们忘记了什么?感谢您阅读到这里!

当您不从Play商店安装或手动安装发布的APK时,您的APK是否正常工作? - Dhaval Solanki
@DhavalSolanki 目前具有 FCM 代码的 APK 并未在 Play 商店中提供,只有 GCM 版本。但是,无论是通过 Android Studio 安装的发布版还是调试版都无法正常工作,即我可以安装它们,但 FCM 无效。 - SOERGI
1个回答

1

所以这个问题并不明显...我已经撞了3天的墙,this post让我找到了正确的路径。下面这行在清单中是有问题的:

tools:node="replace"

它导致清单中的属性不会合并,而是被替换,这导致 Firebase 库自动生成的重要标签未包含在最终的 manifest 文件中。我只需删除该行(并修复一些依赖于其为 replace 的小问题)即可解决此问题。 replace 的症状是以下错误消息:

确保先调用 FirebaseApp.initializeApp(Context)

一个常见的解决方案(例如here)是在代码的早期某个位置设置 initializeApp 行。这会导致在获取 FCM 令牌时出现运行时 NPE。可以使用另一个 hack 解决这个问题,然后你就会得到一个编译无误且不会抛出任何错误的应用程序,但也不会接收任何通知(如问题描述)。
因此,要点是:谨慎盲目地使用 SO 上的已接受答案,并尝试理解潜在问题。当然,如果 Firebase 迁移指南提供了验证正确生成代码的方法将会很有帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接