如何通过 CURL 向所有设备发送 Firebase 通知?

我试图发送一个通知给所有的应用程序用户(在 Android 上) ,本质上是复制通过 Firebase 管理控制台发送通知时发生的事情。下面是我首先使用的 CURL 命令:

Curl —— security —— header“ Authorization: key = AIzaSyBidmyauthkeyisfineL-6NcJxj-1JUvEM”—— header“ Content-Type: application/json”-d”{“ tification”: {“ title”: “ note-Title”,“ body”: “ note-Body”}}“ https://fcm.googleapis.com/fcm/send

这里解析出的 JSON 对您的眼睛来说更容易:

{
"notification":{
"title":"note-Title",
"body":"note-Body"
}
}

得到的回应只有两个字符:

对了,就是“去”这个词。(报头400)我怀疑这与我的 JSON 中没有“ to”有关。一个人怎么会把“ to”写成“ to”呢?我没有定义主题,设备也没有为任何东西注册自己。然而,他们仍然能够接收来自 Firebase 管理面板的通知。

我想尝试一个“仅数据”的 JSON 包,因为 Firebase 通知处理的惊人限制,如果你的应用在前台,通知将由你的处理器处理,但如果你的应用在后台,它将由 Firebase 服务内部处理,永远不会传递给你的通知处理器。显然,如果你通过 API 提交你的通知请求,这个问题可以解决,但是只有当你只使用数据的时候。(这就打破了用同样的信息处理 iOS 和 Android 的能力。)在我的 JSON 中用“数据”替换“通知”没有任何效果。

好的,然后我在这里尝试了解决方案: Firebase Java Server 向所有设备发送推送通知 在我看来,这意味着“好吧,即使通过管理控制台向每个人发送通知是可能的... ... 但是通过 API 实际上是不可能的。”解决方案是让每个客户端订阅一个主题,然后推出该主题的通知。首先,onCreate 中的代码是:

FirebaseMessaging.getInstance().subscribeToTopic("allDevices");

然后我发送新的 JSON:

{
"notification":{
"title":"note-Title",
"body":"note-Body"
},
"to":"allDevices"
}

所以现在我至少从服务器得到了一个真实的响应。 JSON 响应:

{
"multicast_id":463numbersnumbers42000,
"success":0,
"failure":1,
"canonical_ids":0,
"results":
[
{
"error":"InvalidRegistration"
}
]
}

还有一个 HTTP 代码200。好的... 根据 https://firebase.google.com/docs/cloud-messaging/http-server-ref的一个200代码与“无效注册”意味着与注册令牌的问题。也许吧?因为这部分文档是针对消息传递服务器的。通知服务器是否相同?不清楚。我在其他地方看到,这个话题可能需要几个小时才会被激活。似乎这会使得创建新的聊天室变得毫无用处,所以这看起来也是错误的。

当我能够从头开始编写一个应用程序时,我非常兴奋,因为我以前从未使用过 Firebase,而这个应用程序能够在几个小时内收到通知。在达到 Stripe.com 文档的水平之前,似乎还有很长的路要走。

底线: 是否有人知道提供什么样的 JSON 来向所有运行应用程序的设备发送消息以镜像管理控制台功能?

152729 次浏览

Firebase Notifications doesn't have an API to send messages. Luckily it is built on top of Firebase Cloud Messaging, which has precisely such an API.

With Firebase Notifications and Cloud Messaging, you can send so-called downstream messages to devices in three ways:

  1. to specific devices, if you know their device IDs
  2. to groups of devices, if you know the registration IDs of the groups
  3. to topics, which are just keys that devices can subscribe to

You'll note that there is no way to send to all devices explicitly. You can build such functionality with each of these though, for example: by subscribing the app to a topic when it starts (e.g. /topics/all) or by keeping a list of all device IDs, and then sending the message to all of those.

For sending to a topic you have a syntax error in your command. Topics are identified by starting with /topics/. Since you don't have that in your code, the server interprets allDevices as a device id. Since it is an invalid format for a device registration token, it raises an error.

From the documentation on sending messages to topics:

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA


{
"to": "/topics/foo-bar",
"data": {
"message": "This is a Firebase Cloud Messaging Topic Message!",
}
}

Your can send notification to all devices using "/topics/all"

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA


{
"to": "/topics/all",
"notification":{ "title":"Notification title", "body":"Notification body", "sound":"default", "click_action":"FCM_PLUGIN_ACTIVITY", "icon":"fcm_push_icon" },
"data": {
"message": "This is a Firebase Cloud Messaging Topic Message!",
}
}

One way to do that is to make all your users' devices subscribe to a topic. That way when you target a message to a specific topic, all devices will get it. I think this how the Notifications section in the Firebase console does it.

The most easiest way I came up with to send the push notification to all the devices is to subscribe them to a topic "all" and then send notification to this topic. Copy this in your main activity

FirebaseMessaging.getInstance().subscribeToTopic("all");

Now send the request as

{
"to": "/topics/all",
"data":
{
"title":"Your title",
"message":"Your message"
"image-url":"your_image_url"
}
}

This might be inefficient or non-standard way, but as I mentioned above it's the easiest. Please do post if you have any better way to send a push notification to all the devices.

Just checked the FCM documentation, this is the only way to send notifications to all the devices (as of 8th July 2022).

As mentioned in the comments, the notification is not automatically displayed, you have to define a class that is derived from FirebaseMessagingService and then override the function onMessageReceived.

First register your service in app manifest.

<!-- AndroidManifest.xml -->


<service
android:name=".java.MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>

Add these lines inside the application tag to set the custom default icon and custom color:

<!-- AndroidManifest.xml -->


<!-- Set custom default icon. This is used when no icon is set
for incoming notification messages. -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_stat_ic_notification" />
<!-- Set color used with incoming notification messages. This is used
when no color is set for the incoming notification message. -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/colorAccent" />

Now create your service to receive the push notifications.

// MyFirebaseMessagingService.java


package com.google.firebase.example.messaging;


import android.content.Context;
import android.util.Log;


import androidx.annotation.NonNull;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
import androidx.work.Worker;
import androidx.work.WorkerParameters;


import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;


public class MyFirebaseMessagingService extends FirebaseMessagingService {


private static final String TAG = "MyFirebaseMsgService";


// [START receive_message]
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());


// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());


if (/* Check if data needs to be processed by long running job */ true) {
// For long-running tasks (10 seconds or more) use WorkManager.
scheduleJob();
} else {
// Handle message within 10 seconds
handleNow();
}


}


// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
}


}
// [END receive_message]


// [START on_new_token]
/**
* There are two scenarios when onNewToken is called:
* 1) When a new token is generated on initial app startup
* 2) Whenever an existing token is changed
* Under #2, there are three scenarios when the existing token is changed:
* A) App is restored to a new device
* B) User uninstalls/reinstalls the app
* C) User clears app data
*/
@Override
public void onNewToken(@NonNull String token) {
Log.d(TAG, "Refreshed token: " + token);


// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// FCM registration token to your app server.
sendRegistrationToServer(token);
}
// [END on_new_token]


private void scheduleJob() {
// [START dispatch_job]
OneTimeWorkRequest work = new OneTimeWorkRequest.Builder(MyWorker.class)
.build();
WorkManager.getInstance(this).beginWith(work).enqueue();
// [END dispatch_job]
}


private void handleNow() {
Log.d(TAG, "Short lived task is done.");
}


private void sendRegistrationToServer(String token) {
// TODO: Implement this method to send token to your app server.
}


public static class MyWorker extends Worker {


public MyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}


@NonNull
@Override
public Result doWork() {
// TODO(developer): add long running task here.
return Result.success();
}
}
}

You can follow this tutorial if you're new to sending push notifications using Firebase Cloud Messaging Tutorial - Push Notifications using FCM and Send messages to multiple devices - Firebase Documentation


To send a message to a combination of topics, specify a condition, which is a boolean expression that specifies the target topics. For example, the following condition will send messages to devices that are subscribed to TopicA and either TopicB or TopicC:

{
"data":
{
"title": "Your title",
"message": "Your message"
"image-url": "your_image_url"
},
"condition": "'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)"
}

Read more about conditions and topics here on FCM documentation

Just make all users who log in subscribe to a specific topic, and then send a notification to that topic.

I was looking solution for my Ionic Cordova app push notification.

Thanks to Syed Rafay's answer.

in app.component.ts

const options: PushOptions = {
android: {
topics: ['all']
},

in Server file

"to" => "/topics/all",

EDIT: It appears that this method is not supported anymore (thx to @FernandoZamperin). Please take a look at the other answers!

Instead of subscribing to a topic you could instead make use of the condition key and send messages to instances, that are not in a group. Your data might look something like this:

{
"data": {
"foo": "bar"
},
"condition": "!('anytopicyoudontwanttouse' in topics)"
}

See https://firebase.google.com/docs/cloud-messaging/send-message#send_messages_to_topics_2

Check your topic list on firebase console.

  1. Go to firebase console

  2. Click Grow from side menu

  3. Click Cloud Messaging

  4. Click Send your first message

  5. In the notification section, type something for Notification title and Notification text

  6. Click Next

  7. In target section click Topic

  8. Click on Message topic textbox, then you can see your topics (I didn't created topic called android or ios, but I can see those two topics.

  9. When you send push notification add this as your condition.

    "condition"=> "'all' in topics || 'android' in topics || 'ios' in topics",

Full body

array(
"notification"=>array(
"title"=>"Test",
"body"=>"Test Body",
),
"condition"=> "'all' in topics || 'android' in topics || 'ios' in topics",
);

If you have more topics you can add those with || (or) condition, Then all users will get your notification. Tested and worked for me.

For anyone wondering how to do it in cordova hybrid app:

  • go to index.js -> inside the function onDeviceReady() write :

      subscribe();
    

(It's important to write it at the top of the function!)

  • then, in the same file (index.js) find :

    function subscribe(){

     FirebasePlugin.subscribe("write_here_your_topic", function(){
    
    
    },function(error){
    
    
    logError("Failed to subscribe to topic", error);
    });
    }
    

and write your own topic here -> "write_here_your_topic"

It is a PHP Admin-SDK example to subscribe an user to a Topic and to send messages to a device by device token or to a Topic. Note that the Topic is created automatically when you subscribe an user.

$testTokens = ['device token 1', 'device token 2', ....]


// CREDENTIALS, YOU HAVE TO DOWNLOAD IT FROM FIREBASE CONSOLE.
$factory = (new Factory())->withServiceAccount('credentials.json');


$messaging = $factory->createMessaging();


// Subscribe a token or a group of tokens to a topic (this topic is created automatically if not exists)
// YOU CAN DO THIS IN THE MOBILE APP BUT IS BETTER DO IT IN THE API.
$result = $messaging->subscribeToTopic('all', $testTokens); // 'all' is the topic name


// Send a message to a specific Topic (Channel)
$message = CloudMessage::withTarget('topic', 'all')
->withNotification(Notification::create('Global message Title', 'Global message Body'))
->withData(['key' => 'value']); // optional
$messaging->send($message);


// Send a message to a token or a grup of tokens (ONLY!!!)
foreach($testTokens as $i=>$token){
$message = CloudMessage::withTarget('token', $token)
->withNotification(Notification::create('This is the message Title', 'This is the message Body'))
->withData(['custom_index' => $i]); // optional
$messaging->send($message);

You can check this repo for more details: firebase-php-admin-sdk