Апрель 2016

Том 31 номер 4

На переднем крае - Отправка уведомлений мобильным приложениям

Дино Эспозито | Апрель 2016

Dino EspositoВ последних нескольких статьях я писал по большей части об архитектуре программного обеспечения и проектировании. Хотя роль архитектуры в создании программной системы никогда не следует недооценивать или отрицать, любое приложение в конечном счете зависит от суммы индивидуальных функций. Это все та же философия User Experience Driven Development (UXDD), в которой мерой успеха ПО является то, насколько удобно пользователю работать с приложением. Если ваша программная система включает мобильную клиентскую часть, вы вряд ли сможете проигнорировать такую функцию, как всплывающие уведомления (push notifications).

В этой статье я просуммирую, что необходимо для добавления уровня уведомлений поверх мобильных приложений независимо от самой мобильной ОС. Попутно я дам обзор сервисов платформы Microsoft Azure Notification Hub.

Краткий обзор всплывающих уведомлений

Всплывающим уведомлением называют сообщение, получаемое мобильным устройством от серверной части приложения без предварительной отправки запроса явным образом. Большая часть взаимодействия между клиентскими и серверными компонентами приложения происходит через явные операции, как правило, инициируемые действиями пользователя и требующими обратной связи. В известной мере всплывающее уведомление является своего рода незатребованной обратной связью, сообщением, которое серверная часть посылает, когда становится доступной какая-то важная информация. Однако термин «незатребованный» (unsolicited) не совсем точен здесь. Любое мобильное приложение должно подписываться на доступный канал, чтобы получать всплывающие уведомления. После подписки на этот сервис уведомления поступают без явного запроса от приложения.

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

Крайне важный момент в том, что все технические аспекты всплывающих уведомлений жестко завязаны на конкретную платформу. Например, способ подписки на сервис передачи уведомлений отличается в приложениях iOS, Android, Windows Phone и Universal Windows Platform (UWP). Аналогично каждая платформа использует собственные данные при доставке сообщений подключенным устройствам, и на каждой платформе вы должны настраивать другой механизм диспетчеризации. Несмотря на существенные различия в реализациях, смею заметить, что в целом архитектура системы передачи уведомлений (push notification system, PNS) носит общий характер и выглядит, как на рис. 1.

Общая архитектура специфичной для платформ системы передачи уведомлений
Рис. 1. Общая архитектура специфичной для платформ системы передачи уведомлений

Application Back End Серверная часть приложения
2. Delivery 2. Доставка
Platform-Specific Notification Engine Механизм уведомлений, специфичный для платформы
3. Push 3. Передача
1. Registration 1. Регистрация
Devices Устройства

Работа с несколькими системами передачи уведомлений

Неудивительно, что многообразие мобильных платформ также отражается на многообразии платформ передачи уведомлений. Разработчик, создающий мобильное приложение для нескольких платформ, должен быть знаком с несколькими механизмами передачи уведомлений и уметь настраивать подходящую серверную среду для каждого из них. Если только вы не создаете приложение для одной мобильной платформы без намерений в обозримом будущем портировать его на другие платформы, вам может понадобиться изучить кросс-платформенные PNS (рис. 2). В сравнении с рис. 1 новая архитектура добавляет еще один уровень и предлагает единую входную точку для программирования.

Общая архитектура кросс-платформенной системы передачи уведомлений
Рис. 2. Общая архитектура кросс-платформенной системы передачи уведомлений

Application Back End Серверная часть приложения
2. Enqueuing 2. Постановка в очередь
Generic Platform Notification Engine Механизм передачи уведомлений, базовый для всех платформ
3. Delivery 3. Доставка
Platform-Specific Notification Engine Механизм передачи уведомлений, специфичный для конкретной платформы
1. Registration 1. Регистрация
4. Push 4. Передача
Devices Устройства

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

Одной из таких кросс-платформенных систем передачи уведомлений является Azure Notification Hub. Давайте посмотрим, как он работает.

Azure Notification Hub

Первый шаг в использовании Azure Notification Hub — настройка тарифного плана Azure. Сервис предлагается на трех уровнях, самый низкий из которых бесплатен и задает лимит на число устройств (500) и максимальное количество отправляемых вами уведомлений (1 миллион). Подробнее см. по ссылке bit.ly/1Tbimew. Чтобы приступить к работе, достаточно бесплатной учетной записи, которая позволяет создать Notification Hub и пространство имен внутри него. Эта информация пригодится впоследствии при установлении соединения из серверной части приложения для постановки сообщений в очередь для устройств.

Самая трудоемкая часть в использовании всплывающих уведомлений — это не работа с кросс-платформенным хабом, а соблюдение требований каждой мобильной платформы, которую вы хотите охватить. Например, чтобы доставить обновления на устройства iOS или Android, вы должны сначала полностью сконфигурировать ваши приложения с применением соответствующих «родных» PNS. Подробнее на эту тему см. по ссылке bit.ly/1o15uv2. Как вы, вероятно, знаете, только зарегистрированные iOS-приложения могут принимать всплывающие уведомления. Чтобы зарегистрировать ваше приложение в «родном Apple Push Notification Service, нужно сначала получить сертификат от Apple, который обеспечивает уникальную идентификацию уведомлений, поступающих от вашего приложения. Та же задача для Android требует вместо этого получить ключ API через интерфейс Android Studio. В случае UWP-приложений вы должны предварительно зарегистрироваться в Windows Store. Все операции, специфичные для платформ, следует выполнить для каждой платформы, которую вы намерены поддерживать. Любую полученную вами регистрационную информацию необходимо ввести в Azure Notification Hub, который будет действовать в ваших интересах при взаимодействии с «родными» PNS.

Регистрация приложения в хабе

Допустим, вы располагаете файлом сертификата .p12 и обновили профиль подготовки (provisioning profile) для своего iOS-приложения, которому разрешено принимать уведомления от системы Apple. На этом ваша предварительная работа по большей части была бы закончена, если бы вы не использовали Azure Notification Hub. Действительно ли надо применять промежуточную хаб-систему?

Дело в том, что любая специфичная для платформы PNS все равно оставляет уйму работы для разработчика в выполнении распространенных задач, таких как простое широковещание всем подключенным устройствам или только определенным группам пользователей, которые, допустим, используют устройство с конкретным локализующим идентификатором (locale). В частности, широковещание не является тривиальной задачей, так как может создавать непростые проблемы с масштабируемостью по мере роста числа устройств. Вот почему масштабируемая инфраструктура на промежуточном уровне, которая отделяет базовые сервисы, специфичные для платформы, от создаваемого вами кода, дает колоссальный выигрыш. Однако, чтобы задействовать Azure Notification Hub, вам также понадобится закачать сертификат Apple .p12 и программно зарегистрировать ваше приложение в Azure Hub. Если вы пишете iOS-приложения в Xamarin.iOS, рекомендую прочитать превосходное пошаговое руководство по ссылке bit.ly/1KaySJ3.

Мобильное приложение должно включать код, который, во-первых, обеспечивает подписку на канал уведомлений Azure, а во-вторых, каким-то образом обрабатывает любые входящие уведомления. iOS-приложение физически принимает всплывающие уведомления от сервиса Apple, поэтому оно должно подписаться на него. Это делается методом UIAppliction.SharedApplication.RegisterForRemoteNotifications. По завершении этот метод вызывает в классе делегата приложения переопределяемый метод RegisteredForRemoteNotifications. В нем вы подписываетесь на Azure Hub. Этот метод принимает маркер устройства от ОС, и ваш код просто пересылает его в Hub. Azure Hub идентифицируется по пути и строке подключения, например:

var hub = new SBNotificationHub(connectionString, hubPath);
hub.RegisterNativeAsync(deviceToken, null);

Затем, когда уведомление реально принято, вызывается другой переопределяемый метод в классе делегата приложения: ReceivedRemoteNotification. Этот метод принимает от ОС собственно контент переданного сообщения в виде строкового словаря (возможно, вложенного). Переопределение метода отвечает за извлечение самого сообщения и его вывод в любой форме, пригодной для данного приложения, — как эмблемы (badge), звукового сигнала или оповещения.

Постановка сообщений в очередь Azure Hub

Вся выполненная к данному моменту работа — это лишь половина того, что нужно проделать. Остается выяснить, как отправлять сообщения в Azure Hub и передавать их оттуда подключенным устройствам. Иначе говоря, у вас должна быть серверная часть приложения, которой известны детали соединения с Hub и которая передает сообщение для пользователя. Такая серверная часть может быть .NET-приложением любого вида, в том числе ASP.NET-приложением. Если у вас есть какие-то причины, связанные с бизнесом, для того, чтобы мобильное приложение принимало всплывающие уведомления, значит, что-то в предметной области бизнеса должно генерировать соответствующие сообщения. Это может быть какой-то программный триггер, посылающий сообщение, или действие пользователя с правами администратора, как показано на рис. 3.

Серверная часть на основе ASP.NET, которая посылает сообщения, специфичные для конкретных региональных настроек, в приложение iOS или Android через Azure Hub
Рис. 3. Серверная часть на основе ASP.NET, которая посылает сообщения, специфичные для конкретных региональных настроек, в приложение iOS или Android через Azure Hub

Чтобы включить поддержку всплывающих уведомлений в серверную часть на основе ASP.NET, достаточно установить Nuget-пакет Microsoft Azure NotificationHubs. Кроме того, ваш код отвечает за формирование подходящей строки подключения. Эта строка содержит информацию об URL конечной точки Azure Service Bus и зашифрованный маркер. Конечная точка Service Bus хранит имя пространства имен, созданного вами при подготовке сервиса Azure. Это нечто вроде sb://your-ns.servicebus.windows.net. Зашифрованный маркер считывается из страницы конфигурации вашего пространства имен под меткой «Connection String». Ниже показан код, необходимый для создания допустимого экземпляра Hub:

var hub = NotificationHubClient.CreateClientFromConnectionString(
  connString, hubName);

Следующий шаг заключается в создании корректных передаваемых данных для каждой нужной вам платформы. Передаваемые данные (payload) — это JSON-строка, которая следует фиксированному шаблону. Вы можете формировать такую строку любым способом. В следующем примере $ — это символ-заполнитель для реально отправляемого сообщения:

const string iosFormat = "{\"aps\":{\"alert\":\"$\"}}";
const string androidFormat = "{\"data\":{\"message\":\"$\"}}";
var iosAlert = iosFormat.Replace("$", actualMessage);
var androidAlert = androidFormat.Replace("$", actualMessage);

После формирования передаваемые данные посылаются Hub следующим кодом:

var task1 = hub.SendAppleNativeNotificationAsync(iosAlert);
var outcome1 = task1.Result;
var task2 = hub.SendGcmNativeNotificationAsync(androidAlert);
var outcome2 = task2.Result;

Переменные outcome в этом фрагменте кода являются экземплярами типа NotificationOutcome и возвращают детальную информацию о результате операции.

Отправка сообщений, основанных на шаблоне

В предыдущем примере кода показан простейший способ отправки всплывающих уведомлений: строка текста, которая в неизменном виде широковещательно передается всем подключенным устройствами. Более того, вы должны форматировать ее для каждой мобильной платформы. Гораздо более распространенный сценарий — передача сообщений, основанных на шаблоне. Сообщение, основанное на шаблоне, доставляется в Azure в форме словаря строк, а Azure Hub гарантирует его доставку любой мобильной платформе, сконфигурированной в учетной записи. Ключевая идея сообщений, основанных на шаблоне, состоит в том, что приложение использует более богатый формат, чем по умолчанию. Например, рассмотрим, как посылать разные сообщения пользователям с разными локализующими идентификаторами (locales):

var locale = "EN";
var template = String.Format("{{\"aps\":{{\"alert\":\"$(News_{0})\"}}}}", locale);

В этом примере показан шаблон, который регистрирует в Apple PNS любое входящее сообщение на основе шаблона с именем News_XX, где XX — две начальные буквы locale. Здесь удобство шаблонов в том, что серверная часть приложения может посылать несколько записей в одном словаре, но каждое устройство принимает только то сообщение, на которое оно зарегистрировано. Это просто один из дополнительных сервисов промежуточного хаба вроде Azure Notification Hub. Чтобы отправлять сообщения, специфичные для локализующего идентификатора, вы должны написать следующий код:

var messages = new Dictionary<string, string>
{
  {"News_EN", "..."},
  {"News_ES", "..."},  {"News_PT", "..."},
  {"News_IT", "..."}
};var task = hub.SendTemplateNotificationAsync(messages);
var outcome = task.Result;

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

Запланированные сообщения

Другая интересная функция Azure Notification Hub — поддержка запланированных сообщений. Такие сообщения являются уведомлениями, доставляемыми в Azure, но отправляемыми подключенным устройствам только в заданное время. Для передачи запланированных уведомлений вы просто используете несколько другой API:

var notification = new TemplateNotification(messages);
var task = hub.ScheduleNotificationAsync(notification, new DateTime(...));
var outcome = task.Result;

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

Заключение

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

Вам не следует круглосуточно досаждать пользователю чисто информационными уведомлениями. Поскольку это уведомление всплывающее, вы должны быть уверены, что оно действительно интересно пользователю. В этом отношении сегментация пользователей на группы — отличная функция, на которую можно положиться. Размер сообщения тоже имеет значение. Я предлагаю соблюдать размер любого сообщения близко к длине твита. Например, до появления iOS 8 максимальный размер всплывающих уведомлений был 256 байт, а в более новых системах вырос до 2 Кб. В Android ограничение составляет 4 Кб. Наконец, важно удостовериться, что целевая ОС позволяет легко отказаться от этой функциональности.


Дино Эспозито (Dino Esposito) — соавтор книг «Microsoft .NET: Architecting Mobile Applications Solutions for the Enterprise» (Microsoft Press, 2014) и «Modern Web Applications with ASP.NET» (Microsoft Press, 2016). Идеолог в области технологий для платформ .NET и Android в JetBrains. Часто выступает на конференциях по всему миру, делится своим видением ПО на software2cents.wordpress.com и пишет заметки в Twitter (@despos).

Выражаю благодарность за рецензирование статьи эксперту Microsoft Джону Арни Сетерасу (Jon Arne Saeteras).


Discuss this article in the MSDN Magazine forum