Руководство: отправка push-уведомлений на определенные устройства iOS с помощью службы Центры уведомлений Azure

Обзор

В этом руководстве показано, как использовать службу "Центры уведомлений Azure" для рассылки уведомлений об экстренных новостях в приложение iOS. По завершении вы сможете зарегистрироваться в интересующих вас категориях экстренных новостей и получать push-уведомления только для этих категорий. Этот сценарий часто используется во многих приложениях, которые отправляют уведомления определенным группам пользователей, подтвердившим интерес к этим уведомлениям. Типичные примеры: средства чтения RSS, приложения для любителей музыки и т. д.

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

При работе с этим руководством вы выполните следующие задачи:

  • добавление возможности выбора категорий в приложение;
  • Отправка уведомлений с тегами
  • отправка уведомлений с устройства;
  • Запуск приложения и создание уведомлений

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

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

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

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

  1. В вашем MainStoryboard_iPhone.storyboard добавьте следующие компоненты из библиотеки объектов:

    • метка с текстом "Экстренные новости";

    • метки с текстами категории "Мир", "Политика", "Бизнес", "Технология", "Наука", "Спорт";

    • Шесть переключателей, по одному в каждой категории. Задайте для каждого переключателя Состояние по умолчанию Off (Откл.).

    • Одна кнопка с надписью «Подписка».

      Раскадровка должна выглядеть следующим образом:

      Конструктор интерфейса Xcode

  2. В редакторе помощника создайте выходы для всех переключателей и назовите их WorldSwitch, PoliticsSwitch, BusinessSwitch, TechnologySwitch, ScienceSwitch, SportsSwitch.

  3. Создайте действие для кнопки subscribe. Ваш ViewController.h должен содержать следующий код.

    @property (weak, nonatomic) IBOutlet UISwitch *WorldSwitch;
    @property (weak, nonatomic) IBOutlet UISwitch *PoliticsSwitch;
    @property (weak, nonatomic) IBOutlet UISwitch *BusinessSwitch;
    @property (weak, nonatomic) IBOutlet UISwitch *TechnologySwitch;
    @property (weak, nonatomic) IBOutlet UISwitch *ScienceSwitch;
    @property (weak, nonatomic) IBOutlet UISwitch *SportsSwitch;
    
    - (IBAction)subscribe:(id)sender;
    
  4. Создайте класс Cocoa Touch Class с именем Notifications. Скопируйте следующий код в интерфейсную часть файла Notifications.h:

    @property NSData* deviceToken;
    
    - (id)initWithConnectionString:(NSString*)listenConnectionString HubName:(NSString*)hubName;
    
    - (void)storeCategoriesAndSubscribeWithCategories:(NSArray*)categories
                completion:(void (^)(NSError* error))completion;
    
    - (NSSet*)retrieveCategories;
    
    - (void)subscribeWithCategories:(NSSet*)categories completion:(void (^)(NSError *))completion;
    
  5. Добавьте следующую директиву импорта в Notifications.m:

    #import <WindowsAzureMessaging/WindowsAzureMessaging.h>
    
  6. Скопируйте следующий код в раздел файла Notifications.m, в котором запрограммирована реализация.

    SBNotificationHub* hub;
    
    - (id)initWithConnectionString:(NSString*)listenConnectionString HubName:(NSString*)hubName{
    
        hub = [[SBNotificationHub alloc] initWithConnectionString:listenConnectionString
                                    notificationHubPath:hubName];
    
        return self;
    }
    
    - (void)storeCategoriesAndSubscribeWithCategories:(NSSet *)categories completion:(void (^)(NSError *))completion {
        NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
        [defaults setValue:[categories allObjects] forKey:@"BreakingNewsCategories"];
    
        [self subscribeWithCategories:categories completion:completion];
    }
    
    - (NSSet*)retrieveCategories {
        NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
    
        NSArray* categories = [defaults stringArrayForKey:@"BreakingNewsCategories"];
    
        if (!categories) return [[NSSet alloc] init];
        return [[NSSet alloc] initWithArray:categories];
    }
    
    - (void)subscribeWithCategories:(NSSet *)categories completion:(void (^)(NSError *))completion
    {
        NSString* templateBodyAPNS = @"{\"aps\":{\"alert\":\"$(messageParam)\"}}";
    
        [hub registerTemplateWithDeviceToken:self.deviceToken name:@"simpleAPNSTemplate" 
            jsonBodyTemplate:templateBodyAPNS expiryTemplate:@"0" tags:categories completion:completion];
    }
    

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

  7. В файле AppDelegate.h добавьте оператор импорта для Notifications.h и свойство для экземпляра класса Notifications.

    #import "Notifications.h"
    
    @property (nonatomic) Notifications* notifications;
    
  8. В методе didFinishLaunchingWithOptions в AppDelegate.m добавьте в начало метода код для инициализации экземпляра уведомления.
    В HUBNAME и HUBLISTENACCESS (определены в hubinfo.h) заполнители <hub name> и <connection string with listen access> необходимо заменить именем центра уведомлений и строкой подключения для DefaultListenSharedAccessSignature, полученными раньше.

    self.notifications = [[Notifications alloc] initWithConnectionString:HUBLISTENACCESS HubName:HUBNAME];
    

    Примечание

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

  9. В методе didRegisterForRemoteNotificationsWithDeviceToken в AppDelegate.m замените код в методе следующим кодом, чтобы переместить маркер устройства в класс notifications. Класс notifications выполняет регистрацию для уведомлений с категориями. Если пользователь меняет выбранные категории, для их обновления будет вызван метод subscribeWithCategories в ответ на действие кнопки subscribe.

    Примечание

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

    self.notifications.deviceToken = deviceToken;
    
    // Retrieves the categories from local storage and requests a registration for these categories
    // each time the app starts and performs a registration.
    
    NSSet* categories = [self.notifications retrieveCategories];
    [self.notifications subscribeWithCategories:categories completion:^(NSError* error) {
        if (error != nil) {
            NSLog(@"Error registering for notifications: %@", error);
        }
    }];
    

    На этом этапе в методе didRegisterForRemoteNotificationsWithDeviceToken не должно быть никакого другого кода.

  10. Изучив статью Руководство по отправке push-уведомлений в приложения iOS с помощью Центров уведомлений Azure, в файле AppDelegate.m должны присутствовать указанные методы. В противном случае добавьте их.

    - (void)MessageBox:(NSString *)title message:(NSString *)messageText
    {
    
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:messageText delegate:self
            cancelButtonTitle:@"OK" otherButtonTitles: nil];
        [alert show];
    }
    
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:
       (NSDictionary *)userInfo {
       NSLog(@"%@", userInfo);
       [self MessageBox:@"Notification" message:[[userInfo objectForKey:@"aps"] valueForKey:@"alert"]];
     }
    

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

  11. В ViewController.m добавьте оператор import для AppDelegate.h и скопируйте следующий код в созданный с помощью XCode метод subscribe. Этот код обновляет регистрацию уведомлений для использования тегов новой категории, которые пользователь выбрал в пользовательском интерфейсе.

    #import "Notifications.h"
    
    NSMutableArray* categories = [[NSMutableArray alloc] init];
    
    if (self.WorldSwitch.isOn) [categories addObject:@"World"];
    if (self.PoliticsSwitch.isOn) [categories addObject:@"Politics"];
    if (self.BusinessSwitch.isOn) [categories addObject:@"Business"];
    if (self.TechnologySwitch.isOn) [categories addObject:@"Technology"];
    if (self.ScienceSwitch.isOn) [categories addObject:@"Science"];
    if (self.SportsSwitch.isOn) [categories addObject:@"Sports"];
    
    Notifications* notifications = [(AppDelegate*)[[UIApplication sharedApplication]delegate] notifications];
    
    [notifications storeCategoriesAndSubscribeWithCategories:categories completion: ^(NSError* error) {
        if (!error) {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:"Notification" message:"Subscribed" delegate:self
            cancelButtonTitle:@"OK" otherButtonTitles: nil];
            [alert show];
        } else {
            NSLog(@"Error subscribing: %@", error);
        }
    }];
    

    Этот метод создает NSMutableArray категорий и использует класс Notifications для хранения списка в локальном хранилище и регистрации соответствующих тегов в концентраторе уведомлений. При изменении категорий регистрация создается заново с новыми категориями.

  12. В файле ViewController.m добавьте следующий код в метод viewDidLoad, чтобы задать пользовательский интерфейс на основе ранее сохраненных категорий.

    // This updates the UI on startup based on the status of previously saved categories.
    
    Notifications* notifications = [(AppDelegate*)[[UIApplication sharedApplication]delegate] notifications];
    
    NSSet* categories = [notifications retrieveCategories];
    
    if ([categories containsObject:@"World"]) self.WorldSwitch.on = true;
    if ([categories containsObject:@"Politics"]) self.PoliticsSwitch.on = true;
    if ([categories containsObject:@"Business"]) self.BusinessSwitch.on = true;
    if ([categories containsObject:@"Technology"]) self.TechnologySwitch.on = true;
    if ([categories containsObject:@"Science"]) self.ScienceSwitch.on = true;
    if ([categories containsObject:@"Sports"]) self.SportsSwitch.on = true;
    

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

(Необязательно.) Отправка уведомлений с тегами

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

В этом разделе вы будете отправлять экстренные новости в виде шаблонных уведомлений с тегами из консольного приложения .NET.

  1. Создайте в Visual Studio новое консольное приложение Visual C#.

    1. В меню выберите Файл>Создать>Проект.
    2. В окне Создание проекта выберите в списке шаблонов Консольное приложение (.NET Framework) для C# и нажмите кнопку Далее.
    3. Введите имя приложения.
    4. Для параметра Решение, выберите Добавить к решению и Создать, чтобы создать проект.
  2. Выберите Инструменты>Диспетчер пакетов NuGet>Консоль диспетчера пакетов, а затем в окне консоли выполните следующую команду:

    Install-Package Microsoft.Azure.NotificationHubs
    

    Это действие добавляет ссылку на пакет SDK для Центров уведомлений Azure с помощью пакета Microsoft.Azure.NotificationHubs.

  3. Откройте файл Program.cs и добавьте следующий оператор using:

    using Microsoft.Azure.NotificationHubs;
    
  4. В класс Program добавьте следующий метод или замените его, если он уже существует:

    private static async void SendTemplateNotificationAsync()
    {
        // Define the notification hub.
        NotificationHubClient hub = NotificationHubClient.CreateClientFromConnectionString("<connection string with full access>", "<hub name>");
    
        // Apple requires the apns-push-type header for all requests
        var headers = new Dictionary<string, string> {{"apns-push-type", "alert"}};
    
        // Create an array of breaking news categories.
        var categories = new string[] { "World", "Politics", "Business", "Technology", "Science", "Sports"};
    
        // Send the notification as a template notification. All template registrations that contain
        // "messageParam" and the proper tags will receive the notifications.
        // This includes APNS, GCM/FCM, WNS, and MPNS template registrations.
    
        Dictionary<string, string> templateParams = new Dictionary<string, string>();
    
        foreach (var category in categories)
        {
            templateParams["messageParam"] = "Breaking " + category + " News!";
            await hub.SendTemplateNotificationAsync(templateParams, category);
        }
    }
    

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

  5. В предыдущем коде замените заполнители <hub name> и <connection string with full access> именем центра уведомлений и строкой подключения для DefaultFullSharedAccessSignature, полученными ранее на панели мониторинга центра уведомлений.

  6. Добавьте следующие строки в метод Main():

     SendTemplateNotificationAsync();
     Console.ReadLine();
    
  7. Выполните сборку консольного приложения.

(Необязательно.) Отправка уведомлений с устройства

Как правило, уведомления отправляются серверной службой, но вы можете отправлять уведомления об экстренных новостях непосредственно из приложения. Для этого обновите метод SendNotificationRESTAPI, определенный в руководстве по началу работы со службой "Центры уведомлений".

  1. В файле ViewController.m обновите метод SendNotificationRESTAPI, как показано ниже, чтобы он принимал параметр для тега категории и отправлял правильное шаблонное уведомление.

    - (void)SendNotificationRESTAPI:(NSString*)categoryTag
    {
        NSURLSession* session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration
                                    defaultSessionConfiguration] delegate:nil delegateQueue:nil];
    
        NSString *json;
    
        // Construct the messages REST endpoint
        NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@/messages/%@", HubEndpoint,
                                            HUBNAME, API_VERSION]];
    
        // Generated the token to be used in the authorization header.
        NSString* authorizationToken = [self generateSasToken:[url absoluteString]];
    
        //Create the request to add the template notification message to the hub
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        [request setHTTPMethod:@"POST"];
    
        // Add the category as a tag
        [request setValue:categoryTag forHTTPHeaderField:@"ServiceBusNotification-Tags"];
    
        // Template notification
        json = [NSString stringWithFormat:@"{\"messageParam\":\"Breaking %@ News : %@\"}",
                categoryTag, self.notificationMessage.text];
    
        // Signify template notification format
        [request setValue:@"template" forHTTPHeaderField:@"ServiceBusNotification-Format"];
    
        // JSON Content-Type
        [request setValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    
        //Authenticate the notification message POST request with the SaS token
        [request setValue:authorizationToken forHTTPHeaderField:@"Authorization"];
    
        //Add the notification message body
        [request setHTTPBody:[json dataUsingEncoding:NSUTF8StringEncoding]];
    
        // Send the REST request
        NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request
                    completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
            {
            NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response;
                if (error || httpResponse.statusCode != 200)
                {
                    NSLog(@"\nError status: %d\nError: %@", httpResponse.statusCode, error);
                }
                if (data != NULL)
                {
                    //xmlParser = [[NSXMLParser alloc] initWithData:data];
                    //[xmlParser setDelegate:self];
                    //[xmlParser parse];
                }
            }];
    
        [dataTask resume];
    }
    
  2. В файле ViewController.m обновите действие Send Notification, как показано в указанном ниже коде. Таким образом, он будет отправлять уведомления на несколько платформ, используя отдельно каждый тег.

    - (IBAction)SendNotificationMessage:(id)sender
    {
        self.sendResults.text = @"";
    
        NSArray* categories = [NSArray arrayWithObjects: @"World", @"Politics", @"Business",
                                @"Technology", @"Science", @"Sports", nil];
    
        // Lets send the message as breaking news for each category to WNS, FCM, and APNS
        // using a template.
        for(NSString* category in categories)
        {
            [self SendNotificationRESTAPI:category];
        }
    }
    
  3. Повторно создайте проект и убедитесь, что у вас не возникли ошибки сборки.

Запуск приложения и создание уведомлений

  1. Нажмите кнопку Запуск для построения проекта, после чего запустите приложение. Чтобы подписаться на некоторые экстренные новости, нажмите кнопку Подписаться . В появившемся диалоговом окне отобразятся те уведомления, на которые была настроена подписка.

    Пример уведомления в iOS

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

  2. Введите сообщение, отправляемое в качестве экстренных новостей, и нажмите кнопку Отправить уведомление . Можно также запустить консольное приложение .NET для создания уведомлений.

    Настройка параметров уведомлений в iOS

  3. Каждое устройство с подпиской на экстренные новости получает отправленные вами уведомления об экстренных новостях.

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

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