Опубликован: 15.05.2013 | Доступ: свободный | Студентов: 264 / 9 | Длительность: 24:25:00
Специальности: Системный архитектор
Лекция 6:

Push-уведомления и Windows Push Notification Service

< Лекция 5 || Лекция 6: 1234 || Лекция 7 >
Аннотация: Для обновления плитки, установки индикатора уведомления или отправки всплывающего уведомления настолько быстро, насколько позволяет система, и для персонализации содержимого (как в случае с напоминаниями календаря или оповещениями об электронной почте) используются push-уведомления.

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

Для обновления плитки, установки индикатора уведомления или отправки всплывающего уведомления настолько быстро, насколько позволяет система, и для персонализации содержимого (как в случае с напоминаниями календаря или оповещениями об электронной почте), нужно быть немного настойчивее и использовать push-уведомления. Это уведомления, которые поступают в систему от агента, расположенного за её пределами, обычно – от сервиса, который отслеживает состояние каких-то других источников информации и обнаруживает условия, когда нужно отправить уведомление. Мы видели этот механизм в разделе "Четыре источника для обновлений и уведомлений" и на рис. 4.14. Подводя итоги, можно сказать:

  • При запуске, приложение запрашивает URI канала для каждой из своих динамических плиток и затем отправляет эти URI связанному с ним веб-сервису. Приложению следует делать это каждый раз при запуске, так как период истечения срока действия для WNS-канала – 30 дней . Каждый URI канала уникален для пользователя, плитки и устройства.
  • Веб-сервис сохраняет URI канала и связывает его с пользователем для настройки содержимого уведомлений для него (как, опять же, происходит с оповещениями об электронной почте и о событиях календаря, уведомлениями об активности друзей и так далее).
  • При необходимости веб-сервис отправляет обновление (полезные данные XML) в этот канал.
  • WNS, в свою очередь, отправляет уведомление на устройство клиента, где приложение запросило URI канала. Это уведомление может обновлять плитки, индикаторы уведомлений, вызывать показ всплывающих уведомлений и обновлять данные на экране блокировки (при условии наличия соответствующих приложений экрана блокировки и фоновых задач).

Кроме того, возможно, и службе, и WNS, отправлять то, что называется необработанными уведомлениями (raw notification), которые могут включать в себя любую полезную нагрузку, которая вам нужна: надо лишь, чтобы что-то прослушивало их, так как Windows не будет знать, что делать с этими данными. Приложение переднего плана может прослушивать их посредством события PushNotificationChannel.onpushnotificationreceived; приложение экрана блокировки может сделать это с помощью фоновой задачи. В последнем случае необработанные уведомления обычно используются для доставки информации фоновой задаче и отправки других уведомлений в ответ, или для обновления данных приложения.

Прежде чем вы сможете сделать что-либо в приложении, однако, вам нужно следовать инструкциям, описанным в материале "Проверка подлинности с помощью службы push-уведомлений Windows (WNS)" (http://msdn.microsoft.com/library/windows/apps/hh465407.aspx) в Центре разработчиков Windows (это – часть целой серии материалов "Отправка push-уведомлений" (http://msdn.microsoft.com/library/windows/apps/hh465460.aspx)). Этот материал проведет вас по шагам, которые необходимо произвести в Информационной панели Магазина Windows (Windows Store Dashboard) для получения Идентификатора безопасности пакета (Package Security Identifie) (SID) и секретного ключа, которые ваш веб-сервис должен использовать для прохождения проверки подлинности при помощи WNS.

Это сделано, теперь давайте пройдёмся по каждому из этих шагов, используя Сценарии 1 – 3 того же самого примера "Push-уведомления и периодические уведомления, клиентская часть" (http://code.msdn.microsoft.com/windowsapps/Push-and-periodic-de225603), который мы использовали ранее при работе с периодическими обновлениями.

Примечание. Так как URI канала уникально для сочетания приложение+пользователь+устройство, использование push-уведомлений может создать серьезную нагрузку на ваш веб-сервис, который должен записывать и поддерживать канал для каждой отдельной плитки каждого пользовательского устройства и затем решать, когда и какие уведомления отправлять на каждый из каналов. Если ваше приложение станет популярным, это потребует масштабирования вашего сервиса для потенциально возможной ситуации, когда придётся управлять тысячами или даже миллионами URI каналов. По этой причине, серьезно подойдите к оценке того, подходят ли для вашего сценария периодические уведомления, особенно для обновлений, которые не относятся к конкретному пользователю, так как подобное гораздо легче выполнить на стороне сервиса.

Запрос и кэширование URI канала (приложение)

Запрос URI канала выполняется с помощью объекта Windows.Networking.PushNotifications.PushNotificationChannelManager. У этого управляющего объекта есть лишь два метода: createPushNotificationChannelForApplicationAsync и createPushNotificationChannelForSecondaryTileAsync. Первый связан с приложением и всплывающими уведомлениями. Второй предназначен для использования с дополнительными плитками и принимает аргумент tileId для идентификации конкретной плитки.

Результат обеих асинхронных операций – это объект PushNotificationChannel , который будет передан обработчику завершения, как показано в Сценарии 1 примера (начинается в js/scenario1.js, затем переходит в js/notifications.js):

  var channelOperation;
  // Канал для плитки приложения
  if (isPrimaryTile) {
  channelOperation = Windows.Networking.PushNotifications.PushNotificationChannelManager
  .createPushNotificationChannelForApplicationAsync();
  } else {
  // Канал для дополнительной плитки
  channelOperation = Windows.Networking.PushNotifications.PushNotificationChannelManager
  .createPushNotificationChannelForSecondaryTileAsync(itemId);
  }

  channelOperation.done(function (newChannel) {
  // Отправка канала веб-сервису
  };	/* обработчик ошибок */
  );

Объект PushNotificationChannel (newChannel в коде) это простой объект с несколькими членами, но они очень важны:

  • expirationTime Свойство только для чтения, показывающее, когда истекает срок действия канала – уведомления, отправленные в этот канал после истечения срока, отклоняются. Приложение должно обновлять, при необходимости, свой канал, для того, чтобы предотвратить перебои в поступлении уведомлений.
  • uri Только для чтения, содержит URI по которому веб-сервис приложения отправляет уведомления
  • close Метод, который объявляет канал недействительным.
  • pushnotificationreceived Событие, которое вызывается, когда уведомление поступает на клиентское устройство из канала уведомления. Оно вызывается только для приложения, которое находится на переднем плане.

Вашему приложению следует пройти через эти процедуры для того, чтобы получить необходимый URI канала, когда оно запускается или восстанавливается (в особенности, если для какого-то канала истекло время, показанное в expirationTime). Вряд ли приложение будет находиться очень долго в приостановленном режиме, но это возможно. Более того, если вы обеспокоены тем, что ваше приложение может не запускаться более чем 30 дней, вы можете реализовать фоновую задачу на основе триггера обслуживания (maintenance trigger) для этих целей. Смотрите "Задачи для триггеров обслуживания" дальше в этой лекции и Сценарий 2 примера.

Снова напоминаю, что у вас может быть больше, чем один URI канала, если вы так же используете push-уведомления для дополнительных плиток, как и для обычной плитки приложения. В этом случае вы будете работать с различными URI канала для каждой плитки.

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

Отправка URI вашему веб-сервису может быть выполнена с помощью простого вызова WinJS.xhr, как в примере (внутри channelOperation.done). Здесь мы так же видим проверки на то, не является ли URI тем же самым, что и раньше.

  
 channelOperation.done(function (newChannel) {
  // _urls[] это массив идентификаторов каналов для основной и дополнительной плиток
  var tileData = that._urls[itemId];

  // Отправка URI канала, если клиент не зафиксировал отправку того же самого
  // uri на сервер
  if (tileData && newChannel.uri === tileData.channelUri) {
  // Сохраняет URI в локальных данных приложения
  that._updateUrl(url, newChannel.uri, itemId, isPrimaryTile);
  completed(newChannel);
  } else { WinJS.xhr({
  type: "POST",
  url: url,
  headers: { "Content-Type": "application/x-www-form-urlencoded" }, data: "channelUri=" + encodeURIComponent(newChannel.uri) +
  "&itemId=" + encodeURIComponent(itemId)
  }).done(function (request) {

  // Обновление данных на клиенте если отправка URI канала прошла успешно.
  // Если это не удалось, вы можете решить настроить другую фоновую задачу, попытаться снова
  // и так далее. (Если операция выдаст ошибку, будет выдано исключение, тогда операция завершится
  // в обработчике ошибки.)
  that._updateUrl(url, newChannel.uri, itemId, isPrimaryTile);
  completed(newChannel);
  }, failed);
  }
  }, failed);

Управление URI каналов (Сервис)

Если вы использовали код из предыдущего раздела, ваш веб-сервис, который генерирует push-уведомления, получит запрос HTTP POST с уникальным URI канала для каждой плитки. Это не единственный способ передачи URI канала, конечно. На самом деле, так как URI канала могут быть использованы для передачи персональной информации через уведомления, его, в идеале, перед отправкой на сервер, следует зашифровать с помощью закрытого ключа. В противном случае кто-нибудь может перехватить этот URI и использовать его для перенаправления уведомлений, относящихся к конкретному пользователю.

В любом случае, сервис должен ожидать получения, для последующего управления ими, уникальных URI для каждой комбинации приложения/пользователя/устройства. Это подчеркивает тот факт, что push-уведомления лучше всего использовать для уведомлений, специфичных для пользователя, чем для широковещательных уведомлений. В последнем случае настройка сервиса для выполнения периодических уведомлений – гораздо более простое решение.

Как только сервис получит URI канала вместе с любыми данными для идентификации пользователя и цели использования канала, он должен безопасно сохранить эту информацю в каком-нибудь постоянном хранилище, таком, как база данных SQL Server (для сервиса ASP.NET) или MySQL (для PHP-сервиса).

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

Простую страницу сервиса ASP.NET, которая получает сообщение от Сценария 1 примера "Push-уведомления и периодические уведомления, клиентская часть" (http://code.msdn.microsoft.com/windowsapps/Push-and-periodic-de225603) можно найти в проекте веб-сайта HelloTiles в дополнительных материалах к лекции, в частности, это receiveuri.aspx. Для того, чтобы запустить этот сервис, убедитесь в том, что ваш локальный хост соответствующим образом настроен, как описано выше в разделе "Использование локального хоста". Так же вам может понадобиться установить ASP.NET на ваш локальный хост. Простой способ это сделать – загрузить пример "Фоновая передача данных" ( http://code.msdn.microsoft.com/windowsapps/Background-Transfer-Sample-d7833f61), перейти в его папку Server и затем, из командной строки администратора, выполнить команду powershell -ExecutionPolicy unrestrictedfile serversetup.ps1. Если затем вы запустите сайт в Visual Studio Express 2012 для Web, как мы делали раньше, у вас должен быть порт локального хоста для сервиса (например, http://localhost:52568/HelloTiles/receiveuri.aspx).

Затем вы можете установить точку останова в коде сервиса, вставить сервисный URI в Сценарий 1 примера "Push-уведомления и периодические уведомления, клиентская часть" и нажать его кнопку Reopen Channel And Send To Server (Повторно открыть канал и отправить на сервер). При этом должна сработать точка останова в сервисе, что позволить вам пошагово исполнить код, который обрабатывает запрос. Здесь вы можете обнаружить, что запрос содержит значения channelUri и itemId (наряду с LOGON_USER), которые могут быть сохранены для отправки уведомлений WNS, когда это будет нужно. Что-то похожее, конечно, можно написать на других серверных языках, хорошее место, где можно найти инструменты, которые помогут в написании кода сервисов, является Windows Azure Toolkit ( http://watwindows8.codeplex.com/).

Отправка обновлений и оповещений (Сервис)

Прежде чем сервис сможет отправлять обновления, он должен пройти проверку подлинности с помощью WINS, отправляя ему Идентификатор безопасности пакета (SID) и секретный ключ, полученные в Магазине Windows. Это можно сделать с помощью отправки WNS запроса XmlHttpRequest (через HTTPS), что может выглядеть примерно так:

POST /accesstoken.srf HTTP/1.1
  Content-Type: application/x-www-form-urlencoded
  Host: https://login.live.com
  Content-Length: 211
  grant_type=client_credentials&client_id=ms-app%3a%2f%2fS-1-15-2-2972962901-2322836549-3722629029-13452385
  79-3987825745-2155616079-650196962&client_secret=Vex8L9WOFZuj95euaLrvSH7XyoDhLJc7&scope=notify.windows.com

Здесь вы должны убедиться, что значения client_id и client_secret соответствуют SID пакета и секретному ключу. Если проверка подлинности прошла успешно, вы получите ответ 200 OK с маркером доступа (access token), который понадобится вам для отправки уведомлений:

   HTTP/1.1 200 OK
  Cache-Control: no-store
  Content-Length: 422
  Content-Type: application/json
  {
  "access_token":"EgAcAQMAAAAALYAAY/c+Huwi3Fv4Ck10UrKNmtxRO6Njk2MgA=", "token_type":"bearer"
  }

Код, который выполняет эти шаги для сервиса, написанного на C#, можно найти в материале "Проверка подлинности с помощью службы push-уведомлений Windows" (http://msdn.microsoft.com/library/windows/apps/hh465407.aspx), где ваш сервис будет использовать метод GetAccessToken, показанный здесь для получения объекта OAuthToken с информацией из ответа. Сервисы, написанные на других языках, очевидно, нуждаются в использовании подходящих средств для отправки запроса и получения ответа.

В любом случае, как только вы получите маркер доступа, вы готовы к тому, чтобы начать отправлять обновления и уведомления с помощью XmlHttpRequests по URI каналов, которые поддерживет сервис.

Для обновлений плиток и индикаторов события, для всплывающих уведомлений, отправка уведомления подразумевает создание полезных данных XML, как и для любых других обновлений или уведомлений, и затем отправка их WNS с ранее полученным маркером доступа. Единственная настоящая разница между этими запросами, помимо различного XML – это значение X-WNS-Type в заголовке запроса: wns/badge, wns/tile, wns/toast, или wns/raw (смотрите следующий раздел). Остальной код у них один и тот же.

Общий код для C#-сервисов можно найти в материалах "Краткое руководство: отправка push-уведомления" (http://msdn.microsoft.com/library/windows/apps/xaml/hh868252.aspx) и "Краткое руководство: отправка всплывающих push-уведомлений" (http://msdn.microsoft.com/library/windows/apps/xaml/hh868255.aspx). Я включил версию с обновлением индикатора событий в sendBadgeToWNS.aspx в сайт Hello Tiles, который находится в дополнительных материалах к этой лекции, там SID и секретный ключ – те, что я получил для примера "Push-уведомления и периодические уведомления, клиентская часть" (Вам может понадобиться создать новые для себя). Для того, чтобы всё это протестировать, запустим веб-сайт Hello Tiles в Visual Studio Express 2012 для Web и установим точку останова в начале sendBadgeToWNS.aspx. Предполагая, что вы запустили Сценарий 1 примера "Push-уведомления и периодические уведомления, клиентская часть" в Visual Studio Express 2012 для Windows 8 для отправки URI канала receiveuri.aspx, в проекте веб-сайта должен быть файл, который называется channeluri_aspx.txt, он содержит отправленные данные.

Теперь переключимся на Сценарий 3 примера и нажмём кнопку для того, чтобы начать прослушивание события pushnotificationreceived. В js/scenario3.js этого примера, установим точку останова в функции pushNotificationReceivedHandler. Когда всё готово, откроем браузер и введем адрес sendBadgeToWNS.aspx на локальном хосте: http://localhost:52568/HelloTiles/sendBadgeToWNS.aspx,например. Точка останова должна сработать в Visual Studio Express 2012 для Web, где вы можете пошагово исполнить код страницы и увидеть, что она загружает URI канала из channeluri_aspx.txt, по которому она затем отправляет обновление индикатора уведомления. Когда это происходит, должна сработать точку останова в приложении Push notifications, где вы так же можете пошагово исполнить код. Обратите внимание на то, что когда вы достигаете строки e.cancel=true, пропустите её, щелкните правой кнопкой мыши ниже её и выберите Задать следующий оператор (Set Next Statement). Это позволит Windows обработать уведомление и обновить индикатор событий для приложения-примера, который должен выглядеть сейчас примерно так, с индикатором * в нижнем правом углу:


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

Ошибки 404 или 410, кстати, отличаются от невозможности доставить уведомление по причине того, что клиент не подключен к сети. В подобном случае WNS будет кэшировать уведомления для плитки, индикатора событий или необработанные уведомления до тех пор, пока клиент не подключится к сети. Другими словами, это не то, о чём должен беспокоиться сервис. Отправляйте уведомления как всегда, и позвольте WNS заниматься деталями их доставки.

< Лекция 5 || Лекция 6: 1234 || Лекция 7 >