从Android发送Firebase消息到主题

时间:2019-05-02 08:21:11

标签: android firebase-cloud-messaging

我想从我的Android应用程序中向FCM主题发送消息。通过Firebase控制台发送消息运行良好。但是我希望一旦用户执行了特定的操作,就会向所有订阅了特定主题的其他用户发送一条消息。

在文档中可以找到以下代码:

// The topic name can be optionally prefixed with "/topics/".
String topic = "highScores";

// See documentation on defining a message payload.
Message message = Message.builder()
.putData("score", "850")
.putData("time", "2:45")
.setTopic(topic)
.build();

// Send a message to the devices subscribed to the provided topic.
String response = FirebaseMessaging.getInstance().send(message);
// Response is a message ID string.
System.out.println("Successfully sent message: " + response);

我不知道Message是哪个类的。显然不是RemoteMessage

谢谢

4 个答案:

答案 0 :(得分:1)

您可以通过 Volley FCM API

完成此操作

这里是一个示例,用于将用户的通知发送到“ newOrder”主题,并具有标题和正文

RequestQueue mRequestQue = Volley.newRequestQueue(this);

        JSONObject json = new JSONObject();
        try {
            json.put("to", "/topics/" + "newOrder");
            JSONObject notificationObj = new JSONObject();
            notificationObj.put("title", "new Order");
            notificationObj.put("body", "New order from : " + phoneNum.replace("+", " "));
            //replace notification with data when went send data
            json.put("notification", notificationObj);

            String URL = "https://fcm.googleapis.com/fcm/send";
            JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST, URL,
                    json,
                    response -> Log.d("MUR", "onResponse: "),
                    error -> Log.d("MUR", "onError: " + error.networkResponse)
            ) {
                @Override
                public Map<String, String> getHeaders() {
                    Map<String, String> header = new HashMap<>();
                    header.put("content-type", "application/json");
                    header.put("authorization", "key=yourKey");
                    return header;
                }
            };


            mRequestQue.add(request);
        } catch (JSONException e) {
            e.printStackTrace();
        }
在Firebase项目中用服务器密钥

替换您的密钥

答案 1 :(得分:0)

无法使用Firebase Cloud Message将消息直接从一台Android设备发送到另一台设备。您将始终需要服务器(或其他受信任的环境)来执行此操作。请参阅此文档部分,其中显示how messages are sent和我的答案。此处:How to send one to one message using Firebase Messaging

您共享的代码示例正在使用Java的Admin SDK发送消息,该消息应在受信任的环境中运行。无法在您的Android应用中使用它。

答案 2 :(得分:0)

请参阅此link。。您可以通过此Google官方文档进行所需的操作。

但是我可以向您展示我通过AndroidFastNetworking库编写的示例:

# plot
plt.figure(figsize=(16, 8))
for j in range(0, len(centers)*2, 2):
    
    x_features = features[:, j]
    y_features = features[:, j+1]
    x_centers = centers[:, j]
    y_centers = centers[:, j+1]
    
    # add the data for each label to the plot
    for i, l in enumerate(labels):
        plt.plot(x_features[i], y_features[i], marker=markers[int(j/2)], color=colors[int(j/2)], alpha=0.5)

    # add the centers
    for k in range(len(centers)):  
        plt.scatter(x_centers[k], y_centers[k], marker="X", color=colors[int(j/2)])

# create the rectangles for the legend
patches = [Patch(color=v, label=k) for k, v in cmap.items()]
# create centers marker for the legend
black_x = Line2D([], [], color='k', marker='X', linestyle='None', label='centers', markersize=10)
# add the legend
plt.legend(title='Labels', handles=patches + [black_x], bbox_to_anchor=(1.04, 0.5), loc='center left', borderaxespad=0, fontsize=15)
    
plt.show()

答案 3 :(得分:-1)

这是一个使用 OkHttp 4.x 和 Kotlin 的实现:

// create the payload
val payload = JSONObject()
    .put("key", "value")       

// create the request body (POST request)
val mediaType = "application/json; charset=utf-8".toMediaType()
val requestBody = JSONObject()
    .put("to", "/topics/my_topic")
    .put("data", payload)
    .toString().toRequestBody(mediaType)

// create request
val request = Request.Builder()
    .url("https://fcm.googleapis.com/fcm/send")
    .post(requestBody)
    .addHeader("Authorization", "key=${server_key_please_replace}")
    .addHeader("Content-Type", "application/json")
    .build()

// execute the call
val response = OkHttpClient().newCall(request).execute()
val responseBody = response.body?.charStream()?.readLines()
val httpCode = response.code

// error handling goes here, it's an error if the http response code is not 200
// or if the responseBody contains an error message like
// [{"multicast_id":2633602252647458018,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}]

安全注意事项

不建议在客户端使用服务器 API 密钥,因为该密钥可以被攻击者提取,然后用于代表密钥所有者(也就是您)发送消息。然而,我认为在某些情况下风险相当低:

  • 通知消息:向所有应用用户发送通知的能力只有在这些消息可能造成伤害的情况下才有风险。就我而言,无法显示通知,因为该应用仅处理数据消息。
  • 数据消息:在我的情况下,应用程序接受特定主题,但仅当它们从同一用户 ID 发送时(我使用 FCM 在多个设备上同步同一用户的数据)。在不知道所有用户 ID 的情况下,攻击者甚至无法发送消息。用户 ID 无法检索,因为它们仅存储在设备和用户的 Google Drive 上,除非整个 Google Drive 服务受到损害,否则这是理论上的风险。最重要的是,数据消息对我来说是无害的。
  • 我看到的唯一真正风险是攻击者可以发起 DOS 攻击,以便 Google 关闭您的应用对 FCM 的访问。如果 FCM 对您的应用程序来说是关键业务,那么这就是一个真正的威胁。 但是 防止对后端 API 的相同攻击并非易事。如果您有一个 API 来发送消息,则该 API 需要受到保护。有一个端点来发送消息可能会保护 FCM 密钥,但不会保护自己免受 DOS 攻击。如果用户未通过身份验证(在许多应用中他们未通过身份验证),那么提供这种保护是一项非常重要的任务(机器人管理器解决方案成本高昂,并且在客户端和服务器之间实施 mTLS 并不简单)。

总结:虽然不建议在客户端使用服务器 API 密钥,但根据用例,安全风险非常低。许多应用无法仅为该功能运行后端服务,因此我认为在某些情况下使用服务器密钥客户端是合理的。