来自Java而不是Firebase控制台的Firebase云消息传递通知

San*_*ena 27 java firebase firebase-cloud-messaging

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

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

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

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

为此,我按照此处列出的步骤进行了操作 - https://firebase.google.com/docs/server/setup#prerequisites.具体来说,这些是我执行的步骤:

  1. 创建了一个名为My Notification ServerFirebase Console 的新项目.
  2. Settings > Permissions在Firebase控制台中使用,创建了一个新的服务帐户并下载了该serviceAccountCredentials.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>
Run Code Online (Sandbox Code Playgroud)
  1. 然后,我扩展com.google.android.gcm.sender.Sender为创建FCMSender并覆盖受保护的方法getConnection(String url)以使用新的FCM端点,如下所示:

    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();
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. main()我的Java应用程序的方法如下所示:

    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();
            }
        }
    
    Run Code Online (Sandbox Code Playgroud)

当我运行Java应用程序时,我收到MismatchSenderId错误.我尝试使用curl如下所示的故障排除,但得到了同样的错误:

$ 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"}]}
Run Code Online (Sandbox Code Playgroud)

我没有在Firebase控制台中使用Server Key列表中Project Settings > Cloud MessagingMy Notification Server项目列表,而是尝试使用Project Number但是由此引起的InvalidRequestException: HTTP Status Code: 401.

错误代码的Firebase文档说明了这一点MismatchSenderId:

不匹配的发件人200 + error:MismatchSenderId
注册令牌绑定到某组发件人.当客户端应用程序注册FCM时,它必须指定允许哪些发件人发送消息.在向客户端应用程序发送消息时,您应该使用其中一个发件人ID.如果您切换到其他发件人,现有的注册令牌将无法使用.

我无法弄清楚Firebase控制台的位置/方式可以配置Android应用程序(已经与My Notification Client项目相关)以便能够接收消息.

对此有任何帮助,将不胜感激!

小智 9

我最近也开始使用Firebase,没有谷歌云消息传递方面的经验.AFAIK,目前还没有适用于Firebase云消息传递的服务器端SDK.

要将通知/消息从App Server发送到Mobile Client,您需要实现自己的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;
}
Run Code Online (Sandbox Code Playgroud)

注意:http客户端和json是由vertx(http://vertx.io/)提供的,但希望代码能够清楚地显示出足够清晰的内容,以便您可以使用任何您想要的内容.

  • 不推荐使用firebase-server-sdk以支持firebase-admin-sdk,并引用后者的Google文档:"Firebase Admin Java SDK目前没有FCM API.如果要从非节点发送消息.在js服务器上,您应该使用HTTP或XMPP API,如关于Firebase Cloud Messaging Server中所述.FCM是Firebase云消息传递. (3认同)
  • @Hamedz不能用于我能找到的FCM. (2认同)

小智 6

我遇到了同样的问题.问题在于:

String serverKey = <get_server_key_from_firebase_console>;
Run Code Online (Sandbox Code Playgroud)

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