Теплым летним вечером, в процессе разработки очередного приложения для iOS, у меня совпало два фактора — возникла необходимость реализации Apple Push Notification (APN) и желание попробовать что-то совсем новое для меня. Идти проторенной дорогой через один из множества сервисов, предлагающих отправку APN не хотелось.

Для изобретения велосипеда был выбран Amazon Simple Notification Service (Amazon SNS). Amazon SNS — это сервис, который позволяет вам отправлять сообщения-нотификации, посредством разнообразных механизмов (APN, GCM, e-mail, SMS и т.д.).

О том, как это работает и более подробную информацию можно прочитать в документации Amazon. Я расскажу совсем немного, чтобы определиться с дальнейшей терминологией. У SNS есть два типа клиентов — публикаторы (publishers) и подписчики (subscribers). Публикаторы с подписчиками асинхронно обмениваются сообщениями (messages), которые доставляются подписчикам, посредством разнообразных механизмов. Для отправки групповых сообщений подписчики могут быть сгруппированы по темам (topics). Тогда все подписчики, подписанные на тему, получат сообщение в эту тему отправленное.

Картинка из документации Amazon:
image

Поскольку тема данной статьи — работа с сервисом SNS из iOS, подробно на бекенде останавливаться не будем. Скажу несколько предложений.
В рамках изобретения велосипеда бекенд был написан с использованием следующих технологий:

  • Java 1.8;
  • Spring Boot 1.2.4;
  • Maven 3.3;
  • AWS SDK for Java 1.10.1.

Я являюсь программистом на Objective C/Swift, поэтому все это добро, включая Java, я в этом проекте использовал можно сказать впервые. Проект PushSnsSender выложил на GitHub. Во-первых, может кому-нибудь пригодится; а во-вторых, был бы очень рад push-реквестам.

Данный код поднимает веб-сервис, который на ваш POST-запрос вида:

{"topic": "arn:aws:sns:YOUR-TOPIC", "message": "Hooray!", "badge": 0, "sound": "bingbong.aiff", "isDebug": false }

Отправит APN “Hooray!” на SNS-тему “YOUR-TOPIC”.

Как бы то ни было, не ради бекенда я затевал эту статью. Все дело в том, что механизм подписки на топик из iOS приложения несправедливо обойден вниманием в документации Amazon, а именно на нем я хочу остановиться. Возможно кому-то это сэкономит драгоценные часы времени.

Перед тем как приступить к программированию, в консоли AWS нужно выполнить следующие действия:

  • активация сервиса AWS SNS;
  • активация сервиса AWS Cognito;
  • создание Platform Application в сервисе SNS и привязка ключей Apple для работы с APN;
  • создание новой темы для сервиса SNS;
  • создание Identity Pool и привязанной к нему роли для сервиса Cognito.

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

Окно создания Platform Application:
image

Окно создания новой темы:
image

Окно создания нового Identity Pool:
image

Немного задержимся на сервисе Cognito. Что это и зачем он нужен?

Как вы понимаете, с вашим уютным AWS не должно быть разрешено работать кому попало. За строгую авторизацию в AWS отвечает сервис Identity and Access Management, который каждому пользователю выдает ключи авторизации. Ключи авторизации, состоящие из Access Key Id и Secret Access Key — очень интимная штука, которая при попадании в неправильные руки может причинить вашему аккаунту AWS и вашему кошельку много-много бед. Поэтому никогда и не при каких обстоятельствах не садитесь в машину к незнакомым дядям не отдавайте ключи AWS.

Вместе с этим ваше iOS приложение на телефонах пользователей должно как-то авторизовываться в AWS, чтобы подписаться на тему. Тут на помощь нам приходит сервис AWS Cognito — одной из функций которого является аутентификация пользователей и назначение им определенной роли. Работать с сервисом достаточно просто. После создания нового Identity Pool, сервис сам сгенерит вам код, который надо использовать в вашем iOS приложении.

Окно нового Identity Pool и сгенерированного кода:
image

Вводные операции закончены и наконец можно перейти к любимой части — написанию кода.
Для работы с сервисами Amazon из нашего iOS приложения нам потребуется AWS SDK for iOS, а точнее три компонента оттуда: AWSCore; AWSSNS и AWSCognito. Для установки воспользуемся любимым менеджером пакетов, например для CocoaPods это будет выглядеть так:
pod 'AWSCore', '~> 2.2' pod 'AWSSNS', '~> 2.2' pod 'AWSCognito', '~> 2.2'

Настало время самого интересного — ответа на вопрос: “Как из нашего iOS приложения подписаться на тему SNS?” Документация Amazon предложит нам решение в виде регистрации отдельного устройство и отправки сообщения на него, что для массовой рассылки абсолютно не подходит. Поэтому после авторизации с помощью кода, сгенеренного сервисом Cognito, мы просто вызовим API сервиса SNS и подпишемся на тему вручную.
Код вызова приведен ниже:

- (void)subscribeToPushTopicWithDeviceToken:(NSData *)deviceToken 
{
    
    AWSSNS *sns = [AWSSNS defaultSNS];

    AWSSNSCreatePlatformEndpointInput *endpointRequest = [AWSSNSCreatePlatformEndpointInput new];
    
    //get some device's IDs
    NSString *userDeviceName = [[UIDevice currentDevice] name];
    NSString *userDevicePlatform = [[UIDevice currentDevice] model];
    
    //get SNS settings 
    self.myPlatformApplicationArn = @"arn:aws:sns:us-east-1:XXXXXXXXXXXXX:app/APNS/XXXXXXXXXXXXX";
    self.myTopicArn = @"arn:aws:sns:us-east-1:XXXXXXXXXXXXX:XXXXXXXXXXXXX";

    endpointRequest.platformApplicationArn = self.myPlatformApplicationArn;
    endpointRequest.token = [self deviceTokenAsString:deviceToken];
    endpointRequest.customUserData = [NSString stringWithFormat:@"%@ - %@", userDevicePlatform, userDeviceName];

    [[[sns createPlatformEndpoint:endpointRequest] continueWithSuccessBlock:^id(AWSTask *task) {

        AWSSNSCreateEndpointResponse *response = task.result;

        AWSSNSSubscribeInput *subscribeRequest = [AWSSNSSubscribeInput new];

        subscribeRequest.endpoint = response.endpointArn;
        subscribeRequest.protocols = @"application";
        subscribeRequest.topicArn = self.myTopicArn;

        return [sns subscribe:subscribeRequest];

    }] continueWithBlock:^id(AWSTask *task) {

        if (task.cancelled) {
            NSLog(@"AWS SNS Task cancelled!");
        }

        else if (task.error) {
            NSLog(@"%s file: %s line: %d - AWS SNS Error occurred: [%@]", __FUNCTION__, __FILE__, __LINE__, task.error);
        }

        else {
            NSLog(@"AWS SNS Task Success.");
        }

        return nil;

    }];
    
}

Вот и все. После успешного запуска приложения в консоли AWS вы увидите одно авторизованное устройство в Identity Pool сервиса Cognito и ваше устройство в качестве подписчика на тему:

Экран с отоброжением устройства, подписанного на тему:
image

Обратите внимание на различие ключей Apple для работы с APN в среде разработки и продуктивной среде.

Файлы Objective C:

BGMAwsSnsProvider.h
BGMAwsSnsProvider.m

Спасибо за внимание. Надеюсь, данная статья сэкономила вам хоть сколько-нибудь времени и подтолкнула обратить внимание на такой замечательный сервис как Amazon SNS.

Комментарии (3)


  1. InstaRobot
    02.11.2015 15:31

    В начале статьи, слово «преложения» поправьте плиз. Я не филолог, но статьи с Хабра очень быстро идут в индекс поисковых систем


  1. bigMOTOR
    02.11.2015 15:49

    InstaRobot Как же я просмотрел-то… Поправил. Спасибо!


    1. InstaRobot
      02.11.2015 15:52

      Под заголовком статьи иконка «гаечный ключ» у Вас должна быть. Чуть выше тегов и правее.