Отправлять сообщения на несколько устройств

Firebase Cloud Messaging предоставляет два способа нацеливания сообщения на несколько устройств:

  • Тема сообщений , которая позволяет отправлять сообщения нескольким устройствам, включивших к определенной теме.
  • Группа сообщений устройств , которая позволяет отправить сообщение нескольким устройствам , которые принадлежат к группе вы определили.

Этот учебник посвящен отправке тему сообщения с вашего сервера приложений с помощью Admin SDK или REST API для FCM и приема и обработки их в приложение для Android. Мы рассмотрим обработку сообщений как для фоновых, так и для приоритетных приложений. Охвачены все шаги для достижения этого, от настройки до проверки.

Настройте SDK

Этот раздел может охватывать действия , которые уже завершены , если вы создали приложение для Android клиента для ТСМА или работали через шаги , чтобы Переслать свое первое сообщение .

Прежде чем вы начнете

  • Установить или обновить Android Studio до последней версии.

  • Убедитесь, что ваш проект соответствует следующим требованиям:

    • Ориентирован на уровень API 19 (KitKat) или выше.
    • Использует Android 4.4 или выше
    • Использует Jetpack (AndroidX) , которая включает в себя выполнение этих требований версии:
      • com.android.tools.build:gradle v3.2.1 или более поздняя версия
      • compileSdkVersion 28 или более поздней версии
  • Настройка физического устройства или использовать эмулятор для запуска приложения.
    Обратите внимание , что Firebase SDKs с зависимостью от услуг в Google Play требуется устройство или эмулятор , чтобы службы Google Play установлена.

  • Войдите в Firebase , используя учетную запись Google.

Если вы уже не имеете Android проекта и просто хотите попробовать Firebase продукт, вы можете скачать один из наших образцов быстрой настройки .

Создайте проект Firebase

Прежде чем вы сможете добавить Firebase в свое Android-приложение, вам необходимо создать проект Firebase для подключения к вашему Android-приложению. Визит Понимать Firebase Проекты более узнать о проектах Firebase.

Зарегистрируйте свое приложение в Firebase

Чтобы использовать Firebase в своем приложении для Android, вам необходимо зарегистрировать свое приложение в проекте Firebase. Регистрация вашего приложения часто называется «добавлением» вашего приложения в ваш проект.

  1. Перейти к консоли Firebase .

  2. В центре главной страницы проекта, нажмите значок Android ( ) или добавить приложение , чтобы запустить рабочий процесс установки.

  3. Введите название пакета приложения в поле Android имени пакета.

  4. (Необязательно) Введите другую информацию приложение: App ник и подпись Debug сертификат SHA-1.

  5. Выберите Зарегистрировать приложение.

Добавьте файл конфигурации Firebase

  1. Добавьте файл конфигурации Firebase Android в свое приложение:

    1. Нажмите Загрузить Google-services.json , чтобы получить файл конфигурации Firebase Android ( google-services.json ).

    2. Переместите файл конфигурации в каталог модуля (уровня приложения) вашего приложения.

  2. Чтобы включить продукты Firebase в вашем приложении, добавьте Google-сервисы плагин для ваших Gradle файлов.

    1. В корневом уровне ( на уровне проекта) Gradle файл ( build.gradle ), добавить правила , чтобы включить плагин Google Services Gradle. Убедитесь, что у вас также есть репозиторий Google Maven.

      buildscript {
      
        repositories {
          // Check that you have the following line (if not, add it):
          google()  // Google's Maven repository
        }
      
        dependencies {
          // ...
      
          // Add the following line:
          classpath 'com.google.gms:google-services:4.3.10'  // Google Services plugin
        }
      }
      
      allprojects {
        // ...
      
        repositories {
          // Check that you have the following line (if not, add it):
          google()  // Google's Maven repository
          // ...
        }
      }
      
    2. В вашем модуле (приложение уровня) Gradle файл (обычно app/build.gradle ), применять плагин Google Services Gradle:

      apply plugin: 'com.android.application'
      // Add the following line:
      apply plugin: 'com.google.gms.google-services'  // Google Services plugin
      
      android {
        // ...
      }
      

Добавьте Firebase SDK в свое приложение

  1. Использование Firebase Android Банка Москвы , объявить зависимость для библиотеки Firebase Cloud Messaging Android в вашем модуле (приложение уровня) Gradle файл (обычно app/build.gradle ).

    Для оптимальной работы с Firebase Cloud Messaging, мы рекомендуем позволяет Google Analytics в проекте Firebase и добавление Firebase SDK для Google Analytics для вашего приложения.

    Ява

    dependencies {
        // Import the BoM for the Firebase platform
        implementation platform('com.google.firebase:firebase-bom:29.0.4')
    
        // Declare 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'
    }
    

    С помощью Firebase Android Банка Москвы , ваше приложение будет всегда использовать совместимые версии библиотек Firebase Android.

    (Альтернативный) Объявляет Firebase библиотеки зависимостей без использования спецификации

    Если вы решите не использовать Firebase BoM, вы должны указать каждую версию библиотеки Firebase в строке зависимостей.

    Обратите внимание , что если вы используете несколько библиотеки Firebase в вашем приложении, мы настоятельно рекомендуем использовать спецификации для управления версиями библиотеки, что гарантирует , что все версии совместимы.

    dependencies {
        // Declare 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:23.0.0'
        implementation 'com.google.firebase:firebase-analytics:20.0.2'
    }
    

    Котлин+КТХ

    dependencies {
        // Import the BoM for the Firebase platform
        implementation platform('com.google.firebase:firebase-bom:29.0.4')
    
        // Declare 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-ktx'
        implementation 'com.google.firebase:firebase-analytics-ktx'
    }
    

    С помощью Firebase Android Банка Москвы , ваше приложение будет всегда использовать совместимые версии библиотек Firebase Android.

    (Альтернативный) Объявляет Firebase библиотеки зависимостей без использования спецификации

    Если вы решите не использовать Firebase BoM, вы должны указать каждую версию библиотеки Firebase в строке зависимостей.

    Обратите внимание , что если вы используете несколько библиотеки Firebase в вашем приложении, мы настоятельно рекомендуем использовать спецификации для управления версиями библиотеки, что гарантирует , что все версии совместимы.

    dependencies {
        // Declare 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-ktx:23.0.0'
        implementation 'com.google.firebase:firebase-analytics-ktx:20.0.2'
    }
    

  2. Синхронизируйте свое приложение, чтобы убедиться, что все зависимости имеют необходимые версии.

Подпишите клиентское приложение на тему

Клиентские приложения могут подписаться на любую существующую тему или создать новую тему. Когда клиентское приложение подписывается на новую тему (которая еще не существует для вашего проекта Firebase), в FCM создается новая тема с таким именем, и впоследствии любой клиент может подписаться на нее.

Чтобы подписаться на тему, клиентское приложение вызывает Firebase Cloud Messaging subscribeToTopic() с именем FCM тему. Этот метод возвращает Task , которая может быть использована для заканчивания слушателя , чтобы определить , удалось ли подписка:

Ява

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

Котлин+КТХ

Firebase.messaging.subscribeToTopic("weather")
        .addOnCompleteListener { task ->
            var msg = getString(R.string.msg_subscribed)
            if (!task.isSuccessful) {
                msg = getString(R.string.msg_subscribe_failed)
            }
            Log.d(TAG, msg)
            Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
        }

Чтобы отказаться от подписки, клиентское приложение вызывает Firebase Cloud Messaging unsubscribeFromTopic() с именем темы.

Получение и обработка тематических сообщений

FCM доставляет тематические сообщения так же, как и другие нижестоящие сообщения.

Для получения сообщений, используйте сервис , который расширяет FirebaseMessagingService . Ваша служба должна переопределить onMessageReceived и onDeletedMessages обратных вызовов. Он должен обрабатывать любое сообщение в течение 20 секунд после получения (10 секунд на Android Marshmallow). Время может быть короче , в зависимости от задержек ОС понесены перед призванием onMessageReceived . После этого, различные формы поведения , такие как OS Android Выходов пределы исполнения фон может мешать вашей способности завершить свою работу. Для получения дополнительной информации посетите наш обзор приоритет сообщений .

onMessageReceived предназначен для большинства типов сообщений, со следующими исключениями:

  • Сообщения уведомления доставлены , когда приложение работает в фоновом режиме. В этом случае уведомление доставляется в системный трей устройства. Пользователь, нажимающий на уведомление, по умолчанию открывает панель запуска приложений.

  • Сообщения как с уведомлением и полезной нагрузкой данных, когда полученные в фоновом режиме. В этом случае уведомление доставляется в системный трей устройства, а полезная нагрузка данных доставляется в дополнение к намерению вашей активности запуска.

В итоге:

Состояние приложения Уведомление Данные Оба
Передний план onMessageReceived onMessageReceived onMessageReceived
Задний план Системный трей onMessageReceived Уведомление: системный трей
Данные: в статистах умысла.
Для получения дополнительной информации о типах сообщений см Уведомления и данных сообщений .

Изменить манифест приложения

Для использования FirebaseMessagingService , необходимо добавить следующее в вашем приложении манифеста:

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

Кроме того, рекомендуется установить значения по умолчанию, чтобы настроить внешний вид уведомлений. Вы можете указать настраиваемый значок по умолчанию и настраиваемый цвет по умолчанию, которые применяются всякий раз, когда эквивалентные значения не установлены в полезной нагрузке уведомления.

Добавьте эти строки внутри 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 отображает пользовательский значок по умолчанию для

  • Все сообщения уведомления , отправленные с композитором Notifications .
  • Любое сообщение уведомления, которое явно не устанавливает значок в полезной нагрузке уведомления.

Android использует пользовательский цвет по умолчанию для

  • Все сообщения уведомления , отправленные с композитором Notifications .
  • Любое сообщение уведомления, в котором явно не задан цвет полезных данных уведомления.

Если не задан пользовательский значок по умолчанию и не задан значок в полезной нагрузке уведомления, Android отображает значок приложения, окрашенный в белый цвет.

Override onMessageReceived

Переопределелив метод FirebaseMessagingService.onMessageReceived , вы можете выполнять действия на основании полученного RemoteMessage объект и получить данные сообщения:

Ява

@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.
}

Котлин+КТХ

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}")

        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.
    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.
}

Override onDeletedMessages

В некоторых ситуациях FCM может не доставить сообщение. Это происходит, когда слишком много сообщений (> 100) ожидают вашего приложения на определенном устройстве во время его подключения или если устройство не подключалось к FCM более одного месяца. В этих случаях, вы можете получить обратный вызов FirebaseMessagingService.onDeletedMessages() Когда экземпляр приложения получает этот обратный вызов, он должен выполнить полную синхронизацию с сервером приложений. Если вы не отправили сообщение в приложение на этом устройстве в течение последних 4 недель, FCM не будет вызывать onDeletedMessages() .

Обработка уведомлений в фоновом приложении

Когда ваше приложение работает в фоновом режиме, Android направляет уведомления на панель задач. Пользователь, нажав на уведомление, по умолчанию открывает панель запуска приложений.

Сюда входят сообщения, содержащие как уведомления, так и полезные данные (и все сообщения, отправленные из консоли уведомлений). В этих случаях уведомление доставляется в системный трей устройства, а полезная нагрузка данных доставляется в дополнительных целях вашего действия запуска.

Для понимания доставки сообщений в вашем приложении, см FCM отчетности приборной панели , которая записывает количество отправленных сообщений и открыл на устройствах Apple , и Android, а также с данными для «впечатлений» (уведомления , замеченные пользователями) для Android приложений.

Фоновые приложения с ограниченным доступом (Android P или новее)

FCM не может доставить сообщения приложения , которые были введены в ограничение фона пользователем (например, с помощью: Настройка -> Приложения и уведомления -> [имя_приложения] -> Аккумулятор). Как только ваше приложение будет снято с фонового ограничения, новые сообщения в приложение будут доставляться, как и раньше. Для предотвращения потери сообщений и других последствий ограничения фона, убедитесь , чтобы избежать плохого поведения , перечисленное в Android Vitals усилий. Такое поведение может привести к тому, что устройство Android порекомендует пользователю ограничить доступ вашего приложения в фоновом режиме. Ваше приложение может проверить , если это фон ограничено использованием: isBackgroundRestricted () .

Создание запросов на отправку

После того, как вы создали тему, либо подписавшись экземплярами приложения клиента к теме на стороне клиента или через сервер API , вы можете отправлять сообщения в эту тему. Если это ваш первый раз строит запросы посыла для ТСМ, смотрите руководство к серверной среде и ТСМ для получения важной информации фона и настройки.

В логике отправки на серверной части укажите желаемое имя темы, как показано ниже:

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

Ява

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

Питон

# 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)

Идти

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

С#

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

ОТДЫХ

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"
      }
   }
}

URL-команда:

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

Для того, чтобы отправить сообщение на комбинацию тем, указать условие, которое является логическим выражением , которое определяет целевые темы. Например, следующее условие будет посылать сообщения на устройства, которые подписались на TopicA и либо TopicB или TopicC :

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

FCM сначала оценивает любые условия в круглых скобках, а затем вычисляет выражение слева направо. В приведенном выше выражении пользователь, подписанный на какую-либо отдельную тему, не получает сообщение. Кроме того, пользователь , который не подписаться на TopicA не получает сообщение. Эти комбинации действительно получают его:

  • TopicA и TopicB
  • TopicA и TopicC

В условное выражение можно включить до пяти тем.

Для отправки в состояние:

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

Ява

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

Питон

# 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)

Идти

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

С#

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

ОТДЫХ

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",
    }
  }
}

URL-команда:

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

Следующие шаги