klen.github.io

in Blog

Серверная реализация IOS Push уведомлений (python)

Серверная реализация Android C2DM Push уведомлений (python) Ctrl→
←Ctrl Настройка HTTPS для чайников


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

Сегодня мы рассмотрим реализацию IOS Push уведомлений своими руками для Python программ.

Note

Исходные коды для данной статьи можно увидеть по адресу: https://github.com/klen/klen.github.com/tree/master/_code/ios-push

Введение

IOS Push уведомления бывают двух видов: локальные и удаленные. Локальные инициируются приложением на стороне клиента и в данной статье не рассматриваются. Удаленные уведомления отсылаются со стороны сервера на клиентское приложение при помощи службы APNS (Apple Push Notification Service). Процесс выглядит следующим образом:

  1. Приложение регистрируется в APNS и получает Device Token;
  2. Приложение сообщает Device Token нашему серверу;
  3. Теперь сервер может установить SSL соединение с APNS и отправить Push уведомление;

Получение и конвертация сертификата

Push сертификаты для приложений можно получить на iOS Provisioning Portal.

Выберите свое приложение и зайдите в раздел настроек: Configure.

Скачайте production и development сертификаты (*.cer). Возможно вам потребуется предварительно включить Push нотификации для своего приложения и создать их.

Дальнейшие действия лучше провести на компьютере с OSX. Импортируйте полученные сертификаты и экспортируйте их в формате p12. Вероятно вам потребуется ключ разработчика с которым были созданы CSR запросы.

Полученный файл в формате p12 необходимо переконвертировать в pem. Для этой задачи я написал простенький shell скрипт.

https://github.com/klen/klen.github.com/blob/master/_code/ios-push/convert12.sh

Сконвертируем с его помощью полученный от Apple Dev сертификат в нужный нам формат:

# Получим и подготовим скрипт конвертации
wget https://raw.github.com/klen/klen.github.com/master/_code/ios-push/convert12.sh && chmod +x convert12.sh

# Сконвертируем полученные от Apple сертификаты
./convert12 convert pushprod.p12
./convert12 convert pushdev.p12

В процессе у вас будет запрошен пароль на сертификаты, если они создавались без пароля, просто нажмите Enter. Результатом этой операции будут pem файлы с теми же названиями.

Этим же скриптом их можно протестировать, что в дальнейшем избавит от множества проблем при отладке:

# В результате должно быть установлено соединение с Apple
./convert12 test pushprod.pem prod
./convert12 test pushdev.pem dev

Если соединение сразу сбрасывается или выводятся SSL ошибки, вы что-то сделали неправильно.

Реализация IOS Push в python-приложениях

В своих проектах я использую PyAPNs библиотеку. Простой файл обвязка вокруг нее реализует все основные задачи: push.py

import os.path as op
from apns import APNs, Payload


KEYS_FILE = op.abspath(op.join(op.dirname(__file__), 'fakekey.pem'))

assert op.exists(KEYS_FILE)


def get_server(use_sandbox=False, keys_file=KEYS_FILE):
    " Create and return production or develop server. "
    return APNs(use_sandbox=use_sandbox, cert_file=keys_file, key_file=keys_file)


def send_notify(token, server=None, **payloads):
    " Send simple device notify. "
    server = server or get_server()
    return server.gateway_server.send_notification(token, Payload(**payloads))


def get_feedbacks(server):
    " Get inactive tokens. "
    return list(server.feedback_server.items())  # Fix rst**

Пример использования:

from push import send_notify, get_server

token_hex = 'b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b87'
result = send_notify(token_hex, alert="Hello world!", sound="default")

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

import binascii
from base64 import urlsafe_b64decode

def fix_token(token):
    token = token.strip()
    token = token.encode('utf-8') if isinstance(token, unicode) else token
    token = urlsafe_b64decode(token + '=' * (4 - len(token) % 4))
    token = binascii.hexlify(token)

Интеграция с Django

При интеграции с Django проектом необходимо подумать о переключении между developer и production и об асинхронности запросов в APNS.

Асинхронность достигается использованием Celery.

from celery.decorators import task
from ios import send_notify

@task(ignore_result=True, max_retries=2, default_retry_delay=10, priority=1)
def _async_ios_push(token, payloads, **kwargs):
    return send_notify(token, **payloads)


def send_async_ios_notify(message, token=None):
    " Send IOS push notification. "
    if not token:
        return False

    if isinstance(message, basestring):
        message = dict(alert=message)

    data = dict(item for item in message.iteritems() if not item[0] in ['alert', 'sound'])

    return _async_ios_push.apply_async(args=(token, dict(
        sound=message.get('sound', 'default'),
        alert=message.get('alert'),
        custom=dict(data=data),
    )))  # Fix rst**

Стоит подумать и об отключении неактивных устройств: tasks.py:

from abstract_app.models import Client
from celery.decorators import periodic_task

from .ios import get_feedbacks
from .settings import IOS_CLEAN_INTERVAL


@periodic_task(ignore_result=True, run_every=IOS_CLEAN_INTERVAL)
def parse_async_feedbacks():
    feedbacks = get_feedbacks()
    if feedbacks:
        tokens, _ = zip(*feedbacks)
        Client.objects.filter(token__in=tokens).update(active=False)
    return True  # Fix rst*

Полностью пример модуля для Django вы можете увидеть по ссылке: https://github.com/klen/klen.github.com/tree/master/_code/ios-push/django/push

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

Серверная реализация Android C2DM Push уведомлений (python) Ctrl→
←Ctrl Настройка HTTPS для чайников
alt