Руководство. Отправка push-уведомлений в приложения React Native с помощью Центров уведомлений Azure через серверную службу

Скачать пример Скачивание примера

В этом руководстве вы используете Центры уведомлений Azure для отправки push-уведомлений в приложение React Native, предназначенное для Android и iOS.

Серверная часть веб-API ASP.NET Core используется для обработки регистрации устройств для клиента с использованием последнего и наилучшего подхода к установке. Служба также будет отправлять push-уведомления кроссплатформенным способом.

Эти операции обрабатываются с помощью пакета SDK центров уведомлений для внутренних операций. Дополнительные сведения об общем подходе приведены в документации по регистрации из серверной части приложения .

В этом руководстве описаны следующие действия.

Предварительные требования

Для этого вам потребуется:

  • Подписка Azure, в которой можно создавать ресурсы и управлять ими.
  • Компьютер Mac с установленной Visual Studio для Mac (или компьютер под управлением Visual Studio 2019 с рабочей нагрузкой Разработка мобильных приложений с помощью .NET).
  • Возможность запуска приложения на устройствах Android (физические устройства или устройства эмулятора) или iOS (только на физических устройствах).

Для Android необходимо иметь:

  • Разработчик разблокировал физическое устройство или эмулятор (с API 26 и более поздних версий с установленными службами Google Play).

Для iOS необходимо:

Примечание

Симулятор iOS не поддерживает удаленные уведомления, поэтому при изучении этого примера на iOS требуется физическое устройство. Однако для работы с этим руководством вам не нужно запускать приложение на устройствах Android и iOS .

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

Указанные действия предназначены для Visual Studio для Mac и Visual Studio Code однако их можно выполнить с помощью Visual Studio 2019.

Настройка служб push-уведомлений и Центра уведомлений Azure

В этом разделе описана настройка Firebase Cloud Messaging (FCM) и служб push-уведомлений Apple (APNS). Затем вы создадите и настроите центр уведомлений для работы с этими службами.

Создание проекта Firebase и включение Firebase Cloud Messaging для Android

  1. Войдите в консоль Firebase. Создайте проект Firebase, указав PushDemo в качестве имени проекта.

    Примечание

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

  2. После создания проекта выберите Добавить Firebase в приложение Android.

    Добавление Firebase в приложение Android

  3. На странице Добавление Firebase в приложение Android выполните следующие действия.

    1. В поле Имя пакета Android введите имя пакета. Например: com.<organization_identifier>.<package_name>.

      Указание имени пакета

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

    3. Выберите Скачать google-services.json. Затем сохраните файл в локальную папку для последующего использования и нажмите кнопку Далее.

      Скачать google-services.json

    4. Нажмите кнопку Далее.

    5. Выберите Continue to console (Продолжить в консоль).

      Примечание

      Если кнопка Продолжить в консоли не включена из-за проверка проверки установки, выберите Пропустить этот шаг.

  4. В консоли Firebase выберите шестеренку для проекта. Затем выберите Параметры проекта.

    Выбор параметров проекта

    Примечание

    Если вы еще не скачали файл google-services.json , его можно скачать на этой странице.

  5. Перейдите на вкладку Cloud Messaging вверху. Скопируйте и сохраните ключ сервера для последующего использования. Это значение используется для настройки центра уведомлений.

    Копирование ключа сервера

Регистрация приложения iOS для push-уведомлений

Чтобы отправлять push-уведомления в приложение iOS, зарегистрируйте приложение в Apple, а также зарегистрируйтесь для получения push-уведомлений.

  1. Если вы еще не зарегистрировали приложение, перейдите на портал подготовки iOS в Центре разработчиков Apple. Войдите на портал с помощью идентификатора Apple ID, перейдите в раздел Сертификаты, идентификаторы & Профили, а затем выберите Идентификаторы. Щелкните + , чтобы зарегистрировать новое приложение.

    Страница идентификаторов приложений портала подготовки iOS

  2. На экране Регистрация нового идентификатора выберите переключатель Идентификаторы приложений . Затем нажмите кнопку Продолжить.

    Страница регистрации нового идентификатора на портале подготовки iOS

  3. Обновите следующие три значения для нового приложения, а затем нажмите кнопку Продолжить:

    • Описание. Введите описательное имя приложения.

    • Идентификатор пакета. Введите идентификатор пакета в форме com.organization_identifier<>.<>product_name, как указано в руководстве по распространению приложений. На следующем снимке экрана значение используется в качестве идентификатора организации, mobcat а значение PushDemo — в качестве имени продукта.

      Страница регистрации идентификатора приложения на портале подготовки iOS

    • Push-уведомления. Установите флажок Push-уведомления в разделе Возможности .

      Форма для регистрации нового идентификатора приложения

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

      Подтверждение нового идентификатора приложения

      После нажатия кнопки Зарегистрировать вы увидите новый идентификатор приложения в виде элемента строки на странице Сертификаты, идентификаторы & Профили .

  4. На странице Сертификаты, идентификаторы & Профили в разделе Идентификаторы найдите созданный элемент строки идентификатора приложения. Затем выберите ее строку, чтобы отобразить экран Изменение конфигурации идентификатора приложения .

Создание сертификата для Центров уведомлений

Сертификат необходим, чтобы центр уведомлений мог работать со службами push-уведомлений Apple (APNS) и может быть предоставлен одним из двух способов:

  1. Создание сертификата push-уведомлений p12, который можно отправить непосредственно в центр уведомлений (исходный подход)

  2. Создание сертификата p8, который можно использовать для проверки подлинности на основе маркеров (более новый и рекомендуемый подход)

Новый подход имеет ряд преимуществ, описанных в статье Проверка подлинности на основе токенов (HTTP/2) для APNS. Требуется меньшее количество шагов, но также требуется для конкретных сценариев. Однако для обоих подходов предусмотрены шаги, так как любой из них будет работать для целей этого руководства.

ВАРИАНТ 1. Создание сертификата push-уведомлений p12, который можно отправить непосредственно в Центр уведомлений
  1. На компьютере Mac запустите средство keychain Access. Его можно открыть из папки Utilities или Other на панели запуска.

  2. Выберите Keychain Access (Доступ к цепочке ключей), разверните узел Помощник по сертификатам, а затем выберите Запросить сертификат из центра сертификации.

    Запрос нового сертификата с помощью доступа к цепочке ключей

    Примечание

    По умолчанию keychain Access выбирает первый элемент в списке. Это может быть проблемой, если вы находитесь в категории Сертификаты , а центр сертификации Apple Worldwide Developer Relations Не является первым элементом в списке. Перед созданием CSR (запрос на подпись сертификата) убедитесь, что у вас есть неключеловой элемент или выбран ключ центра сертификации Apple Worldwide Developer Relations.

  3. Выберите адрес Email пользователя, введите общее имя, убедитесь, что задано значение Сохранено на диске, а затем нажмите кнопку Продолжить. Оставьте адрес ЦС Email пустым, так как он не требуется.

    Ожидаемые сведения о сертификате

  4. Введите имя файла запроса на подпись сертификата (CSR) в поле Сохранить как, выберите расположение в поле Где, а затем нажмите кнопку Сохранить.

    Выбор имени файла для сертификата

    Это действие сохраняет CSR-файл в выбранном расположении. Расположение по умолчанию — Desktop. Запомните расположение, выбранное для файла.

  5. Вернитесь на страницу Сертификаты, идентификаторы & Профилина портале подготовки iOS, прокрутите вниз до флажка Push-уведомления и выберите Настроить , чтобы создать сертификат.

    Страница

  6. Откроется окно Tls/SSL-сертификаты службы push-уведомлений Apple . Нажмите кнопку Создать сертификат в разделе Разработка TLS/SSL-сертификата .

    Кнопка

    Отобразится экран Создание сертификата .

    Примечание

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

  7. Выберите Выбрать файл, перейдите в расположение, в котором вы сохранили CSR-файл, а затем дважды щелкните имя сертификата, чтобы загрузить его. Затем нажмите кнопку Продолжить.

  8. Когда портал создаст сертификат, нажмите кнопку Скачать . Сохраните сертификат и запомните расположение, в котором он сохранен.

    Страница скачивания созданного сертификата

    Сертификат скачается и сохраняется на компьютере в папке "Загрузки ".

    Найдите файл сертификата в папке

    Примечание

    По умолчанию скачанный сертификат разработки называется aps_development.cer.

  9. Дважды щелкните скачанный сертификат push-уведомлений aps_development.cer. Это действие устанавливает новый сертификат в цепочке ключей, как показано на следующем рисунке:

    Список сертификатов для доступа к цепочке ключей с новым сертификатом

    Примечание

    Хотя имя в сертификате может отличаться, оно будет иметь префикс с помощью push-служб Apple Development iOS и соответствующего идентификатора пакета.

  10. В разделе Доступ к + цепочке ключейщелкните новый сертификат push-уведомлений, созданный в категории Сертификаты. Выберите Экспорт, присвойте файлу имя, выберите формат p12 и нажмите кнопку Сохранить.

    Экспорт сертификата в формате p12

    Вы можете защитить сертификат паролем, но пароль является необязательным. Нажмите кнопку ОК , чтобы обойти создание пароля. Запишите имя файла и расположение экспортированного сертификата p12. Они используются для включения проверки подлинности с помощью APN.

    Примечание

    Имя и расположение файла p12 могут отличаться от указанных в этом руководстве.

ВАРИАНТ 2. Создание сертификата p8, который можно использовать для проверки подлинности на основе маркеров
  1. Запишите следующие сведения:

    • Префикс идентификатора приложения (идентификатор команды)
    • Идентификатор пакета
  2. Вернитесь в раздел Сертификаты, Идентификаторы & Профили и щелкните Ключи.

    Примечание

    Если у вас уже есть ключ, настроенный для APNS, можно повторно использовать сертификат p8, скачанный сразу после его создания. В этом случае можно игнорировать шаги 35.

  3. Нажмите кнопку + (или кнопку Создать клавишу ), чтобы создать новую клавишу.

  4. Укажите подходящее значение имени ключа, а затем проверка параметр Службы push-уведомлений Apple (APNS) и нажмите кнопку Продолжить, а затем зарегистрировать на следующем экране.

  5. Нажмите кнопку Скачать , а затем переместите p8-файл (с префиксом AuthKey_) в безопасный локальный каталог, а затем нажмите кнопку Готово.

    Примечание

    Не забудьте сохранить файл p8 в безопасном месте (и сохранить резервную копию). После скачивания ключа его невозможно скачать повторно, так как копия сервера удаляется.

  6. В разделе Ключи щелкните созданный ключ (или существующий ключ, если вы решили использовать его).

  7. Запишите значение идентификатора ключа .

  8. Откройте сертификат p8 в подходящем приложении, например Visual Studio Code. Запишите значение ключа (между -----BEGIN PRIVATE KEY----- и -----END PRIVATE KEY-----).

    закрытый ключ -----BEGIN-----
    <key_value>
    -----КОНЕЧНЫЙ ЗАКРЫТЫЙ КЛЮЧ-----

    Примечание

    Это значение маркера , которое будет использоваться позже для настройки центра уведомлений.

В конце этих действий у вас должны быть следующие сведения для последующего использования в разделе Настройка центра уведомлений с помощью сведений об APNS:

  • Идентификатор команды (см. шаг 1)
  • Идентификатор пакета (см. шаг 1)
  • Идентификатор ключа (см. шаг 7)
  • Значение токена (значение ключа p8, полученное на шаге 8)

Создание профиля подготовки для приложения

  1. Вернитесь на портал подготовки iOS, выберите Сертификаты, Идентификаторы & Профили, в меню слева выберите Профили , а затем создайте + новый профиль. Откроется экран Регистрация нового профиля подготовки .

  2. Выберите Разработка приложений iOS в разделе Разработка в качестве типа профиля подготовки, а затем нажмите кнопку Продолжить.

    Список профилей подготовки

  3. Затем выберите созданный идентификатор приложения в раскрывающемся списке Идентификатор приложения и нажмите кнопку Продолжить.

    Выберите идентификатор приложения.

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

    Примечание

    Этот сертификат не является сертификатом push-уведомлений, созданным на предыдущем шаге. Это ваш сертификат разработки. Если он не существует, его необходимо создать, так как это необходимое условие для работы с этим руководством. Сертификаты разработчиков можно создать на портале разработчика Apple, с помощью Xcode или Visual Studio.

  5. Вернитесь на страницу Сертификаты, идентификаторы & Профили , выберите Профили в меню слева, а затем создайте + новый профиль. Откроется экран Регистрация нового профиля подготовки .

  6. В окне Выбор сертификатов выберите созданный сертификат разработки. Затем нажмите кнопку Продолжить.

  7. Затем выберите устройства для тестирования и нажмите кнопку Продолжить.

  8. Наконец, выберите имя профиля в поле Имя профиля подготовки и нажмите кнопку Создать.

    Выбор имени профиля подготовки

  9. После создания нового профиля подготовки выберите Скачать. Запомните расположение, в котором он сохранен.

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

Создание центра уведомлений

В этом разделе вы создадите центр уведомлений и настроите проверку подлинности с помощью APNS. Вы можете использовать сертификат push-уведомлений p12 или проверку подлинности на основе маркеров. Если вы хотите использовать уже созданный центр уведомлений, можно перейти к шагу 5.

  1. Войдите в Azure.

  2. Щелкните Создать ресурс, найдите и выберите Центр уведомлений, а затем нажмите кнопку Создать.

  3. Обновите следующие поля, а затем нажмите кнопку Создать:

    ОСНОВНЫЕ СВЕДЕНИЯ

    Подписки: Выберите целевую подписку из раскрывающегося списка.
    Группа ресурсов: Создайте новую группу ресурсов (или выберите существующую).

    СВЕДЕНИЯ О ПРОСТРАНСТВЕ ИМЕН

    Пространство имен центра уведомлений: Введите глобально уникальное имя для пространства имен центра уведомлений .

    Примечание

    Убедитесь, что для этого поля выбран параметр Создать .

    СВЕДЕНИЯ О КОНЦЕНТРАТОРЕ УВЕДОМЛЕНИЙ

    Центр уведомлений: Введите имя центра уведомлений.
    Расположение: Выберите подходящее расположение из раскрывающегося списка
    Ценовая категория: Оставьте параметр по умолчанию Бесплатный

    Примечание

    Если вы не достигли максимального количества концентраторов на бесплатном уровне.

  4. После подготовки центра уведомлений перейдите к ресурсу.

  5. Перейдите в новый центр уведомлений.

  6. Выберите Политики доступа в списке (в разделе УПРАВЛЕНИЕ).

  7. Запишите значения имени политики и соответствующие значения строки подключения .

Настройка центра уведомлений с помощью сведений об APNS

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

Примечание

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

ВАРИАНТ 1. Использование сертификата push-уведомлений .p12

  1. Выберите Сертификат.

  2. Щелкните значок файла.

  3. Выберите P12-файл, экспортируемый ранее, и нажмите кнопку Открыть.

  4. При необходимости укажите правильный пароль.

  5. Выберите режим песочницы .

  6. Нажмите кнопку Сохранить.

ВАРИАНТ 2. Использование проверки подлинности на основе маркеров

  1. Выберите Токен.

  2. Введите следующие значения, полученные ранее:

    • Идентификатор ключа
    • Идентификатор пакета
    • Идентификатор команды
    • Маркер
  3. Выберите Песочница.

  4. Нажмите кнопку Сохранить.

Настройка центра уведомлений с помощью данных FCM

  1. Выберите Google (GCM/FCM) в разделе Параметры в меню слева.
  2. Введите ключ сервера , который вы записали в консоли Google Firebase.
  3. Нажмите кнопку Сохранить на панели инструментов.

Создание серверного приложения веб-API ASP.NET Core

В этом разделе вы создадите серверную часть веб-API ASP.NET Core для обработки регистрации устройств и отправки уведомлений в мобильное приложение React Native.

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

  1. В Visual Studio выберите Файл>Создать решение.

  2. ВыберитеПриложение>.NET Core>ASP.NET Core>API>Далее.

  3. В диалоговом окне Настройка нового ASP.NET Core веб-API выберите Целевая платформа.NET Core 3.1.

  4. Введите PushDemoApi в поле Имя проекта и нажмите кнопку Создать.

  5. Запустите отладку (ввод команды), + чтобы протестировать шаблонное приложение.

    Примечание

    Приложение с шаблоном настроено для использования WeatherForecastController в качестве launchUrl. Этот параметр задается вразделе Свойства> launchSettings.json.

    Если появится запрос на сообщение о недопустимом сертификате разработки:

    1. Нажмите кнопку Да , чтобы согласиться на запуск средства https dotnet dev-certs, чтобы устранить эту проблему. Затем средство dotnet dev-certs https предлагает ввести пароль для сертификата и пароль для цепочки ключей.

    2. Нажмите кнопку Да при появлении запроса Установить и доверять новому сертификату, а затем введите пароль для цепочки ключей.

  6. Разверните папку Контроллеры и удалите WeatherForecastController.cs.

  7. Удалить WeatherForecast.cs.

  8. Настройте значения локальной конфигурации с помощью средства диспетчера секретов. Разделение секретов из решения гарантирует, что они не будут в конечном итоге в системе управления версиями. Откройте Терминал , затем перейдите в каталог файла проекта и выполните следующие команды:

    dotnet user-secrets init
    dotnet user-secrets set "NotificationHub:Name" <value>
    dotnet user-secrets set "NotificationHub:ConnectionString" <value>
    

    Замените значения заполнителей собственным именем центра уведомлений и строка подключения значениями. Вы записали их в разделе Создание центра уведомлений . В противном случае их можно найти в Azure.

    NotificationHub:Name:
    См . раздел Имя в сводке основных компонентов в верхней части окна Обзор.

    NotificationHub:ConnectionString:
    См. раздел DefaultFullSharedAccessSignature в разделе Политики доступа.

    Примечание

    Для рабочих сценариев можно просмотреть такие варианты, как Azure KeyVault, для безопасного хранения строка подключения. Для простоты секреты будут добавлены в параметры Служба приложений Azure приложения.

Проверка подлинности клиентов с помощью ключа API (необязательно)

Ключи API не так безопасны, как маркеры, но их будет достаточно для целей этого руководства. Ключ API можно легко настроить с помощью ПО промежуточного слоя ASP.NET.

  1. Добавьте ключ API в значения локальной конфигурации.

    dotnet user-secrets set "Authentication:ApiKey" <value>
    

    Примечание

    Замените значение заполнителя собственным и запишите его.

  2. Управления + Щелкните проект PushDemoApi , выберите Создать папку в меню Добавить , а затем щелкните Добавить с помощью проверки подлинности в качестве имени папки.

  3. Управления + Щелкните папку Проверка подлинности , а затем выберите Создать файл... в меню Добавить .

  4. Выберите Общий>пустой класс, введите ApiKeyAuthOptions.cs в поле Имя, а затем нажмите кнопку Создать , добавив следующую реализацию.

    using Microsoft.AspNetCore.Authentication;
    
    namespace PushDemoApi.Authentication
    {
        public class ApiKeyAuthOptions : AuthenticationSchemeOptions
        {
            public const string DefaultScheme = "ApiKey";
            public string Scheme => DefaultScheme;
            public string ApiKey { get; set; }
        }
    }
    
  5. Добавьте еще один пустой класс в папку Authenticationс именем ApiKeyAuthHandler.cs, а затем добавьте следующую реализацию.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Claims;
    using System.Text.Encodings.Web;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    
    namespace PushDemoApi.Authentication
    {
        public class ApiKeyAuthHandler : AuthenticationHandler<ApiKeyAuthOptions>
        {
            const string ApiKeyIdentifier = "apikey";
    
            public ApiKeyAuthHandler(
                IOptionsMonitor<ApiKeyAuthOptions> options,
                ILoggerFactory logger,
                UrlEncoder encoder,
                ISystemClock clock)
                : base(options, logger, encoder, clock) {}
    
            protected override Task<AuthenticateResult> HandleAuthenticateAsync()
            {
                string key = string.Empty;
    
                if (Request.Headers[ApiKeyIdentifier].Any())
                {
                    key = Request.Headers[ApiKeyIdentifier].FirstOrDefault();
                }
                else if (Request.Query.ContainsKey(ApiKeyIdentifier))
                {
                    if (Request.Query.TryGetValue(ApiKeyIdentifier, out var queryKey))
                        key = queryKey;
                }
    
                if (string.IsNullOrWhiteSpace(key))
                    return Task.FromResult(AuthenticateResult.Fail("No api key provided"));
    
                if (!string.Equals(key, Options.ApiKey, StringComparison.Ordinal))
                    return Task.FromResult(AuthenticateResult.Fail("Invalid api key."));
    
                var identities = new List<ClaimsIdentity> {
                    new ClaimsIdentity("ApiKeyIdentity")
                };
    
                var ticket = new AuthenticationTicket(
                    new ClaimsPrincipal(identities), Options.Scheme);
    
                return Task.FromResult(AuthenticateResult.Success(ticket));
            }
        }
    }
    

    Примечание

    Обработчик проверки подлинности — это тип, реализующий поведение схемы, в данном случае настраиваемой схемы ключа API.

  6. Добавьте еще один пустой класс в папку Authenticationс именем ApiKeyAuthenticationBuilderExtensions.cs, а затем добавьте следующую реализацию.

    using System;
    using Microsoft.AspNetCore.Authentication;
    
    namespace PushDemoApi.Authentication
    {
        public static class AuthenticationBuilderExtensions
        {
            public static AuthenticationBuilder AddApiKeyAuth(
                this AuthenticationBuilder builder,
                Action<ApiKeyAuthOptions> configureOptions)
            {
                return builder
                    .AddScheme<ApiKeyAuthOptions, ApiKeyAuthHandler>(
                        ApiKeyAuthOptions.DefaultScheme,
                        configureOptions);
            }
        }
    }
    

    Примечание

    Этот метод расширения упрощает код конфигурации ПО промежуточного слоя в Startup.cs что делает его более удобочитаемым и в целом проще для выполнения.

  7. В Startup.cs обновите метод ConfigureServices , чтобы настроить проверку подлинности ключа API под вызовом служб. Метод AddControllers .

    using PushDemoApi.Authentication;
    using PushDemoApi.Models;
    using PushDemoApi.Services;
    
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
    
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = ApiKeyAuthOptions.DefaultScheme;
            options.DefaultChallengeScheme = ApiKeyAuthOptions.DefaultScheme;
        }).AddApiKeyAuth(Configuration.GetSection("Authentication").Bind);
    }
    
  8. В Startup.cs обновите метод Configure , чтобы вызвать методы расширения UseAuthentication и UseAuthorization в IApplicationBuilder приложения. Убедитесь, что эти методы вызываются после UseRouting и перед приложением. UseEndpoints.

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
    
        app.UseHttpsRedirection();
    
        app.UseRouting();
    
        app.UseAuthentication();
    
        app.UseAuthorization();
    
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
    

    Примечание

    Вызов UseAuthentication регистрирует ПО промежуточного слоя, которое использует ранее зарегистрированные схемы проверки подлинности (из Раздела ConfigureServices). Он должен вызываться перед любым ПО промежуточного слоя, которое зависит от проверки подлинности пользователей.

Добавление зависимостей и настройка служб

ASP.NET Core поддерживает шаблон проектирования программного обеспечения внедрения зависимостей, который является методом достижения инверсии управления (IoC) между классами и их зависимостями.

Использование центра уведомлений и пакета SDK центров уведомлений для внутренних операций инкапсулируется в службе. Служба регистрируется и становится доступной с помощью подходящей абстракции.

  1. Управления + Щелкните папку Dependencies (Зависимости ), а затем выберите Управление пакетами NuGet....

  2. Выполните поиск по запросу Microsoft.Azure.NotificationHubs и убедитесь, что он установлен.

  3. Щелкните Добавить пакеты, а затем нажмите кнопку Принять при появлении запроса на принятие условий лицензии.

  4. Управления + Щелкните проект PushDemoApi , выберите Создать папку в меню Добавить , а затем щелкните Добавить с помощью моделей в качестве имени папки.

  5. Управления + Щелкните папку Models (Модели ), а затем выберите Создать файл... в меню Добавить .

  6. Выберите Общий>пустой класс, введите PushTemplates.cs в поле Имя, а затем нажмите кнопку Создать , добавив следующую реализацию.

    namespace PushDemoApi.Models
    {
        public class PushTemplates
        {
            public class Generic
            {
                public const string Android = "{ \"notification\": { \"title\" : \"PushDemo\", \"body\" : \"$(alertMessage)\"}, \"data\" : { \"action\" : \"$(alertAction)\" } }";
                public const string iOS = "{ \"aps\" : {\"alert\" : \"$(alertMessage)\"}, \"action\" : \"$(alertAction)\" }";
            }
    
            public class Silent
            {
                public const string Android = "{ \"data\" : {\"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\"} }";
                public const string iOS = "{ \"aps\" : {\"content-available\" : 1, \"apns-priority\": 5, \"sound\" : \"\", \"badge\" : 0}, \"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\" }";
            }
        }
    }
    

    Примечание

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

  7. Добавьте еще один пустой класс в папку Modelsс именем DeviceInstallation.cs, а затем добавьте следующую реализацию.

    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    
    namespace PushDemoApi.Models
    {
        public class DeviceInstallation
        {
            [Required]
            public string InstallationId { get; set; }
    
            [Required]
            public string Platform { get; set; }
    
            [Required]
            public string PushChannel { get; set; }
    
            public IList<string> Tags { get; set; } = Array.Empty<string>();
        }
    }
    
  8. Добавьте еще один пустой класс в папку Modelsс именем NotificationRequest.cs, а затем добавьте следующую реализацию.

    using System;
    
    namespace PushDemoApi.Models
    {
        public class NotificationRequest
        {
            public string Text { get; set; }
            public string Action { get; set; }
            public string[] Tags { get; set; } = Array.Empty<string>();
            public bool Silent { get; set; }
        }
    }
    
  9. Добавьте еще один пустой класс в папку Modelsс именем NotificationHubOptions.cs, а затем добавьте следующую реализацию.

    using System.ComponentModel.DataAnnotations;
    
    namespace PushDemoApi.Models
    {
        public class NotificationHubOptions
        {
            [Required]
            public string Name { get; set; }
    
            [Required]
            public string ConnectionString { get; set; }
        }
    }
    
  10. Добавьте новую папку в проект PushDemoApiс именем Services.

  11. Добавьте пустой интерфейс в папку Servicesс именем INotificationService.cs, а затем добавьте следующую реализацию.

    using System.Threading;
    using System.Threading.Tasks;
    using PushDemoApi.Models;
    
    namespace PushDemoApi.Services
    {
        public interface INotificationService
        {
            Task<bool> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation, CancellationToken token);
            Task<bool> DeleteInstallationByIdAsync(string installationId, CancellationToken token);
            Task<bool> RequestNotificationAsync(NotificationRequest notificationRequest, CancellationToken token);
        }
    }
    
  12. Добавьте пустой класс в папку Servicesс именем NotificationHubsService.cs, а затем добавьте следующий код для реализации интерфейса INotificationService :

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Azure.NotificationHubs;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    using PushDemoApi.Models;
    
    namespace PushDemoApi.Services
    {
        public class NotificationHubService : INotificationService
        {
            readonly NotificationHubClient _hub;
            readonly Dictionary<string, NotificationPlatform> _installationPlatform;
            readonly ILogger<NotificationHubService> _logger;
    
            public NotificationHubService(IOptions<NotificationHubOptions> options, ILogger<NotificationHubService> logger)
            {
                _logger = logger;
                _hub = NotificationHubClient.CreateClientFromConnectionString(
                    options.Value.ConnectionString,
                    options.Value.Name);
    
                _installationPlatform = new Dictionary<string, NotificationPlatform>
                {
                    { nameof(NotificationPlatform.Apns).ToLower(), NotificationPlatform.Apns },
                    { nameof(NotificationPlatform.Fcm).ToLower(), NotificationPlatform.Fcm }
                };
            }
    
            public async Task<bool> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation, CancellationToken token)
            {
                if (string.IsNullOrWhiteSpace(deviceInstallation?.InstallationId) ||
                    string.IsNullOrWhiteSpace(deviceInstallation?.Platform) ||
                    string.IsNullOrWhiteSpace(deviceInstallation?.PushChannel))
                    return false;
    
                var installation = new Installation()
                {
                    InstallationId = deviceInstallation.InstallationId,
                    PushChannel = deviceInstallation.PushChannel,
                    Tags = deviceInstallation.Tags
                };
    
                if (_installationPlatform.TryGetValue(deviceInstallation.Platform, out var platform))
                    installation.Platform = platform;
                else
                    return false;
    
                try
                {
                    await _hub.CreateOrUpdateInstallationAsync(installation, token);
                }
                catch
                {
                    return false;
                }
    
                return true;
            }
    
            public async Task<bool> DeleteInstallationByIdAsync(string installationId, CancellationToken token)
            {
                if (string.IsNullOrWhiteSpace(installationId))
                    return false;
    
                try
                {
                    await _hub.DeleteInstallationAsync(installationId, token);
                }
                catch
                {
                    return false;
                }
    
                return true;
            }
    
            public async Task<bool> RequestNotificationAsync(NotificationRequest notificationRequest, CancellationToken token)
            {
                if ((notificationRequest.Silent &&
                    string.IsNullOrWhiteSpace(notificationRequest?.Action)) ||
                    (!notificationRequest.Silent &&
                    (string.IsNullOrWhiteSpace(notificationRequest?.Text)) ||
                    string.IsNullOrWhiteSpace(notificationRequest?.Action)))
                    return false;
    
                var androidPushTemplate = notificationRequest.Silent ?
                    PushTemplates.Silent.Android :
                    PushTemplates.Generic.Android;
    
                var iOSPushTemplate = notificationRequest.Silent ?
                    PushTemplates.Silent.iOS :
                    PushTemplates.Generic.iOS;
    
                var androidPayload = PrepareNotificationPayload(
                    androidPushTemplate,
                    notificationRequest.Text,
                    notificationRequest.Action);
    
                var iOSPayload = PrepareNotificationPayload(
                    iOSPushTemplate,
                    notificationRequest.Text,
                    notificationRequest.Action);
    
                try
                {
                    if (notificationRequest.Tags.Length == 0)
                    {
                        // This will broadcast to all users registered in the notification hub
                        await SendPlatformNotificationsAsync(androidPayload, iOSPayload, token);
                    }
                    else if (notificationRequest.Tags.Length <= 20)
                    {
                        await SendPlatformNotificationsAsync(androidPayload, iOSPayload, notificationRequest.Tags, token);
                    }
                    else
                    {
                        var notificationTasks = notificationRequest.Tags
                            .Select((value, index) => (value, index))
                            .GroupBy(g => g.index / 20, i => i.value)
                            .Select(tags => SendPlatformNotificationsAsync(androidPayload, iOSPayload, tags, token));
    
                        await Task.WhenAll(notificationTasks);
                    }
    
                    return true;
                }
                catch (Exception e)
                {
                    _logger.LogError(e, "Unexpected error sending notification");
                    return false;
                }
            }
    
            string PrepareNotificationPayload(string template, string text, string action) => template
                .Replace("$(alertMessage)", text, StringComparison.InvariantCulture)
                .Replace("$(alertAction)", action, StringComparison.InvariantCulture);
    
            Task SendPlatformNotificationsAsync(string androidPayload, string iOSPayload, CancellationToken token)
            {
                var sendTasks = new Task[]
                {
                    _hub.SendFcmNativeNotificationAsync(androidPayload, token),
                    _hub.SendAppleNativeNotificationAsync(iOSPayload, token)
                };
    
                return Task.WhenAll(sendTasks);
            }
    
            Task SendPlatformNotificationsAsync(string androidPayload, string iOSPayload, IEnumerable<string> tags, CancellationToken token)
            {
                var sendTasks = new Task[]
                {
                    _hub.SendFcmNativeNotificationAsync(androidPayload, tags, token),
                    _hub.SendAppleNativeNotificationAsync(iOSPayload, tags, token)
                };
    
                return Task.WhenAll(sendTasks);
            }
        }
    }
    

    Примечание

    Выражение тега, предоставленное для SendTemplateNotificationAsync , ограничено 20 тегами. Для большинства операторов оно ограничено 6, но в этом случае выражение содержит только OR (||). Если в запросе более 20 тегов, их необходимо разделить на несколько запросов. Дополнительные сведения см. в документации по выражениям маршрутизации и тегов .

  13. В Startup.cs обновите метод ConfigureServices , чтобы добавить NotificationHubsService в качестве одноэлементной реализации INotificationService.

    
    using PushDemoApi.Models;
    using PushDemoApi.Services;
    
    public void ConfigureServices(IServiceCollection services)
    {
        ...
    
        services.AddSingleton<INotificationService, NotificationHubService>();
    
        services.AddOptions<NotificationHubOptions>()
            .Configure(Configuration.GetSection("NotificationHub").Bind)
            .ValidateDataAnnotations();
    }
    

Создание API уведомлений

  1. Управления + Щелкните папку Контроллеры , а затем выберите Создать файл... в меню Добавить .

  2. Выберите ASP.NET Core>Веб-класс контроллера API, введите NotificationsController в поле Имя, а затем нажмите кнопку Создать.

    Примечание

    Если вы используете Visual Studio 2019, выберите шаблон Контроллер API с действиями чтения и записи .

  3. Добавьте следующие пространства имен в начало файла.

    using System.ComponentModel.DataAnnotations;
    using System.Net;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using PushDemoApi.Models;
    using PushDemoApi.Services;
    
  4. Обновите шаблонный контроллер так, чтобы он был производным от ControllerBase и дополнен атрибутом ApiController .

    [ApiController]
    [Route("api/[controller]")]
    public class NotificationsController : ControllerBase
    {
        // Templated methods here
    }
    

    Примечание

    Базовый класс Controller обеспечивает поддержку представлений, но в этом случае это не требуется, поэтому вместо него можно использовать ControllerBase . Если вы используете Visual Studio 2019, этот шаг можно пропустить.

  5. Если вы решили выполнить действия в разделе Проверка подлинности клиентов с помощью ключа API , необходимо также украсить NotificationsController атрибутом Authorize .

    [Authorize]
    
  6. Обновите конструктор, чтобы принять зарегистрированный экземпляр INotificationService в качестве аргумента и назначить его члену только для чтения.

    readonly INotificationService _notificationService;
    
    public NotificationsController(INotificationService notificationService)
    {
        _notificationService = notificationService;
    }
    
  7. В launchSettings.json (в папке Свойства) измените launchUrl с weatherforecast на api/notifications в соответствии с URL-адресом, указанным в атрибуте Маршрута RegistrationsController.

  8. Начните отладку (ввод команды + ), чтобы убедиться, что приложение работает с новым NotificationsController , и возвращает состояние 401 Unauthorized (Не авторизовано ).

    Примечание

    Visual Studio может не запускать приложение автоматически в браузере. С этого момента вы будете использовать Postman для тестирования API.

  9. На новой вкладке Postman задайте для запроса значение GET. Введите адрес ниже, заменив заполнитель <applicationUrl> https applicationUrl в разделе Свойства>launchSettings.json.

    <applicationUrl>/api/notifications
    

    Примечание

    ApplicationUrl должен иметь значение "https://localhost:5001" для профиля по умолчанию. Если вы используете СЛУЖБЫ IIS (по умолчанию в Visual Studio 2019 для Windows), следует использовать applicationUrl, указанный в элементе iisSettings . Если адрес неправильный, вы получите ответ 404.

  10. Если вы решили выполнить действия в разделе Проверка подлинности клиентов с помощью ключа API , обязательно настройте заголовки запросов, чтобы включить значение apikey .

    Ключ Значение
    apikey <your_api_key>
  11. Нажмите кнопку Отправить .

    Примечание

    Вы должны получить состояние 200 ОК с некоторым содержимым JSON .

    Если появится предупреждение о проверке SSL-сертификата , можно отключить параметр проверки SSL-сертификата Postman в параметрах.

  12. Замените методы шаблонного класса в NotificationsController.cs следующим кодом.

    [HttpPut]
    [Route("installations")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)]
    public async Task<IActionResult> UpdateInstallation(
        [Required]DeviceInstallation deviceInstallation)
    {
        var success = await _notificationService
            .CreateOrUpdateInstallationAsync(deviceInstallation, HttpContext.RequestAborted);
    
        if (!success)
            return new UnprocessableEntityResult();
    
        return new OkResult();
    }
    
    [HttpDelete()]
    [Route("installations/{installationId}")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)]
    public async Task<ActionResult> DeleteInstallation(
        [Required][FromRoute]string installationId)
    {
        var success = await _notificationService
            .DeleteInstallationByIdAsync(installationId, CancellationToken.None);
    
        if (!success)
            return new UnprocessableEntityResult();
    
        return new OkResult();
    }
    
    [HttpPost]
    [Route("requests")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)]
    public async Task<IActionResult> RequestPush(
        [Required]NotificationRequest notificationRequest)
    {
        if ((notificationRequest.Silent &&
            string.IsNullOrWhiteSpace(notificationRequest?.Action)) ||
            (!notificationRequest.Silent &&
            string.IsNullOrWhiteSpace(notificationRequest?.Text)))
            return new BadRequestResult();
    
        var success = await _notificationService
            .RequestNotificationAsync(notificationRequest, HttpContext.RequestAborted);
    
        if (!success)
            return new UnprocessableEntityResult();
    
        return new OkResult();
    }
    

Создание приложения API

Теперь вы создаете приложение API в Служба приложений Azure для размещения серверной службы.

  1. Войдите в портал Azure.

  2. Щелкните Создать ресурс, найдите и выберите Приложение API, а затем нажмите кнопку Создать.

  3. Обновите следующие поля, а затем нажмите кнопку Создать.

    Имя приложения:
    Введите глобально уникальное имя приложения API.

    Подписки:
    Выберите ту же целевую подписку, в которую вы создали центр уведомлений.

    Группа ресурсов:
    Выберите ту же группу ресурсов, в которую вы создали центр уведомлений.

    План или расположение Служба приложений:
    Создание плана Служба приложений

    Примечание

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

    Application Insights:
    Оставьте предложенный параметр (новый ресурс будет создан под этим именем) или выберите существующий ресурс.

  4. После подготовки приложения API перейдите к ресурсу.

  5. Запишите свойство URL-адреса в сводке основных компонентов в верхней части обзора. Этот URL-адрес — это серверная конечная точка , которая будет использоваться далее в этом руководстве.

    Примечание

    URL-адрес использует указанное ранее имя приложения API в формате https://<app_name>.azurewebsites.net.

  6. Выберите Конфигурация в списке (в разделе Параметры).

  7. Для каждого из указанных ниже параметров щелкните Новый параметр приложения , чтобы ввести имя и значение, а затем нажмите кнопку ОК.

    Имя Значение
    Authentication:ApiKey <api_key_value>
    NotificationHub:Name <hub_name_value>
    NotificationHub:ConnectionString <hub_connection_string_value>

    Примечание

    Это те же параметры, которые вы определили ранее в параметрах пользователя. Вы сможете скопировать их. Параметр Authentication:ApiKey требуется только в том случае, если вы решили выполнить проверку подлинности клиентов с помощью ключа API . Для рабочих сценариев можно просмотреть такие варианты, как Azure KeyVault. Они были добавлены в качестве параметров приложения для простоты в данном случае.

  8. После добавления всех параметров приложения нажмите кнопку Сохранить, а затем продолжить.

Публикация серверной службы

Затем разверните приложение в приложении API, чтобы сделать его доступным со всех устройств.

Примечание

Следующие действия относятся только к Visual Studio для Mac. Если вы используете Visual Studio 2019 в Windows, поток публикации будет отличаться. См. статью Публикация в Служба приложений Azure в Windows.

  1. Измените конфигурацию с Отладка на Выпуск , если вы еще этого не сделали.

  2. Управления + Щелкните проект PushDemoApi , а затем выберите Опубликовать в Azure... в меню Публикация .

  3. Следуйте потоку проверки подлинности при появлении соответствующего запроса. Используйте учетную запись, которая использовалась при предыдущем создании приложения API .

  4. Выберите ранее созданное приложение API Служба приложений Azure в списке в качестве целевого объекта публикации и нажмите кнопку Опубликовать.

После завершения работы мастера приложение публикуется в Azure, а затем открывается. Запишите URL-адрес , если вы еще этого не сделали. Этот URL-адрес является серверной конечной точкой , которая будет использоваться далее в этом руководстве.

Проверка опубликованного API

  1. В Postman откройте новую вкладку, задайте для запроса значение PUT и введите адрес ниже. Замените заполнитель базовым адресом, который вы записали в предыдущем разделе публикации серверной службы .

    https://<app_name>.azurewebsites.net/api/notifications/installations
    

    Примечание

    Базовый адрес должен быть в формате https://<app_name>.azurewebsites.net/

  2. Если вы решили выполнить действия в разделе Проверка подлинности клиентов с помощью ключа API , обязательно настройте заголовки запросов, чтобы включить значение apikey .

    Ключ Значение
    apikey <your_api_key>
  3. Выберите необработанный параметр для текста, затем выберите JSON в списке параметров формата, а затем включите заполнитель содержимого JSON :

    {}
    
  4. Нажмите кнопку Отправить.

    Примечание

    Вы должны получить состояние 422 UnprocessableEntity от службы.

  5. Выполните шаги 1–4 еще раз, но на этот раз укажите конечную точку запросов, чтобы убедиться, что вы получили ответ 400 Bad Request .

    https://<app_name>.azurewebsites.net/api/notifications/requests
    

Примечание

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

Создание кроссплатформенного приложения React Native

В этом разделе описано, как создать мобильное приложение React Native, реализующее push-уведомления на разных платформах.

Это позволяет зарегистрировать и отменить регистрацию в центре уведомлений через созданную вами серверную службу.

Оповещение отображается, когда указано действие и приложение находится на переднем плане. В противном случае уведомления отображаются в центре уведомлений.

Примечание

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

Создание решения React Native

  1. В Terminalобновите средства среды, необходимые для работы с React Native с помощью следующих команд:

    # install node
    brew install node
    # or update
    brew update node
    # install watchman
    brew install watchman
    # or update
    brew upgrade watchman
    # install cocoapods
    sudo gem install cocoapods
    
  2. Если Terminalу вас установлен React Native интерфейс командной строки, выполните следующую команду, чтобы удалить ее. Используйте для npx автоматического доступа к последней доступной версии React Native CLI:

    npm uninstall -g react-native-cli
    

    Примечание

    React Native имеет встроенный интерфейс командной строки. Вместо глобальной установки конкретной версии CLI и управления ею рекомендуется получить доступ к текущей версии во время выполнения с помощью npx, которая поставляется с Node.js. При npx react-native <command>использовании текущая стабильная версия CLI будет скачан и выполнена во время выполнения команды.

  3. Перейдите в папку проектов, в которой вы хотите создать новое приложение. Используйте шаблон на основе Typescript, указав --template параметр :

    # init new project with npx
    npx react-native init PushDemo --template react-native-template-typescript
    
  4. Запустите сервер metro, который создает пакеты JavaScript и отслеживает все обновления кода для обновления пакетов в режиме реального времени:

    cd PushDemo
    npx react-native start
    
  5. Запустите приложение iOS, чтобы проверить установку. Перед выполнением следующей команды убедитесь, что вы запустили симулятор iOS или подключили устройство iOS:

    npx react-native run-ios
    
  6. Запустите приложение Android, чтобы проверить установку. Для настройки эмулятора или устройства Android необходимо выполнить несколько дополнительных действий, чтобы получить доступ к серверу React Native metro. Следующие команды создают исходный пакет JavaScript для Android и помещают его в папку assets.

    # create assets folder for the bundle
    mkdir android/app/scr/main/assets
    # build the bundle
    npx react-native bundle --platform android --dev true --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res
    # enable ability for sim to access the localhost
    adb reverse tcp:8081 tcp:8081
    

    Этот скрипт будет предварительно развернут с начальной версией приложения. После развертывания настройте эмулятор или устройство для доступа к серверу metro, указав IP-адрес сервера. Выполните следующую команду, чтобы создать и запустить приложение Android:

    npx react-native run-android
    

    После входа в приложение нажмите (CMD+Mэмулятор) или встряхните устройство, чтобы заполнить параметры разработчика, перейдите по адресуChange Bundle LocationSettings> и укажите IP-адрес сервера метро с портом по умолчанию: . <metro-server-ip-address>:8081

  7. App.tsx В файле примените любое изменение к макету страницы, сохраните его и сделайте это изменение автоматически отраженным в приложениях iOS и Android.

    Примечание

    Подробное руководство по настройке среды разработки доступно в официальной документации.

Установка необходимых пакетов

Для работы с этим примером требуются следующие три пакета:

  1. React Native push-уведомления iOS - Project GitHub

    Этот пакет был создан, когда PushNotificationIOS был отделен от ядра React Native. Пакет изначально реализует push-уведомления для iOS и предоставляет React Native интерфейс для доступа к нему. Выполните следующую команду, чтобы установить пакет:

    yarn add @react-native-community/push-notification-ios
    
  2. React Native push-уведомления на разных платформах

    Этот пакет реализует локальные и удаленные уведомления в iOS и Android на разных платформах. Выполните следующую команду, чтобы установить пакет:

    yarn add react-native-push-notification
    
  3. Пакет сведений об устройстве Пакет предоставляет сведения об устройстве во время выполнения. Используйте его для определения идентификатора устройства, который используется для регистрации для push-уведомлений. Выполните следующую команду, чтобы установить пакет:

    yarn add react-native-device-info
    

Реализация кроссплатформенных компонентов

  1. Создайте и реализуйте DemoNotificationHandler:

    import PushNotification from 'react-native-push-notification';
    
    class DemoNotificationHandler {
      private _onRegister: any;
      private _onNotification: any;
    
      onNotification(notification: any) {
        console.log('NotificationHandler:', notification);
    
        if (typeof this._onNotification === 'function') {
          this._onNotification(notification);
        }
      }
    
      onRegister(token: any) {
        console.log('NotificationHandler:', token);
    
        if (typeof this._onRegister === 'function') {
          this._onRegister(token);
        }
      }
    
      attachTokenReceived(handler: any) {
        this._onRegister = handler;
      }
    
      attachNotificationReceived(handler: any) {
        this._onNotification = handler;
      }
    }
    
    const handler = new DemoNotificationHandler();
    
    PushNotification.configure({
      onRegister: handler.onRegister.bind(handler),
      onNotification: handler.onNotification.bind(handler),
      permissions: {
        alert: true,
        badge: true,
        sound: true,
      },
      popInitialNotification: true,
      requestPermissions: true,
    });
    
    export default handler;
    
  2. Создайте и реализуйте DemoNotificationService:

    import PushNotification from 'react-native-push-notification';
    import DemoNotificationHandler from './DemoNotificationHandler';
    
    export default class DemoNotificationService {
      constructor(onTokenReceived: any, onNotificationReceived: any) {
        DemoNotificationHandler.attachTokenReceived(onTokenReceived);
        DemoNotificationHandler.attachNotificationReceived(onNotificationReceived);
        PushNotification.getApplicationIconBadgeNumber(function(number: number) {
          if(number > 0) {
            PushNotification.setApplicationIconBadgeNumber(0);
          }
        });
      }
    
      checkPermissions(cbk: any) {
        return PushNotification.checkPermissions(cbk);
      }
    
      requestPermissions() {
        return PushNotification.requestPermissions();
      }
    
      cancelNotifications() {
        PushNotification.cancelLocalNotifications();
      }
    
      cancelAll() {
        PushNotification.cancelAllLocalNotifications();
      }
    
      abandonPermissions() {
        PushNotification.abandonPermissions();
      }
    }
    
  3. Создайте и реализуйте DemoNotificationRegistrationService:

    export default class DemoNotificationService {
        constructor(
            readonly apiUrl: string,
            readonly apiKey: string) {
        }
    
    async registerAsync(request: any): Promise<Response> {
            const method = 'PUT';
            const registerApiUrl = `${this.apiUrl}/notifications/installations`;
            const result = await fetch(registerApiUrl, {
                method: method,
                headers: {
                    Accept: 'application/json',
                    'Content-Type': 'application/json',
                    'apiKey': this.apiKey
                },
                body: JSON.stringify(request)
            });
    
            this.validateResponse(registerApiUrl, method, request, result);
            return result;
        }
    
        async deregisterAsync(deviceId: string): Promise<Response> {
            const method = 'DELETE';
            const deregisterApiUrl = `${this.apiUrl}/notifications/installations/${deviceId}`;
            const result = await fetch(deregisterApiUrl, {
                method: method,
                headers: {
                    Accept: 'application/json',
                    'Content-Type': 'application/json',
                    'apiKey': this.apiKey
                }
            });
    
            this.validateResponse(deregisterApiUrl, method, null, result);
            return result;
        }
    
        private validateResponse(requestUrl: string, method: string, requestPayload: any, response: Response) {
            console.log(`Request: ${method} ${requestUrl} => ${JSON.stringify(requestPayload)}\nResponse: ${response.status}`);
            if (!response || response.status != 200) {
                throw `HTTP error ${response.status}: ${response.statusText}`;
            }
        }
    }
    
  4. Настройте приложение. Откройте package.json и добавьте следующее определение скрипта:

    "configure": "cp .app.config.tsx src/config/AppConfig.tsx"
    

    Затем выполните этот скрипт, который скопирует конфигурацию по умолчанию в папку config .

    yarn configure
    

    Последним шагом является обновление файла конфигурации, скопированного на предыдущем шаге, с помощью сведений о доступе к API. Укажите apiKey параметры и apiUrl :

    module.exports = {
        appName: "PushDemo",
        env: "production",
        apiUrl: "https://<azure-push-notifications-api-url>/api/",
        apiKey: "<api-auth-key>",
    };
    

Реализация кроссплатформенного пользовательского интерфейса

  1. Определение макета страницы

    <View style={styles.container}>
      {this.state.isBusy &&
        <ActivityIndicator></ActivityIndicator>
      }
      <View style={styles.button}>
        <Button title="Register" onPress={this.onRegisterButtonPress.bind(this)} disabled={this.state.isBusy} />
      </View>
      <View style={styles.button}>
        <Button title="Deregister" onPress={this.onDeregisterButtonPress.bind(this)} disabled={this.state.isBusy} />
      </View>
    </View>
    
  2. Применение стилей

    const styles = StyleSheet.create({
      container: {
        flex: 1,
        alignItems: "center",
        justifyContent: 'flex-end',
        margin: 50,
      },
      button: {
        margin: 5,
        width: "100%",
      }
    });
    
  3. Инициализация компонента страницы

      state: IState;
      notificationService: DemoNotificationService;
      notificationRegistrationService: DemoNotificationRegistrationService;
      deviceId: string;
    
      constructor(props: any) {
        super(props);
        this.deviceId = DeviceInfo.getUniqueId();
        this.state = {
          status: "Push notifications registration status is unknown",
          registeredOS: "",
          registeredToken: "",
          isRegistered: false,
          isBusy: false,
        };
    
        this.notificationService = new DemoNotificationService(
          this.onTokenReceived.bind(this),
          this.onNotificationReceived.bind(this),
        );
    
        this.notificationRegistrationService = new DemoNotificationRegistrationService(
          Config.apiUrl,
          Config.apiKey,
        );
      }
    
  4. Определение обработчиков нажатия кнопки

      async onRegisterButtonPress() {
        if (!this.state.registeredToken || !this.state.registeredOS) {
          Alert.alert("The push notifications token wasn't received.");
          return;
        }
    
        let status: string = "Registering...";
        let isRegistered = this.state.isRegistered;
        try {
          this.setState({ isBusy: true, status });
          const pnPlatform = this.state.registeredOS == "ios" ? "apns" : "fcm";
          const pnToken = this.state.registeredToken;
          const request = {
            installationId: this.deviceId,
            platform: pnPlatform,
            pushChannel: pnToken,
            tags: []
          };
          const response = await this.notificationRegistrationService.registerAsync(request);
          status = `Registered for ${this.state.registeredOS} push notifications`;
          isRegistered = true;
        } catch (e) {
          status = `Registration failed: ${e}`;
        }
        finally {
          this.setState({ isBusy: false, status, isRegistered });
        }
      }
    
      async onDeregisterButtonPress() {
        if (!this.notificationService)
          return;
    
        let status: string = "Deregistering...";
        let isRegistered = this.state.isRegistered;
        try {
          this.setState({ isBusy: true, status });
          await this.notificationRegistrationService.deregisterAsync(this.deviceId);
          status = "Deregistered from push notifications";
          isRegistered = false;
        } catch (e) {
          status = `Deregistration failed: ${e}`;
        }
        finally {
          this.setState({ isBusy: false, status, isRegistered });
        }
      }
    
  5. Обработка регистраций полученных маркеров и push-уведомлений

      onTokenReceived(token: any) {
        console.log(`Received a notification token on ${token.os}`);
        this.setState({ registeredToken: token.token, registeredOS: token.os, status: `The push notifications token has been received.` });
    
        if (this.state.isRegistered && this.state.registeredToken && this.state.registeredOS) {
          this.onRegisterButtonPress();
        }
      }
    
      onNotificationReceived(notification: any) {
        console.log(`Received a push notification on ${this.state.registeredOS}`);
        this.setState({ status: `Received a push notification...` });
    
        if (notification.data.message) {
          Alert.alert(AppConfig.appName, `${notification.data.action} action received`);
        }
      }
    };
    

Настройка собственного проекта Android для push-уведомлений

Настройка необходимых пакетов Android

Пакет автоматически связывается при сборке приложения. Ниже приведено несколько дополнительных действий для завершения процесса настройки.

Настройка манифеста Android

В разделе android/app/src/main/AndroidManifest.xml проверьте имя пакета, разрешения и необходимые службы. Убедитесь, что вы зарегистрировали RNPushNotificationPublisher и RNPushNotificationBootEventReceiver получателей, а также зарегистрировали RNPushNotificationListenerService службу. Метаданные уведомлений можно использовать для настройки внешнего вида push-уведомлений.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="YOUR_PACKAGE_NAME">

      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.WAKE_LOCK" />
      <uses-permission android:name="android.permission.VIBRATE" />
      <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

      <application
        android:name=".MainApplication"
        android:label="@string/app_name"
        android:usesCleartextTraffic="true"
        android:icon="@mipmap/ic_launcher"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:allowBackup="false"
        android:theme="@style/AppTheme">

        <meta-data  android:name="com.dieam.reactnativepushnotification.notification_channel_name"
                    android:value="PushDemo Channel"/>
        <meta-data  android:name="com.dieam.reactnativepushnotification.notification_channel_description"
                    android:value="PushDemo Channel Description"/>
        <meta-data  android:name="com.dieam.reactnativepushnotification.notification_foreground"
                    android:value="true"/>
        <meta-data  android:name="com.dieam.reactnativepushnotification.notification_color"
                    android:resource="@android:color/white"/>

        <receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher" />
        <receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

        <service
            android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerService"
            android:exported="false" >
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>

        <activity
          android:name=".MainActivity"
          android:label="@string/app_name"
          android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
          android:launchMode="singleTask"
          android:windowSoftInputMode="adjustResize">
          <intent-filter>
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>
        </activity>
        <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
      </application>

</manifest>

Настройка служб Google

В android/app/build.gradle зарегистрируйте Службы Google:

dependencies {
  ...
  implementation 'com.google.firebase:firebase-analytics:17.3.0'
  ...
}

apply plugin: 'com.google.gms.google-services'

Скопируйте файл google-services.json, скачанный во время настройки FCM, в папку проекта android/app/.

Обработка push-уведомлений для Android

Вы настроили существующую RNPushNotificationListenerService службу для обработки входящих push-уведомлений Android. Эта служба была зарегистрирована ранее в манифесте приложения. Он обрабатывает входящие уведомления и перенаправит их в кроссплатформенную React Native часть. Никаких дополнительных действий не требуется.

Настройка собственного проекта iOS для push-уведомлений

Настройка необходимых пакетов iOS

Пакет автоматически связывается при сборке приложения. Все, что вам нужно сделать, это установить собственные модули pod:

npx pod-install

Настройка Info.plist и Entitlements.plist

  1. Перейдите в папку PushDemo/ios и откройте рабочую область PushDemo.xcworkspace, выберите верхний проект PushDemo и перейдите на вкладку "Возможности подписывания &".

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

  3. Добавьте две новые возможности с помощью кнопки - "+":

    • Возможность фонового режима и установите флажок Удаленные уведомления.
    • Возможность push-уведомлений

Обработка push-уведомлений для iOS

  1. Откройте AppDelegate.h и добавьте следующий импорт:

    #import <UserNotifications/UNUserNotificationCenter.h>
    
  2. Обновите список протоколов, поддерживаемых AppDelegate, добавив UNUserNotificationCenterDelegate:

    @interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate, UNUserNotificationCenterDelegate>
    
  3. Откройте AppDelegate.m и настройте все необходимые обратные вызовы iOS:

    #import <UserNotifications/UserNotifications.h>
    #import <RNCPushNotificationIOS.h>
    
    ...
    
    // Required to register for notifications
    - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
    {
     [RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings];
    }
    
    // Required for the register event.
    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
    {
     [RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
    }
    
    // Required for the notification event. You must call the completion handler after handling the remote notification.
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
    fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
    {
      [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
    }
    
    // Required for the registrationError event.
    - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
    {
     [RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
    }
    
    // IOS 10+ Required for localNotification event
    - (void)userNotificationCenter:(UNUserNotificationCenter *)center
    didReceiveNotificationResponse:(UNNotificationResponse *)response
             withCompletionHandler:(void (^)(void))completionHandler
    {
      [RNCPushNotificationIOS didReceiveNotificationResponse:response];
      completionHandler();
    }
    
    // IOS 4-10 Required for the localNotification event.
    - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
    {
     [RNCPushNotificationIOS didReceiveLocalNotification:notification];
    }
    
    //Called when a notification is delivered to a foreground app.
    -(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
    {
      completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
    }
    

Тестирование решения

Теперь вы можете проверить отправку уведомлений через серверную службу.

Отправка тестового уведомления

  1. Откройте новую вкладку в Postman.

  2. Задайте для запроса значение POST и введите следующий адрес:

    https://<app_name>.azurewebsites.net/api/notifications/requests
    
  3. Если вы решили выполнить действия в разделе Проверка подлинности клиентов с помощью ключа API , обязательно настройте заголовки запросов, чтобы включить значение apikey .

    Ключ Значение
    apikey <your_api_key>
  4. Выберите необработанный параметр для текста, затем выберите JSON в списке параметров формата, а затем включите заполнитель содержимого JSON :

    {
        "text": "Message from Postman!",
        "action": "action_a"
    }
    
  5. Нажмите кнопку Код , которая находится под кнопкой Сохранить в правом верхнем углу окна. Запрос должен выглядеть примерно так, как в следующем примере, если он отображается для HTML (в зависимости от того, включен ли заголовок apikey ):

    POST /api/notifications/requests HTTP/1.1
    Host: https://<app_name>.azurewebsites.net
    apikey: <your_api_key>
    Content-Type: application/json
    
    {
        "text": "Message from backend service",
        "action": "action_a"
    }
    
  6. Запустите приложение PushDemo на одной или обеих целевых платформах (Android и iOS).

    Примечание

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

  7. В приложении PushDemo нажмите кнопку Зарегистрировать .

  8. Вернитесь в Postman, закройте окно Создание фрагментов кода (если вы еще этого не сделали), а затем нажмите кнопку Отправить .

  9. Убедитесь, что вы получили ответ 200 ОК в Postman , и в приложении появится оповещение, показывающее полученное действие ActionA.

  10. Закройте приложение PushDemo , а затем снова нажмите кнопку Отправить в Postman.

  11. Убедитесь, что вы получили ответ 200 ОК в Postman еще раз. Убедитесь, что в области уведомлений для приложения PushDemo отображается уведомление с правильным сообщением.

  12. Коснитесь уведомления, чтобы убедиться, что приложение открывается и отображается оповещение о получении действия ActionA .

  13. Вернитесь в Postman, измените текст предыдущего запроса, чтобы отправить автоматическое уведомление , указав action_b вместо action_a для значения действия .

    {
        "action": "action_b",
        "silent": true
    }
    
  14. Пока приложение все еще открыто, нажмите кнопку Отправить в Postman.

  15. Убедитесь, что вы получили ответ 200 OK в Postman и что в приложении отображается оповещение о получении действия ActionB вместо полученного действия ActionA.

  16. Закройте приложение PushDemo , а затем снова нажмите кнопку Отправить в Postman.

  17. Убедитесь, что вы получили ответ 200 OK в Postman и что автоматическое уведомление не отображается в области уведомлений.

Устранение неполадок

Нет ответа от серверной службы

При локальном тестировании убедитесь, что серверная служба запущена и использует правильный порт.

При тестировании в приложении API Azure проверка служба запущена, развернута и запущена без ошибок.

Не забудьте проверка вы правильно указали базовый адрес в Postman или в конфигурации мобильного приложения при тестировании через клиент. При локальном тестировании базовым адресом должен быть https://<api_name>.azurewebsites.net/ или https://localhost:5001/ .

Отсутствие уведомлений в Android после запуска или остановки сеанса отладки

Убедитесь, что вы снова зарегистрируетесь после запуска или остановки сеанса отладки. Отладчик вызовет создание нового токена Firebase . Также необходимо обновить установку центра уведомлений.

Получение кода состояния 401 из серверной службы

Убедитесь, что вы задаете заголовок запроса apikey , и это значение совпадает с тем, которое вы настроили для серверной службы.

Если эта ошибка возникает при локальном тестировании, убедитесь, что значение ключа, определенное в конфигурации клиента, соответствует значению параметра пользователя Authentication:ApiKey , используемому API.

При тестировании с помощью приложения API убедитесь, что значение ключа в файле конфигурации клиента соответствует параметру приложения Authentication:ApiKey , который используется в приложении API.

Примечание

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

Если вы решили не выполнять проверку подлинности клиентов с помощью ключа API , убедитесь, что атрибут Authorize не применен к классу NotificationsController .

Получение кода состояния 404 из серверной службы

Убедитесь, что конечная точка и метод HTTP-запроса верны. Например, конечные точки должны быть примерно такими:

  • [PUT]https://<api_name>.azurewebsites.net/api/notifications/installations
  • [DELETE]https://<api_name>.azurewebsites.net/api/notifications/installations/<installation_id>
  • [POST]https://<api_name>.azurewebsites.net/api/notifications/requests

Или при локальном тестировании:

  • [PUT]https://localhost:5001/api/notifications/installations
  • [DELETE]https://localhost:5001/api/notifications/installations/<installation_id>
  • [POST]https://localhost:5001/api/notifications/requests

При указании базового адреса в клиентском приложении убедитесь, что он заканчивается на /. При локальном тестировании базовым адресом должен быть https://<api_name>.azurewebsites.net/ или https://localhost:5001/ .

Не удается зарегистрироваться и отображается сообщение об ошибке центра уведомлений

Убедитесь, что тестовое устройство подключено к сети. Затем определите код состояния HTTP-ответа, задав точку останова для проверки значения свойства StatusCode в HttpResponse.

Просмотрите предыдущие рекомендации по устранению неполадок, если это применимо, на основе кода состояния.

Установите точку останова в строках, возвращающих эти коды состояния для соответствующего API. Затем попробуйте вызвать серверную службу при локальной отладке.

Убедитесь, что серверная служба работает должным образом с помощью Postman , используя соответствующие полезные данные. Используйте фактические полезные данные, созданные клиентским кодом для рассматриваемой платформы.

Просмотрите разделы конфигурации для конкретной платформы, чтобы убедиться, что шаги не пропущены. Убедитесь, что подходящие значения разрешаются для installation id переменных и token для соответствующей платформы.

Не удается разрешить идентификатор для отображаемого сообщения об ошибке устройства

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

Дальнейшие действия

Теперь у вас должно быть базовое приложение React Native, подключенное к центру уведомлений через серверную службу, которое может отправлять и получать уведомления.

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

Центр приложений Visual Studio можно быстро включить в мобильные приложения, предоставляющие аналитику и диагностика для устранения неполадок.