Отправляйте сообщения на несколько устройств на платформах Apple.

Чтобы нацелить сообщение на несколько устройств, используйте функцию «Тема сообщений» . Эта функция позволяет отправлять сообщение на несколько устройств, которые подписались на определенную тему.

В этом руководстве основное внимание уделяется отправке тематических сообщений с вашего сервера приложений с помощью Admin SDK или REST API для FCM , а также их получению и обработке в приложении Apple. На этой странице перечислены все шаги для достижения этого, от настройки до проверки — поэтому она может охватывать шаги, которые вы уже выполнили, если вы настроили клиентское приложение Apple для FCM или прошли шаги для отправки вашего первого сообщения .

Добавьте Firebase в свой проект Apple

В этом разделе рассматриваются задачи, которые вы могли выполнить, если вы уже включили другие функции Firebase для своего приложения. Для FCM вам нужно будет загрузить свой ключ аутентификации APNs и зарегистрироваться для удаленных уведомлений .

Предпосылки

  • Установите следующее:

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

    • Ваш проект должен быть ориентирован на эти или более поздние версии платформы:
      • iOS13
      • macOS 10.15
      • tvOS 13
      • watchOS 7
  • Настройте физическое устройство Apple для запуска вашего приложения и выполните следующие задачи:

Если у вас еще нет проекта Xcode и вы просто хотите опробовать продукт Firebase, вы можете загрузить один из наших примеров быстрого старта .

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

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

  1. В консоли Firebase нажмите Добавить проект .

    • Чтобы добавить ресурсы Firebase в существующий проект Google Cloud , введите имя проекта или выберите его из раскрывающегося меню.

    • Чтобы создать новый проект, введите имя проекта. Вы также можете изменить идентификатор проекта, отображаемый под именем проекта.

  2. При появлении соответствующего запроса ознакомьтесь с условиями Firebase и примите их.

  3. Нажмите «Продолжить» .

  4. (Необязательно) Настройте Google Analytics для своего проекта, что обеспечит оптимальную работу с использованием следующих продуктов Firebase: Firebase A/B Testing , Cloud Messaging , Crashlytics , In-App Messaging и Remote Config (включая Personalization ).

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

  5. Нажмите «Создать проект» (или «Добавить Firebase» , если вы добавляете Firebase в существующий проект Google Cloud ).

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

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

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

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

  2. В центре страницы обзора проекта щелкните значок iOS+, чтобы запустить рабочий процесс настройки.

    Если вы уже добавили приложение в свой проект Firebase, нажмите «Добавить приложение» , чтобы отобразить параметры платформы.

  3. Введите идентификатор пакета вашего приложения в поле идентификатора пакета .

    • Идентификатор пакета однозначно идентифицирует приложение в экосистеме Apple.

    • Найдите идентификатор вашего пакета: откройте свой проект в Xcode, выберите приложение верхнего уровня в навигаторе проектов, затем выберите вкладку «Общие» .

      Значение поля «Идентификатор пакета» — это идентификатор пакета (например, com.yourcompany.yourproject ).

    • Имейте в виду, что значение идентификатора пакета чувствительно к регистру и его нельзя изменить для этого приложения Firebase после его регистрации в вашем проекте Firebase.

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

  5. Нажмите «Зарегистрировать приложение» .

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

  1. Нажмите «Загрузить GoogleService-Info.plist» , чтобы получить файл конфигурации платформ Firebase Apple ( GoogleService-Info.plist ).

    • Файл конфигурации Firebase содержит уникальные, но не секретные идентификаторы для вашего проекта. Чтобы узнать больше об этом файле конфигурации, посетите Understand Firebase Projects .

    • Вы можете повторно загрузить файл конфигурации Firebase в любое время.

    • Убедитесь, что имя файла конфигурации не дополнено дополнительными символами, например (2) .

  2. Переместите ваш файл конфигурации в корень вашего проекта Xcode. Если будет предложено, выберите добавление файла конфигурации ко всем целям.

Если в вашем проекте несколько идентификаторов пакетов, необходимо связать каждый идентификатор пакета с зарегистрированным приложением в консоли Firebase , чтобы каждое приложение могло иметь свой собственный файл GoogleService-Info.plist .

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

Используйте Swift Package Manager для установки и управления зависимостями Firebase.

  1. В Xcode откройте проект приложения и перейдите в меню Файл > Добавить пакеты .
  2. При появлении соответствующего запроса добавьте репозиторий Firebase Apple platform SDK:
  3.   https://github.com/firebase/firebase-ios-sdk.git
  4. Выберите библиотеку Firebase Cloud Messaging .
  5. Добавьте флаг -ObjC в раздел «Другие флаги компоновщика» настроек сборки вашей цели.
  6. Для оптимального опыта работы с Firebase Cloud Messaging мы рекомендуем включить Google Analytics в вашем проекте Firebase и добавить Firebase SDK для Google Analytics в ваше приложение. Вы можете выбрать либо библиотеку без сбора IDFA, либо с сбором IDFA. Ознакомьтесь с нашими часто задаваемыми вопросами о последней организации модулей в Google Analytics для Firebase SDK .
  7. По завершении Xcode автоматически начнет разрешать и загружать ваши зависимости в фоновом режиме.

Загрузите свой ключ аутентификации APNs

Загрузите свой ключ аутентификации APNs в Firebase. Если у вас еще нет ключа аутентификации APNs, обязательно создайте его в Apple Developer Member Center .

  1. Внутри вашего проекта в консоли Firebase выберите значок шестеренки, выберите Параметры проекта , а затем выберите вкладку Облачные сообщения .

  2. В разделе «Ключ аутентификации APNs» в разделе «Конфигурация приложения iOS» нажмите кнопку «Загрузить» .

  3. Перейдите к месту, где вы сохранили свой ключ, выберите его и нажмите «Открыть» . Добавьте идентификатор ключа (доступен в Apple Developer Member Center ) и нажмите «Загрузить» .

Инициализируйте Firebase в вашем приложении

Вам нужно будет добавить код инициализации Firebase в ваше приложение. Импортируйте модуль Firebase и настройте общий экземпляр, как показано:

  1. Импортируйте модуль FirebaseCore в ваш UIApplicationDelegate , а также любые другие модули Firebase, которые использует ваш делегат приложения. Например, чтобы использовать Cloud Firestore и Authentication :
    import SwiftUI
    import FirebaseCore
    import FirebaseFirestore
    import FirebaseAuth
    // ...
          
    import FirebaseCore
    import FirebaseFirestore
    import FirebaseAuth
    // ...
          
    @import FirebaseCore;
    @import FirebaseFirestore;
    @import FirebaseAuth;
    // ...
          
  2. Настройте общий экземпляр FirebaseApp в методе делегата приложения application application(_:didFinishLaunchingWithOptions:) :
    // Use Firebase library to configure APIs
    FirebaseApp.configure()
    // Use Firebase library to configure APIs
    FirebaseApp.configure()
    // Use Firebase library to configure APIs
    [FIRApp configure];
  3. Если вы используете SwiftUI, вы должны создать делегат приложения и прикрепить его к структуре App через UIApplicationDelegateAdaptor или NSApplicationDelegateAdaptor . Вы также должны отключить swizzling делегата приложения. Для получения дополнительной информации см. инструкции SwiftUI .
    SwiftUI
    @main
    struct YourApp: App {
      // register app delegate for Firebase setup
      @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    
      var body: some Scene {
        WindowGroup {
          NavigationView {
            ContentView()
          }
        }
      }
    }
          

Зарегистрируйтесь для получения удаленных уведомлений

Либо при запуске, либо в желаемой точке потока вашего приложения зарегистрируйте свое приложение для удаленных уведомлений. Вызовите registerForRemoteNotifications , как показано:
UNUserNotificationCenter.current().delegate = self

let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
  options: authOptions,
  completionHandler: { _, _ in }
)

application.registerForRemoteNotifications()
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert |
    UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
[[UNUserNotificationCenter currentNotificationCenter]
    requestAuthorizationWithOptions:authOptions
    completionHandler:^(BOOL granted, NSError * _Nullable error) {
      // ...
    }];

[application registerForRemoteNotifications];

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

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

Чтобы подписаться на тему, вызовите метод подписки из основного потока вашего приложения ( FCM не является потокобезопасным). Если запрос на подписку изначально не удается, FCM автоматически повторяет попытку. В случаях, когда подписка не может быть завершена, подписка выдает ошибку, которую можно перехватить в обработчике завершения, как показано ниже:

Messaging.messaging().subscribe(toTopic: "weather") { error in
  print("Subscribed to weather topic")
}
[[FIRMessaging messaging] subscribeToTopic:@"weather"
                                completion:^(NSError * _Nullable error) {
  NSLog(@"Subscribed to weather topic");
}];

Этот вызов делает асинхронный запрос к бэкэнду FCM и подписывает клиента на заданную тему. Перед вызовом subscribeToTopic:topic убедитесь, что экземпляр клиентского приложения уже получил регистрационный токен через обратный вызов didReceiveRegistrationToken .

При каждом запуске приложения FCM проверяет, что все запрошенные темы подписаны. Чтобы отписаться, вызовите unsubscribeFromTopic:topic , и FCM отпишется от темы в фоновом режиме.

Получать и обрабатывать тематические сообщения

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

Реализуйте application(_:didReceiveRemoteNotification:fetchCompletionHandler:) , как показано:

func application(_ application: UIApplication,
                 didReceiveRemoteNotification userInfo: [AnyHashable: Any]) async
  -> UIBackgroundFetchResult {
  // If you are receiving a notification message while your app is in the background,
  // this callback will not be fired till the user taps on the notification launching the application.
  // TODO: Handle data of notification

  // With swizzling disabled you must let Messaging know about the message, for Analytics
  // Messaging.messaging().appDidReceiveMessage(userInfo)

  // Print message ID.
  if let messageID = userInfo[gcmMessageIDKey] {
    print("Message ID: \(messageID)")
  }

  // Print full message.
  print(userInfo)

  return UIBackgroundFetchResult.newData
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
    fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  // If you are receiving a notification message while your app is in the background,
  // this callback will not be fired till the user taps on the notification launching the application.
  // TODO: Handle data of notification

  // With swizzling disabled you must let Messaging know about the message, for Analytics
  // [[FIRMessaging messaging] appDidReceiveMessage:userInfo];

  // ...

  // Print full message.
  NSLog(@"%@", userInfo);

  completionHandler(UIBackgroundFetchResultNewData);
}

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

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

В логике отправки на бэкэнде укажите желаемое название темы, как показано ниже:

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

Команда 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

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

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

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

  • TopicA и TopicB
  • TopicA и TopicC

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

Чтобы отправить в состояние:

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

Команда 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

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