如何从Android发送firebase消息到主题



我想从我的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

您可以通过凌空 fcm api

做到这一点。在这里
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();
        }

替换 yourkey 服务器键在您的firebase

中的项目中

更新:正如@frank在正确答案中所说的您将始终需要服务器(或其他可信赖的环境(保持 yourkey 并不公开

因此,此答案已经有效,可以从Android发送通知到主题或令牌

但是,如果有人拿起您的钥匙也可以随时发送到您的应用程序通知因此,我建议使用 firebase函数或服务器上的任何服务,只需确保您的密钥在可信的环境中而不是可触及的

当获取键时,两种类型:1-服务器密钥2-传统服务器键

就像下面的firebase一样,我也建议先使用,因为更改或删除更灵活

Firebase将我们的服务器键升级到了新版本。您可以 继续使用您的旧服务器密钥,但建议您 升级到最新版本

没有办法将消息直接从一个具有Firebase Cloud Messaging的设备安全地发送到另一台设备。您将始终需要服务器(或其他可信赖的环境(来做到这一点。请参阅此文档部分,显示如何发送消息和我的答案。这里:如何使用Firebase Messaging发送一到一条消息。

您共享的代码示例使用admin SDK for Java发送消息,该消息本应在可信的环境中运行。它不能在您的Android应用中使用。

请参阅此链接。您可以通过此官方的Google文档来完成您需要的事情。

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

        JSONObject dataJsonObject = new JSONObject();
        dataJsonObject.put("anyDataYouWant":"value");
        try {
            bodyJsonObject.put("to", "/topics/topic");
            bodyJsonObject.put("data", dataJsonObject);
            
        } catch (JSONException e) {
            e.printStackTrace();
        }
        
        
        
        
        AndroidNetworking.post("https://fcm.googleapis.com/fcm/send")
                .setContentType("application/json; charset=utf-8")
                .addJSONObjectBody(bodyJsonObject)
                .addHeaders("Authorization", "Your Firebase Authorization Key with 'key=' prefix:  ("key=AAAAjHK....") ")
                .setPriority(Priority.HIGH)
                .build()
                .getAsJSONObject(new JSONObjectRequestListener() {
                    @Override
                    public void onResponse(JSONObject response) {
                        Toast.makeText(context, "Success", Toast.LENGTH_SHORT).show();
                    }
                    
                    
                    @Override
                    public void onError(ANError anError) {
                        Toast.makeText(context, "Error: " + anError.toString(), Toast.LENGTH_SHORT).show();
                    }
                });

这是使用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驱动器,否则除非整个Google Drive Service都会损害Google Drive服务,否则这是一种理论风险。最重要的是,在我的情况下,数据消息是无害的。
  • 我看到的唯一真正的风险是攻击者可以发起DOS攻击,以便Google关闭对您的应用程序的FCM访问。如果FCM对您的应用至关重要,那么这是一个真正的威胁。防止对您的后端API进行相同的攻击并不小。如果您有发送消息的API,则需要保护API。有一个发送消息的终点可能会保护FCM密钥,但不能保护DOS攻击本身。如果用户未经身份验证(在许多应用程序中,它们不是(,则说明保护是一项非琐碎的任务(Bot Manager解决方案很昂贵,并且在客户端和服务器之间实现MTL并不简单(。

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

相关内容

  • 没有找到相关文章

最新更新