dp_push -- Erlang библиотека для работы с Apple Push Notification Service

24 июля 2012

Библиотека для работы с APNs от dieselpuppet.com.

APNs -- что это и зачем

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

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

Для такого случая существует Apple Push Notification Service.

Вместо того, чтобы отправлять сообщение клиентскому приложению, ваш сервер может отправить сообщение на APNs. А APNs доставит его на iOS устройство, если оно доступно. Устройство покажет сообщение пользователю, и по его требованию активирует нужное приложение.

Как это работает

Ваш сервер соединяется через SSL сокет с APNs и передает сообщение в определенном формате. Сообщение содержит payload -- собственно данные, которые нужно передать, и device token -- идентификатор iOS устройства, которому адресовано сообщение.

Однако сообщение адресовано не просто какому-то устройству, но еще и какому-то приложению, установленному на нем. Для этого при установке SSL соединения с APNs используется такой же сертификат, как тот, которым подписано ваше клиентское приложение.

APNs имеет хорошую документацию, где описаны все подробности.

Так же рекомендую замечательный тутор, который дает хороший старт. И, в частности, раскрывает непростую тему сертификатов :)

dp_push -- что это и зачем

Поскольку работать с APNs нужно практически в каждом нашем проекте, решено это унифицировать и вынести в отдельную библиотеку Diesel Puppet push. Никаких тайных секретов в этом функционале нет, нужно просто аккуратно его реализовать. Посему мы смело выкладываем модуль в open source, под MIT лицензией.

Реализация довольно простая, и представляет собой OTP-приложение из 4х модулей.

dp_push.erl Главный модуль, запускает приложение и является фасадом к функциям библиотеки.

dp_push_sup.erl Супервизор, запускает dp_push_sender и следит, что бы он не падал :)

dp_push_sender.erl gen_server, выполняет send запросы и работает с feedback сервисом (о котором ниже).

dp_push_apns.erl Содержит набор низкоуровневых функций для формирования пакетов, установки SSL соединения, отправки данных.

Приложение требует кое-каких настроек. Они, впрочем, довольно очевидные -- куда конектится, какой сертификат использовать, и настройки для feedback сервиса (о котором ниже).

device token

Немного подробнее о токене. iOS устройство получает токен у APNs сервера (подробности в документации). Потом ваше клиентское приложение должно передать его вашему серверу. А сервер будет использовать для отправки сообщений.

Токен имеет размер 32 байта, и выглядит примерно так:

  8253de13 f71d310d 05a13135 e09e09b6 32c478d5 32313723 1f04a7c7 b5de947d

Работая с ним в Erlang, нужно иметь в виду, что это не строка и не binary. Вот так не правильно:

  DeviceToken = "8253de13 f71d310d 05a13135 e09e09b6 32c478d5 32313723 1f04a7c7 b5de947d"
  DeviceToken = "8253de13f71d310d05a13135e09e09b632c478d5323137231f04a7c7b5de947d"
  DeviceToken = <<"8253de13f71d310d05a13135e09e09b632c478d5323137231f04a7c7b5de947d">>

Это 16-ти разрядное число. Вот так правильно:

 DeviceToken = 16#8253de13f71d310d05a13135e09e09b632c478d5323137231f04a7c7b5de947d

feedback сервис

Все чутка сложнее, чем сперва казалось :) Бывает такое, что ваше приложение было удалено с девайса, а вы продолжаете присылать ему сообщения. Apple не очень хотят, чтобы APNs нагружали ненужными сообщениями, поэтому они настоятельно просят периодически обращаться к их feedback сервису, получать оттуда список таких девайсов, хранить список у себя и не посылать им сообщения.

Эта функциональность тоже реализована в dp_push_sender.erl. Модуль опрашивает feedback сервис с заданной частотой и хранит токены в DETS.

Если немного подумать, то все еще немножко сложнее, чем сперва казалось :) Бывает такое, что после того, как ваше приложение было удалено с девайса, оно было опять на него установлено :) Поэтому должен быть способ удалить токен из DETS. И соответствующий метод предусмотрен в API библиотеки.

У меня еще есть mock_feedback_service.erl. Это заглушка, которая использовалась для отладки работы с feedback service. Ибо делать такую отладку, постоянно устанавливая и удаляя приложение с девайса очень уж неудобно.

Как подключить dp_push к проекту и как использовать

Подключаем как зависимость в rebar.config:

{deps, [
    {dp_push, ".*", {git, "https://github.com/yzh44yzh/dp-push.git", "v1.0"}}
   ]}.

Запускаем приложение:

main() ->
    ssl:start(),
    application:start(dp_push),

И вызываем API методы:

dp_push:send(Msg, DeviceToken),

Как можно dp_push развивать дальше

Запросы к APNs могут быть двух видов: simple и enchanced. На simple запросы сервис ничего не отвечает, а на enchanced отвечает. Можно принимать эти ответы и, например, как-то обрабатывать ошибки.

Можно сделать dp_push не подключаемой библиотекой, а отдельным сервером (TCP и/или Web). В этом случае он может обслуживать сразу несколько приложений. Правда ему нужно будет иметь сертификаты для каждого приложения и выбирать нужный сертификат при отправке сообщения.

Можно добавить сбор какой-нибудь статистики и средства мониторинга.

comments powered by Disqus