Создание приложений, работающих в режиме реального времени, с помощью служб Mobile Services и Pusher

Для знакомства с возможностями платформы  вы можетеактивировать Microsoft Azure бесплатно!

Тема практической работы — добавление функции работы в режиме реального времени в приложение, использующее службы Microsoft Azure Mobile Services. После выполнения этой практической работы данные TodoList будут синхронизироваться в режиме реального времени со всеми выполняемыми экземплярами вашего приложения.

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

Pusher — это облачная служба, которая наряду с Mobile Services позволяет невероятно легко создавать приложения, работающие в режиме реального времени. Вы можете использовать Pusher для быстрого создания интерактивных опросов, комнат чатов, многопользовательских игр, приложений для совместной работы, а также для трансляции актуальных данных и содержимого. И это только малая толика возможностей Pusher! Дополнительные сведения см. на странице http://pusher.com.

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

  1. Создание учетной записи Pusher
  2. Обновление приложения
  3. Установка серверных скриптов
  4. Проверка приложения

Практическая работа построена на основе проекта быстрого запуска Mobile Services. Предварительно необходимо выполнить практическую работу Как начать работать с Mobile Services.

Создание учетной записи Pusher

Для выполнения практической работы сначала необходимо создать учетную запись. Вы можете воспользоваться БЕСПЛАТНЫМ планом подписки Sandbox (Песочница), который прекрасно подходит для обучения.

Регистрация в Pusher

1. Войдите на портал управления Microsoft Azure.

2. Нажмите кнопку New (Создать) на нижней панели портала управления.

3. Нажмите Store (Магазин).

4. В диалоговом окне Choose an Add-on (Выбор надстроек) выберите Pusher и нажмите стрелку вправо.

5. В диалоговом окне Personalize Add-on (Персонализация надстройки) выберите требуемый план Pusher.

6. Введите имя, позволяющее идентифицировать вашу службу Pusher в параметрах Microsoft Azure, или используйте значение по умолчанию Pusher. Длина имени должна составлять от 1 до 100 символов и содержать только буквенно-цифровые символы, тире, точки и подчеркивания. Имя не должно совпадать ни с одним из имен продуктов Магазина Microsoft Azure, на которые у вас уже есть подписка.

7. Выберите регион, например, West US (Запад США).

8. Нажмите стрелку вправо.

9. На вкладке Review Purchase (Предварительный просмотр покупки) проверьте план и информацию о ценах, а также ознакомьтесь с правилами и условиями. Если вы согласны с правилами и условиями, щелкните значок подтверждения (V). Начинается процесс подготовки вашей учетной записи Pusher.

10. После подтверждения покупки вы будете перенаправлены на панель мониторинга надстроек, где увидите сообщение Purchasing Pusher (Покупка Pusher).

Ваша учетная запись Pusher будет готова сразу же, и вы увидите сообщение Successfully purchased Add-On Pusher (Надстройка Pusher приобретена). Учетная запись готова к работе, и вы можете приступать к использованию службы Pusher.

Чтобы изменить план подписки или узнать контактные данные Pusher, выберите имя своей службы Pusher и откройте панель мониторинга надстроек.

При использовании Pusher вам понадобится указать параметры подключения своего приложения Pusher.

Где найти параметры подключения Pusher

1. Нажмите Connect Info (Информация о подключении).

2. В диалоговом окне Connection info (Информация о подключении) будут указаны идентификатор приложения, ключ и секретный ключ. Скопируйте эти данные, так как они вам понадобятся для выполнения следующих этапов практической работы.

Дополнительные сведения о начале работы с Pusher см. на странице Общие сведения о службе Pusher.

Обновление приложения

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

Установка библиотеки libPusher

Библиотека libPusher позволяет получить доступ к Pusher из iOS.

1. Загрузите библиотеку libPusher здесь.

2. Создайте в своем проекте группу под именем libPusher.

3. В инструменте Finder распакуйте загруженный файл .zip, выберите папки libPusher-combined.a и /headers и перетащите их в группу libPusher в своем проекте.

4. Установите флажок Copy items into destination group’s folder (Копировать элементы в папку целевой группы) и нажмите Finish (Готово).

Файлы libPusher будут скопированы в ваш проект.

5. В обозревателе проектов перейдите в корневую папку проекта, нажмите Build Phases (Этапы построения), затем нажмите Add Build Phase (Добавить этап построения) и Add Copy Files (Добавить скопированные файлы).

6. Перетащите файл libPusher-combined.a из обозревателя проектов в новый этап построения.

7. Измените значение в поле Destination (Назначение) на Frameworks (Платформы) и установите флажок Copy only when installing (Копировать только при установке).

8. В области Link Binary With Libraries (Связать двоичный файл с библиотеками) добавьте следующие библиотеки:

  • libicucore.dylib
  • CFNetwork.framework
  • Security.framework
  • SystemConfiguration.framework

9. Теперь в области Build Settings (Параметры построения) найдите целевой параметр Other Linker Flags (Другие флаги компоновщика) и добавьте флаг -all_load.

Флаг -all_load будет задан для целевого объекта отладочного построения.

Библиотека установлена и готова к использованию.

Добавление кода в приложение

1. В Xcode откройте файл TodoService.h и добавьте следующие объявления метода:

// Позволяет извлекать элементы по идентификаторам - (NSUInteger) getItemIndex:(NSDictionary *)item; // Вызывается, когда элементы добавляются другими пользователями - (NSUInteger) itemAdded:(NSDictionary *)item; .// Вызывается, когда элементы завершаются другими пользователями - (NSUInteger) itemCompleted:(NSDictionary *)item; Замените существующие объявления методов addItem и completeItem следующими: - (void) addItem:(NSDictionary *) item; - (void) completeItem: (NSDictionary *) item; В файле TodoService.m добавьте следующий код для реализации новых методов: // Позволяет извлекать элементы по идентификаторам - (NSUInteger) getItemIndex:(NSDictionary *)item { NSInteger itemId = [[item objectForKey: @"id"] integerValue]; return [items indexOfObjectPassingTest:^BOOL(id currItem, NSUInteger idx, BOOL *stop) { return ([[currItem objectForKey: @"id"] integerValue] == itemId); }]; } // Вызывается, когда элементы добавляются другими пользователями -(NSUInteger) itemAdded:(NSDictionary *)item { NSUInteger index = [self getItemIndex:item]; // Действие завершается, только если элемент отсутствует в списке .if(index == NSNotFound) { NSUInteger newIndex = [items count]; [(NSMutableArray *)items insertObject:item atIndex:newIndex]; return newIndex; } else return -1; } // Вызывается, когда элементы завершаются другими пользователями - (NSUInteger) itemCompleted:(NSDictionary *)item { NSUInteger index = [self getItemIndex:item]; // Действие завершается, только если элемент присутствует в списке if(index != NSNotFound) { NSMutableArray *mutableItems = (NSMutableArray *) items; [mutableItems removeObjectAtIndex:index]; } return index; }

Теперь метод TodoService позволяет находить элементы по идентификаторам, а также добавлять и завершать элементы локально, не отправляя явные запросы удаленной службе.

64.  Замените существующие методы addItem и completeItem следующим кодом:

Замените существующие методы addItem и completeItem следующим кодом: -(void) addItem:(NSDictionary *)item { // Вставка элемента в таблицу TodoItem и добавление в массив элементов по завершении [self.table insert:item completion:^(NSDictionary *result, NSError *error) { [self logErrorIfNotNil:error]; }]; } -(void) completeItem:(NSDictionary *)item { // Помечаем элемент как требующий завершения (требуется изменяемая копия) NSMutableDictionary *mutable = [item mutableCopy]; [mutable setObject:@(YES) forKey:@"complete"]; // Обновление элемента в таблице TodoItem и удаление из массива элементов по завершении [self.table update:mutable completion:^(NSDictionary *item, NSError *error) { [self logErrorIfNotNil:error]; }]; }

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

В файле TodoListController.h добавьте следующие операторы импорта: #import "PTPusherDelegate.h" #import "PTPusher.h" #import "PTPusherEvent.h" #import "PTPusherChannel.h" Измените объявление интерфейса для добавления PTPusherDelegate следующим образом: @interface TodoListController : UITableViewController<UITextFieldDelegate, PTPusherDelegate> Добавьте следующее свойство: @property (nonatomic, strong) PTPusher *pusher; Добавьте код, объявляющий новый метод: // Настройка клиента Pusher - (void) setupPusher; В файле TodoListController.m добавьте следующую строку после строк @synthesise для реализации нового свойства: @synthesize pusher = _pusher; Теперь добавьте следующий код для реализации нового метода: // Настройка клиента Pusher - (void) setupPusher { // Создание клиента Pusher с использованием вашего ключа приложения Pusher в качестве учетных данных // TODO: перемещение ключа приложения Pusher в файл конфигурации self.pusher = [PTPusher pusherWithKey:@"**your_app_key**" delegate:self encrypted:NO]; self.pusher.reconnectAutomatically = YES; // Подписка на канал 'todo-updates' PTPusherChannel *todoChannel = [self.pusher subscribeToChannelNamed:@"todo-updates"]; // Привязка к событию 'todo-added' [todoChannel bindToEventNamed:@"todo-added" handleWithBlock:^(PTPusherEvent *channelEvent) { // Добавление элемента в список todo NSUInteger index = [self.todoService itemAdded:channelEvent.data]; // Если элемента еще нет в списке, добавляем его в пользовательский интерфейс if(index != -1) { NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0]; [self.tableView insertRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationTop]; } }]; // Привязка к событию 'todo-completed' [todoChannel bindToEventNamed:@"todo-completed" handleWithBlock:^(PTPusherEvent *channelEvent) { // Обновление завершаемого элемента NSUInteger index = [self.todoService itemCompleted:channelEvent.data]; // Пока элемент существует в списке, обновляем пользовательский интерфейс if(index != NSNotFound) { NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0]; [self.tableView deleteRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationTop]; } }]; }

147. Замените прототип **your_app_key** значением ключа приложения, которое вы скопировали в диалоговом окне Connection Info (Информация о подключении) ранее.

Замените метод onAdd следующим кодом: - (IBAction)onAdd:(id)sender { if (itemText.text.length == 0) { return; } NSDictionary *item = @{ @"text" : itemText.text, @"complete" : @(NO) }; [self.todoService addItem:item]; itemText.text = @""; }

163. В файле TodoListController.m найдите метод (void)viewDidLoad и добавьте вызов метода setupPusher, чтобы первые строки выглядели следующим образом:

- (void)viewDidLoad { [super viewDidLoad]; [self setupPusher];

167. В конце метода tableView:commitEditingStyle:forRowAtIndexPath замените вызов completeItem следующим кодом:

// Запрос todoService на установку значения YES для завершенных элементов [self.todoService completeItem:item];

Теперь приложение может принимать события из Pusher и соответствующим образом обновлять локальный список Todo.

Установка серверных скриптов

Теперь нам осталось только настроить ваши серверные скрипты. Вставим скрипт, обрабатывающий вставку элемента в таблицу TodoList или его обновление.

1. Войдите на портал управления Microsoft Azure, нажмите Mobile Services и выберите свою мобильную службу.

2. В портале управления нажмите вкладку Data (Данные), затем выберите таблицуTodoItem.

3. В разделе TodoItem нажмите вкладку Script (Скрипт) и выберите операцию Insert (Вставить).

Отображается функция, которая вызывается при вставке элемента в таблицуTodoItem.

//Замените функцию вставки следующим кодом: var Pusher = require('pusher'); function insert(item, user, request) { request.execute({ success: function() { // После вставки записи сразу же происходит переключение на клиента request.respond(); // Публикация события для всех других активных клиентов publishItemCreatedEvent(item); } }); function publishItemCreatedEvent(item) { // В идеале следующие параметры должны извлекаться из файла конфигурации var pusher = new Pusher({ appId: '**your_app_id**', key: '**your_app_key**', secret: '**your_app_secret**' }); // Публикация события на канале Pusher pusher.trigger( 'todo-updates', 'todo-added', item ); } }

39.  Замените прототипы в указанном выше скрипте значениями, скопированными ранее из диалогового окна Connection Info (Информация о подключении):

  • **your_app_id**: значение app_id (идентификатор приложения)
  • **your_app_key**: значение app_key (ключ приложения)
  • **your_app_key_secret**: значение app_key_secret (секретный ключ приложения)

40.  Нажмите кнопку Save (Сохранить). Теперь ваш скрипт будет публиковать событие в Pusher при каждой вставке нового элемента в таблицу TodoItem.

41.  Выберите Update (Обновить) в раскрывающемся списке Operation (Операция).

42. Замените функцию обновления следующим кодом:

var Pusher = require('pusher'); function update(item, user, request) { request.execute({ success: function() { // После обновления записи сразу же происходит переключение на клиента request.respond(); // Публикация события для всех других активных клиентов publishItemUpdatedEvent(item); } }); function publishItemUpdatedEvent(item) { // В идеале следующие параметры должны извлекаться из файла конфигурации var pusher = new Pusher({ appId: '**your_app_id**', key: '**your_app_key**', secret: '**your_app_secret**' }); // Публикация события на канале Pusher pusher.trigger( 'todo-updates', 'todo-completed', item ); } }

79.  Повторите шаг 5 данного скрипта для замены прототипов.

80.  Нажмите кнопку Save (Сохранить). Теперь ваш скрипт будет публиковать событие в Pusher при каждом обновлении нового элемента.

Проверка приложения

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

1. Подключите устройство с iOS, нажмите кнопку Run (Выполнить) (или сочетание клавиш Command+R) для запуска приложения на устройстве и остановите отладку.

Ваше приложение установлено на устройстве.

2. Выполните приложение в имитаторе iOS и одновременно запустите приложение на устройстве с iOS.

Теперь у вас есть два выполняемых экземпляра приложения.

3. Добавьте новый элемент Todo в один из экземпляров.

Убедитесь, что добавленный элемент появился в другом экземпляре.

4. Пометьте элемент Todo как завершенный в одном экземпляре.

Убедитесь, что этот элемент исчез из другого экземпляра.

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