Wysyłanie wiadomości na wiele urządzeń

Aby kierować wiadomość na wiele urządzeń, skorzystaj z funkcji Wiadomości na temat tematów. Ta funkcja pozwala na wysyłanie wiadomości na wiele urządzeń, które wyraziły zgodę na konkretny temat.

Ten samouczek dotyczy wysyłania wiadomości dotyczących tematów z serwera aplikacji za pomocą pakietu Admin SDK lub interfejsu API REST w FCM oraz ich odbierania i obsługiwania w aplikacji na Androida. Omówimy obsługę wiadomości zarówno w aplikacjach działających w tle, jak i na pierwszym planie. Omówiliśmy wszystkie kroki, które należy podjąć, od konfiguracji po weryfikację.

Konfigurowanie pakietu SDK

W tej sekcji mogą się znaleźć informacje o krokach, które zostały już przez Ciebie wykonane, jeśli masz skonfigurowaną aplikację kliencką na Androida dla FCM lub wykonanie kroków wysyłania pierwszej wiadomości.

Zanim zaczniesz

  • Zainstaluj lub zaktualizuj Android Studio do najnowszej wersji.

  • Sprawdź, czy projekt spełnia te wymagania (pamiętaj, że niektóre usługi mogą mieć bardziej rygorystyczne wymagania):

    • Jest kierowana na interfejs API na poziomie 19 (KitKat) lub wyższym
    • Korzysta z Androida 4.4 lub nowszego
    • Wykorzystuje pakiet Jetpack (AndroidX), który spełnia te wymagania dotyczące wersji:
      • com.android.tools.build:gradle w wersji 7.3.0 lub nowszej
      • compileSdkVersion w wersji 28 lub nowszej
  • Skonfiguruj urządzenie fizyczne lub użyj emulatora do uruchamiania aplikacji.
    Pamiętaj, że pakiety SDK Firebase bazujące na usługach Google Playwymagają zainstalowania urządzenia lub usług Google Play.

  • Zaloguj się w Firebase, korzystając ze swojego konta Google.

Jeśli nie masz jeszcze projektu na Androida i chcesz wypróbować usługę Firebase, możesz pobrać krótkie wprowadzenie.

Utwórz projekt Firebase

Zanim dodasz Firebase do swojej aplikacji na Androida, musisz utworzyć projekt Firebase, który będzie połączony z tą aplikacją. Więcej informacji o projektach Firebase znajdziesz w artykule Omówienie projektów Firebase.

Zarejestruj aplikację w Firebase

Aby używać Firebase w swojej aplikacji na Androida, musisz ją zarejestrować w projekcie Firebase. Rejestracja aplikacji to często tzw. „dodanie” jej do projektu.

  1. Otwórz konsolę Firebase.

  2. Na środku strony przeglądu projektu kliknij ikonę Androida () lub Dodaj aplikację, aby uruchomić proces konfiguracji.

  3. Wpisz nazwę pakietu aplikacji w polu Nazwa pakietu na Androida.

  4. (Opcjonalnie) Wpisz inne informacje o aplikacji: Nazwa aplikacji i Certyfikat debugowania SHA-1.

  5. Kliknij Zarejestruj aplikację.

Dodaj plik konfiguracji Firebase

  1. Pobierz, a następnie dodaj do aplikacji plik konfiguracyjny Firebase na Androida (google-services.json):

    1. Kliknij Pobierz google-services.json, aby uzyskać plik konfiguracyjny Firebase na Androida.

    2. Przenieś plik konfiguracyjny do katalogu głównego modułu (na poziomie aplikacji) aplikacji.

  2. Aby wartości w pliku konfiguracyjnym google-services.json były dostępne dla pakietów SDK Firebase, potrzebujesz wtyczki do Gradle usług Google (google-services).

    1. W pliku Gradle głównym (na poziomie projektu) (<project>/build.gradle.kts lub <project>/build.gradle) dodaj wtyczkę usług Google jako zależność:

      Kotlin

      plugins {
        id("com.android.application") version "7.3.0" apply false
        // ...
      
        // Add the dependency for the Google services Gradle plugin
        id("com.google.gms.google-services") version "4.4.1" apply false
      }
      

      Groovy

      plugins {
        id 'com.android.application' version '7.3.0' apply false
        // ...
      
        // Add the dependency for the Google services Gradle plugin
        id 'com.google.gms.google-services' version '4.4.1' apply false
      }
      
    2. W pliku Gradle modułu (na poziomie aplikacji) (zwykle <project>/<app-module>/build.gradle.kts lub <project>/<app-module>/build.gradle) dodaj wtyczkę usług Google:

      Kotlin

      plugins {
        id("com.android.application")
      
        // Add the Google services Gradle plugin
        id("com.google.gms.google-services")
        // ...
      }
      

      Groovy

      plugins {
        id 'com.android.application'
      
        // Add the Google services Gradle plugin
        id 'com.google.gms.google-services'
        // ...
      }
      

Dodaj do aplikacji pakiety SDK Firebase

  1. W pliku Gradle modułu (na poziomie aplikacji) (zwykle <project>/<app-module>/build.gradle.kts lub <project>/<app-module>/build.gradle) dodaj zależność do biblioteki Komunikacji w chmurze Firebase (FCM) na Androida. Do kontrolowania obsługi wersji biblioteki zalecamy używanie BOM Firebase na Androida.

    Aby w pełni wykorzystać możliwości Firebase Cloud Messaging, włącz Google Analytics w projekcie Firebase i dodaj do aplikacji pakiet SDK Firebase dla Google Analytics.

    dependencies {
        // Import the BoM for the Firebase platform
        implementation(platform("com.google.firebase:firebase-bom:33.0.0"))
    
        // Add the dependencies for the Firebase Cloud Messaging and Analytics libraries
        // When using the BoM, you don't specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-messaging")
        implementation("com.google.firebase:firebase-analytics")
    }
    

    Dzięki wykorzystaniu BM od Firebase Android Twoja aplikacja zawsze będzie używała zgodnych wersji bibliotek Firebase na Androida.

    (Alternatywnie) Dodaj zależności biblioteki Firebase bez użycia BoM.

    Jeśli nie chcesz używać BoM Firebase, musisz określić każdą wersję biblioteki Firebase w wierszu zależności.

    Pamiętaj, że jeśli w aplikacji używasz wielu bibliotek Firebase, zdecydowanie zalecamy korzystanie z BoM do zarządzania wersjami biblioteki. Zapewni to zgodność wszystkich wersji.

    dependencies {
        // Add the dependencies for the Firebase Cloud Messaging and Analytics libraries
        // When NOT using the BoM, you must specify versions in Firebase library dependencies
        implementation("com.google.firebase:firebase-messaging:24.0.0")
        implementation("com.google.firebase:firebase-analytics:22.0.0")
    }
    
    Szukasz modułu biblioteki dotyczącego konkretnego narzędzia Kotlin? Od października 2023 r. (Firebase BoM w wersji 32.5.0) deweloperzy korzystający z Kotlin i Javy mogą korzystać z modułu biblioteki głównej (szczegółowe informacje znajdziesz w odpowiedziach na najczęstsze pytania na temat tej inicjatywy).

  2. Zsynchronizuj projekt na Androida z plikami Gradle.

Subskrybowanie tematu w aplikacji klienckiej

Aplikacje klienckie mogą subskrybować dowolny istniejący temat lub tworzyć nowe. Gdy aplikacja kliencka subskrybuje nową nazwę tematu (taką, która jeszcze nie istnieje w Twoim projekcie Firebase), w FCM jest tworzony nowy temat o tej nazwie i każdy klient może go zasubskrybować.

Aby zasubskrybować temat, aplikacja klienta wywołuje funkcję subscribeToTopic() Komunikacji w chmurze Firebase (FCM), podając nazwę tematu w FCM. Ta metoda zwraca wartość Task, której może użyć detektor ukończenia, aby określić, czy subskrypcja się powiodła:

Kotlin+KTX

Firebase.messaging.subscribeToTopic("weather")
    .addOnCompleteListener { task ->
        var msg = "Subscribed"
        if (!task.isSuccessful) {
            msg = "Subscribe failed"
        }
        Log.d(TAG, msg)
        Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
    }

Java

FirebaseMessaging.getInstance().subscribeToTopic("weather")
        .addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                String msg = "Subscribed";
                if (!task.isSuccessful()) {
                    msg = "Subscribe failed";
                }
                Log.d(TAG, msg);
                Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
            }
        });

Aby anulować subskrypcję, aplikacja klienta wywołuje funkcję Firebase Cloud Messaging unsubscribeFromTopic() z nazwą tematu.

Odbieranie i obsługa wiadomości z określonego tematu

FCM dostarcza wiadomości z danego tematu w taki sam sposób jak inne wiadomości powiązane z danym tematem.

Aby odbierać wiadomości, użyj usługi, która rozszerza zakres FirebaseMessagingService. Twoja usługa powinna zastąpić wywołania zwrotne onMessageReceived i onDeletedMessages.

Czas obsługi wiadomości może być krótszy niż 20 sekund w zależności od opóźnień występujących przed wywołaniem onMessageReceived, w tym opóźnień systemu operacyjnego, czasu uruchamiania aplikacji, blokowania wątku głównego przez inne operacje lub zbyt długiego wykonywania wcześniejszych połączeń onMessageReceived. Po tym czasie różne zachowania systemu operacyjnego, takie jak zamykanie procesów czy limity wykonywania w tle Androida O, mogą zakłócać wykonywanie pracy.

Typ onMessageReceived jest dostępny w przypadku większości typów wiadomości, z tymi wyjątkami:

  • Powiadomienia dostarczane, gdy aplikacja działa w tle. W takim przypadku powiadomienie jest dostarczane do obszaru powiadomień urządzenia. Kliknięcie powiadomienia domyślnie otwiera menu z aplikacjami.

  • Wiadomości z powiadomieniami i ładunkiem danych, gdy są odbierane w tle. W tym przypadku powiadomienie jest dostarczane do obszaru powiadomień urządzenia, a ładunek danych jest dostarczany w dodatkami do intencji aktywności programu uruchamiającego.

W skrócie:

Stan aplikacji Powiadomienie Dane Oba rodzaje
Pierwszy plan onMessageReceived onMessageReceived onMessageReceived
Tło Obszar powiadomień onMessageReceived Powiadomienie: obszar powiadomień
Dane: w dodatkowych intencjach.
Więcej informacji o typach wiadomości znajdziesz w artykule Powiadomienia i wiadomości z danymi.

Edytuj plik manifestu aplikacji

Aby używać funkcji FirebaseMessagingService, musisz dodać do pliku manifestu aplikacji te dane:

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

Zalecamy też ustawienie wartości domyślnych w celu dostosowania wyglądu powiadomień. Możesz określić niestandardową ikonę domyślną i niestandardowy kolor domyślny, które będą stosowane zawsze, gdy w ładunku powiadomień nie ustawiono równoważnych wartości.

Aby ustawić niestandardową ikonę domyślną i kolor niestandardowy, dodaj te wiersze w tagu application:

<!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
     See README(https://goo.gl/l4GJaQ) for more. -->
<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. See README(https://goo.gl/6BKBk7) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/colorAccent" />

Android wyświetla niestandardową ikonę domyślną

  • Wszystkie wiadomości z powiadomieniami wysłane z narzędzia do tworzenia powiadomień.
  • Wszystkie wiadomości z powiadomieniami, w których nie ustawiono konkretnej ikony w ładunku powiadomienia.

Android używa niestandardowego koloru domyślnego dla

  • Wszystkie wiadomości z powiadomieniami wysłane z narzędzia do tworzenia powiadomień.
  • Wszystkie wiadomości z powiadomieniami, które nie określają jawnie koloru w ładunku powiadomienia.

Jeśli nie ustawiono niestandardowej ikony domyślnej, a w ładunku powiadomienia nie ustawiono żadnej ikony, Android wyświetla ikonę aplikacji wyrenderowaną na biało.

Zastąp onMessageReceived

Zastąpąc metodę FirebaseMessagingService.onMessageReceived, możesz wykonywać działania na podstawie otrzymanego obiektu RemoteMessage i uzyskiwać dane wiadomości:

Kotlin+KTX

override fun onMessageReceived(remoteMessage: RemoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
    Log.d(TAG, "From: ${remoteMessage.from}")

    // Check if message contains a data payload.
    if (remoteMessage.data.isNotEmpty()) {
        Log.d(TAG, "Message data payload: ${remoteMessage.data}")

        // Check if data needs to be processed by long running job
        if (needsToBeScheduled()) {
            // 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.
    remoteMessage.notification?.let {
        Log.d(TAG, "Message Notification Body: ${it.body}")
    }

    // Also if you intend on generating your own notifications as a result of a received FCM
    // message, here is where that should be initiated. See sendNotification method below.
}

Java

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
    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());
    }

    // Also if you intend on generating your own notifications as a result of a received FCM
    // message, here is where that should be initiated. See sendNotification method below.
}

Zastąp onDeletedMessages

W niektórych sytuacjach FCM może nie dostarczyć wiadomości. Dzieje się tak, gdy w momencie nawiązania połączenia lub gdy urządzenie nie połączyło się z FCM przez ponad miesiąc, na urządzeniu, w którym w momencie nawiązania połączenia jest zbyt wiele (ponad 100) oczekujących wiadomości. W takich przypadkach możesz otrzymać wywołanie zwrotne do FirebaseMessagingService.onDeletedMessages(). Gdy instancja aplikacji otrzyma to wywołanie zwrotne, powinna przeprowadzić pełną synchronizację z serwerem aplikacji. Jeśli w ciągu ostatnich 4 tygodni nie wyślesz wiadomości do aplikacji na danym urządzeniu, FCM nie zadzwoni pod numer onDeletedMessages().

Obsługa powiadomień z aplikacji w tle

Gdy aplikacja działa w tle, Android przekierowuje powiadomienia do obszaru powiadomień. Kliknięcie powiadomienia domyślnie otwiera menu z aplikacjami.

Obejmuje to wiadomości zawierające zarówno powiadomienia, jak i ładunek danych (oraz wszystkie wiadomości wysłane z konsoli powiadomień). W takich przypadkach powiadomienie jest dostarczane do obszaru powiadomień urządzenia, a ładunek danych jest dostarczany z dodatkami do intencji aktywności programu uruchamiającego.

Informacje o dostarczeniu wiadomości do aplikacji znajdziesz w panelu raportowania FCM, który zawiera liczbę wysłanych i otwartych wiadomości na urządzeniach Apple i z Androidem, a także dane o „wyświetleniach” (powiadomieniach widocznych dla użytkowników) w aplikacjach na Androida.

Tworzenie żądań wysyłania

Po utworzeniu tematu (przez zasubskrybowanie instancji aplikacji klienckich do tematu po stronie klienta lub za pomocą interfejsu API serwera) możesz wysyłać wiadomości do tego tematu. Jeśli po raz pierwszy tworzysz żądania wysyłania żądań w FCM, przeczytaj przewodnik na temat środowiska serwera i FCM, w którym znajdziesz ważne informacje o konfiguracji i konfiguracji.

W logice wysyłania w backendzie określ żądaną nazwę tematu w następujący sposób:

Node.js

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

const message = {
  data: {
    score: '850',
    time: '2:45'
  },
  topic: topic
};

// Send a message to devices subscribed to the provided topic.
getMessaging().send(message)
  .then((response) => {
    // Response is a message ID string.
    console.log('Successfully sent message:', response);
  })
  .catch((error) => {
    console.log('Error sending message:', error);
  });

Java

// 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);

Python

# The topic name can be optionally prefixed with "/topics/".
topic = 'highScores'

# See documentation on defining a message payload.
message = messaging.Message(
    data={
        'score': '850',
        'time': '2:45',
    },
    topic=topic,
)

# Send a message to the devices subscribed to the provided topic.
response = messaging.send(message)
# Response is a message ID string.
print('Successfully sent message:', response)

Go

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

// See documentation on defining a message payload.
message := &messaging.Message{
	Data: map[string]string{
		"score": "850",
		"time":  "2:45",
	},
	Topic: topic,
}

// Send a message to the devices subscribed to the provided topic.
response, err := client.Send(ctx, message)
if err != nil {
	log.Fatalln(err)
}
// Response is a message ID string.
fmt.Println("Successfully sent message:", response)

C#

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

// See documentation on defining a message payload.
var message = new Message()
{
    Data = new Dictionary<string, string>()
    {
        { "score", "850" },
        { "time", "2:45" },
    },
    Topic = topic,
};

// Send a message to the devices subscribed to the provided topic.
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
// Response is a message ID string.
Console.WriteLine("Successfully sent message: " + response);

REST

POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1

Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA
{
  "message":{
    "topic" : "foo-bar",
    "notification" : {
      "body" : "This is a Firebase Cloud Messaging Topic Message!",
      "title" : "FCM Message"
      }
   }
}

Polecenie cURL:

curl -X POST -H "Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA" -H "Content-Type: application/json" -d '{
  "message": {
    "topic" : "foo-bar",
    "notification": {
      "body": "This is a Firebase Cloud Messaging Topic Message!",
      "title": "FCM Message"
    }
  }
}' https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1

Aby wysłać wiadomość do kombinacji tematów, określ warunek – wyrażenie logiczne określające tematy docelowe. Na przykład ten warunek spowoduje wysłanie wiadomości do urządzeń, które subskrybują TopicA i TopicB lub TopicC:

"'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)"

FCM najpierw ocenia warunki w nawiasach, a potem ocenia wyrażenie z kolei od lewej do prawej. W powyższym wyrażeniu użytkownik zasubskrybował dowolny temat, ale nie otrzyma tej wiadomości. Analogicznie użytkownik, który nie subskrybuje TopicA, nie otrzyma wiadomości. Dane go otrzymują:

  • TopicATopicB
  • TopicATopicC

W wyrażeniu warunkowym możesz uwzględnić maksymalnie 5 tematów.

Aby wysłać wiadomość do warunku:

Node.js

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
const condition = '\'stock-GOOG\' in topics || \'industry-tech\' in topics';

// See documentation on defining a message payload.
const message = {
  notification: {
    title: '$FooCorp up 1.43% on the day',
    body: '$FooCorp gained 11.80 points to close at 835.67, up 1.43% on the day.'
  },
  condition: condition
};

// Send a message to devices subscribed to the combination of topics
// specified by the provided condition.
getMessaging().send(message)
  .then((response) => {
    // Response is a message ID string.
    console.log('Successfully sent message:', response);
  })
  .catch((error) => {
    console.log('Error sending message:', error);
  });

Java

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
String condition = "'stock-GOOG' in topics || 'industry-tech' in topics";

// See documentation on defining a message payload.
Message message = Message.builder()
    .setNotification(Notification.builder()
        .setTitle("$GOOG up 1.43% on the day")
        .setBody("$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.")
        .build())
    .setCondition(condition)
    .build();

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

Python

# Define a condition which will send to devices which are subscribed
# to either the Google stock or the tech industry topics.
condition = "'stock-GOOG' in topics || 'industry-tech' in topics"

# See documentation on defining a message payload.
message = messaging.Message(
    notification=messaging.Notification(
        title='$GOOG up 1.43% on the day',
        body='$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.',
    ),
    condition=condition,
)

# Send a message to devices subscribed to the combination of topics
# specified by the provided condition.
response = messaging.send(message)
# Response is a message ID string.
print('Successfully sent message:', response)

Go

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
condition := "'stock-GOOG' in topics || 'industry-tech' in topics"

// See documentation on defining a message payload.
message := &messaging.Message{
	Data: map[string]string{
		"score": "850",
		"time":  "2:45",
	},
	Condition: condition,
}

// Send a message to devices subscribed to the combination of topics
// specified by the provided condition.
response, err := client.Send(ctx, message)
if err != nil {
	log.Fatalln(err)
}
// Response is a message ID string.
fmt.Println("Successfully sent message:", response)

C#

// Define a condition which will send to devices which are subscribed
// to either the Google stock or the tech industry topics.
var condition = "'stock-GOOG' in topics || 'industry-tech' in topics";

// See documentation on defining a message payload.
var message = new Message()
{
    Notification = new Notification()
    {
        Title = "$GOOG up 1.43% on the day",
        Body = "$GOOG gained 11.80 points to close at 835.67, up 1.43% on the day.",
    },
    Condition = condition,
};

// Send a message to devices subscribed to the combination of topics
// specified by the provided condition.
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
// Response is a message ID string.
Console.WriteLine("Successfully sent message: " + response);

REST

POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1

Content-Type: application/json
Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA
{
   "message":{
    "condition": "'dogs' in topics || 'cats' in topics",
    "notification" : {
      "body" : "This is a Firebase Cloud Messaging Topic Message!",
      "title" : "FCM Message",
    }
  }
}

Polecenie cURL:

curl -X POST -H "Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA" -H "Content-Type: application/json" -d '{
  "notification": {
    "title": "FCM Message",
    "body": "This is a Firebase Cloud Messaging Topic Message!",
  },
  "condition": "'dogs' in topics || 'cats' in topics"
}' https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send HTTP/1.1

Dalsze kroki