Firebase Cloud Messaging 通知来自 Java 而不是 Firebase Console

2022-09-01 11:01:47

我是 Firebase 的新手,当我的 Java 应用程序尝试使用客户端的 Firebase 令牌发送通知/消息时,我遇到了一些错误,例如发件人 ID 不匹配和 HTTP 状态为 401 的身份验证错误。请注意,使用 Firebase 控制台,我可以将消息发送给客户端。

对于客户端应用,我执行以下操作:

  1. 从这里克隆的Firebase快速入门应用程序 - https://github.com/firebase/quickstart-android/tree/master/messaging - 它已经设置了Firebase依赖项等。已在 中加载克隆的应用程序。messagingAndroid Studio
  2. 使用 Firebase 控制台创建了一个名为“新项目”,并使用该应用的程序包名称添加了一个应用。My Notification Clientcom.google.firebase.quickstart.fcm
  3. 已下载的 Android 应用的文件已添加到新创建的项目中,并将其复制到文件夹中,并与 中的 Grade 文件同步。google-services.jsonmessaging/app/Android Studio
  4. 已创建模拟器并从 内部运行应用。在模拟器中加载应用后,单击按钮以在 的选项卡中捕获客户端的 Firebase 令牌。Android StudioLog TokenAndroid MonitorAndroid Studio
  5. 使用 Firebase 控制台,选择新创建的项目,单击左窗格中的链接,然后通过粘贴在上一步中捕获的 Firebase 令牌向设备发送通知。My Notification ClientNotifications

这效果很好!下一步是使用单独的简单 Java 应用程序(最终成为通知服务器)将通知发送到客户端,而不是使用 Firebase 控制台。

为了实现这一点,我按照这里概述的步骤 - https://firebase.google.com/docs/server/setup#prerequisites。具体来说,这些是我执行的步骤:

  1. 在 Firebase 控制台中创建了一个名为“新项目”。My Notification Server
  2. 在 Firebase 控制台中使用时,创建了一个新的服务帐户并下载了该文件。Settings > PermissionsserviceAccountCredentials.json
  3. 在 Eclipse 中创建了一个新的 maven 项目,并在 pom.xml 中添加了以下依赖项:
    <dependency>
      <groupId>com.google.gcm</groupId>
      <artifactId>gcm-server</artifactId>
      <version>1.0.0</version>
    </dependency>
    <dependency>
      <groupId>com.googlecode.json-simple</groupId>
      <artifactId>json-simple</artifactId>
      <version>1.1.1</version>
    </dependency>
    <dependency>
      <groupId>com.google.firebase</groupId>
      <artifactId>firebase-server-sdk</artifactId>
      <version>3.0.0</version>
    </dependency>
  1. 然后,我扩展以创建并重写受保护的方法以使用新的FCM端点,如下所示:com.google.android.gcm.sender.SenderFCMSendergetConnection(String url)

    class FCMSender extends Sender {
    
        public FCMSender(String key) {
            super(key);
        }
    
        @Override
        protected HttpURLConnection getConnection(String url) throws IOException {
            String fcmUrl = "https://fcm.googleapis.com/fcm/send";
            return (HttpURLConnection) new URL(fcmUrl).openConnection();
        }
    }
    
  2. 我的 Java 应用程序的方法如下所示:main()

    public static void main(String[] args) {
        // Obtain serverKey from Project Settings -> Cloud Messaging tab
        // for "My Notification Client" project in Firebase Console.
        String serverKey = <get_server_key_from_firebase_console>;
        Thread t = new Thread() {
            public void run(){ 
                try {
                    Sender sender = new FCMSender(serverKey);
                    Message message = new Message.Builder()
                                      .collapseKey("message")
                                      .timeToLive(3)
                                      .delayWhileIdle(true)
                                      .addData("message", "Notification from Java application");
                                      .build();  
    
                    // Use the same token(or registration id) that was earlier
                    // used to send the message to the client directly from
                    // Firebase Console's Notification tab.
                    Result result = sender.send(message,
                "APA91bFfIFjSCcSiJ111rbmkpnMkZY-Ej4RCpdBZFZN_mYgfHwFlx-M1UXS5FqDBcN8x1efrS2md8L9K_E9N21qB-PIHUqQwmF4p7Y3U-86nCGH7KNkZNjjz_P_qjcTR0TOrwXMh33vp",
                        1);
                    System.out.println("Result: " + result.toString());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            };
            t.start;
            try {
                t.join();
            }
            catch (InterruptedException iex) {
                iex.printStackTrace();
            }
        }
    

当我运行Java应用程序时,我收到错误。我尝试使用如下所示进行故障排除,但收到相同的错误:MismatchSenderIdcurl

$ skey=<obtained_from_project_settings_cloud_messaging_tab_in_firebase_console>
$ curl -X POST --header "Authorization: key=$skey" \
  --Header "Content-Type: application/json" \
  https://fcm.googleapis.com/fcm/send \
  -d "{\"to\":\"APA91bFfIFjSCcSiJ111rbmkpnMkZY-Ej4RCpdBZFZN_mYgfHwFlx-M1UXS5FqDBcN8x1efrS2md8L9K_E9N21qB-PIHUqQwmF4p7Y3U-86nCGH7KNkZNjjz_P_qjcTR0TOrwXMh33vp\",\"data\":{\"message\":\"Yellow\"}}"

{"multicast_id":7391851081942579857,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"MismatchSenderId"}]}

我没有在Firebase控制台中为项目使用列出的“上”选项卡,而是尝试使用但导致.Server KeyProject Settings > Cloud MessagingMy Notification ServerProject NumberInvalidRequestException: HTTP Status Code: 401

Firebase错误代码的文档是这样说的:MismatchSenderId

不匹配的发件人 200 +
注册令牌绑定到一组特定的发件人。当客户端应用注册 FCM 时,它必须指定允许哪些发件人发送消息。向客户端应用发送消息时,应使用这些发件人 ID 之一。如果切换到其他发件人,则现有的注册令牌将不起作用。error:MismatchSenderId

我无法弄清楚在Firebase控制台中,在哪里/如何配置Android应用程序(该项目已加入)以便能够接收消息。My Notification Client

任何这方面的帮助,将不胜感激!


答案 1

我最近也开始使用Firebase,之前没有Google Cloud Messaging的经验。AFAIK,目前没有用于Firebase Cloud Messaging的服务器端SDK。

要将通知/消息从您的应用服务器发送到您的移动客户端,您需要实现自己的 HTTP 和/或 XMPP 方法。查看 https://firebase.google.com/docs/cloud-messaging/

我的测试代码,使用HTTP:

public CompletableFuture<String> fcmTest1() {
    // https://firebase.google.com/docs/cloud-messaging/http-server-ref
    String host = "fcm.googleapis.com";
    String requestURI = "/fcm/send";
    String CLIENT_TOKEN = "ASK_YOUR_MOBILE_CLIENT_DEV"; // https://developers.google.com/instance-id/

    CompletableFuture<String> fut = new CompletableFuture<>();
    JsonObject body = new JsonObject();
    // JsonArray registration_ids = new JsonArray();
    // body.put("registration_ids", registration_ids);
    body.put("to", CLIENT_TOKEN);
    body.put("priority", "high");
    // body.put("dry_run", true);

    JsonObject notification = new JsonObject();
    notification.put("body", "body string here");
    notification.put("title", "title string here");
    // notification.put("icon", "myicon");

    JsonObject data = new JsonObject();
    data.put("key1", "value1");
    data.put("key2", "value2");

    body.put("notification", notification);
    body.put("data", data);

    HttpClientRequest hcr = httpsClient.post(443, host, requestURI).handler(response -> {
        response.bodyHandler(buffer -> {
            logger.debug("FcmTest1 rcvd: {}, {}", response.statusCode(), buffer.toString());
            if (response.statusCode() == 200) {
                fut.complete(buffer.toString());
            } else {
                fut.completeExceptionally(new RuntimeException(buffer.toString()));
            }
        });
    });
    hcr.putHeader("Authorization", "key=" + Utils.FIREBASE_SERVER_KEY)
        .putHeader("content-type", "application/json").end(body.encode());
    return fut;
}

注意:http客户端和json是由vertx提供的(http://vertx.io/),但希望代码显示正在发生的事情足够清晰,以便您可以使用任何您想要的东西。


答案 2

我遇到了同样的问题。问题出在线路上:

String serverKey = <get_server_key_from_firebase_console>;

这个值应该来自Android应用程序项目;在这种情况下,它将是“我的通知客户端”,而不是“我的通知服务器”。


推荐