Программная логика приложений для Windows 8 и их взаимодействие с системой

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

Разбить на страницы
Показывать лекцию целиком

Вот мы и добрались до того места этой лекции, где мы можем отвлечься от исполняющихся приложений и посмотреть на больше интересных вещей, которые происходят в глубинах системы. Раньше, в "Периодических обновлениях", мы узнали, что самый короткий интервал, который может использовать этот метод, слишком велик по компьтерным меркам: 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 (Повторно открыть канал и отправить на сервер). При этом должна сработать точка останова в сервисе, что позволить вам пошагово исполнить код, который обрабатывает запрос. Здесь вы можете обнаружить, что запрос содержит значения ).

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

    Прежде чем сервис сможет отправлять обновления, он должен пройти проверку подлинности с помощью 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_credentialsclient_id=ms-app%3a%2f%2fS-1-15-2-2972962901-2322836549-3722629029-13452385
      79-3987825745-2155616079-650196962client_secret=Vex8L9WOFZuj95euaLrvSH7XyoDhLJc7scope=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 заниматься деталями их доставки.

    Необработанные уведомления (Сервис)

    Если вы, в качестве типа push-уведомления используете wns/raw, полезные данные, включенные в уведомление могут быть чем угодно, а не только XML, но их размер не может превышать 5 Кб.

    Конечно, Windows не может непосредственно что-либо сделать с этими данными, таким образом приложение должно предоставить обработчик для приёма этих уведомлений, как рассказано в следующем разделе.

    Приём уведомлений (приложение)

    Выполняющееся приложение принимает push-уведомление посредством PushNotificationChannel.onpushnotificationreceived. Это, опять же, нужно для обработки полезной информации из wns/raw уведомлений, но может использоваться и для других видов уведомлений. Если приложение не исполняется, то, конечно, оно не может принять это событие. Вместо этого, приложение должно присуствовать на экране блокировки с фоновой задачей PushNotificationTrigger, предназначенной для этой цели (смотрите "Задачи, зависимые от экрана блокировки и триггеры" ниже в этой лекции). Этот код затем принимает полезные данные XML, обрабатывает их и отправляет, при необходимости, либо обновления плиток, либо индикаторов событий, либо всплывающие уведомления. Помимо сохранения некоторых данных в папки данных приложения, это, на самом деле, всё, что могут делать фоновые задачи, но этого достаточно для сохранения ощущения динамичности приложений и для приглашения пользователей к запуску приложений.

    В выполняющемся приложения вызывается событие pushnotificationreceived так же для других типов уведомлений. Сценарий 3 примера показывает это в его обработчике событий – я, для упрощения, слегка изменил этот код:

    function startListening() {
     // Предполагаем, что канал получен и проверен
     channel.addEventListener("pushnotificationreceived", pushNotificationReceivedHandler);
     }
     function pushNotificationReceivedHandler(e) {
     // Извлекаем полезные данные уведомления для каждого типа уведомлений
    
     var notificationPayload;
     switch (e.notificationType) {
     case pushNotifications.PushNotificationType.toast:
     notificationPayload = e.toastNotification.content.getXml();
     break;
    
     case pushNotifications.PushNotificationType.tile: notificationPayload = e.tileNotification.content.getXml(); break;
    
     case pushNotifications.PushNotificationType.badge:
     notificationPayload = e.badgeNotification.content.getXml();
     break;
    
     case pushNotifications.PushNotificationType.raw:
     notificationPayload = e.rawNotification.content;
     break;
     }
    
     // Обработка уведомления: установите e.cancel в true для подавления автоматической обработки.
     }

    Последняя часть в вышеприведенных комментариях важна. Когда вы принимаете событие в исполняющемся приложении, не нужно показывать всплывающее уведомление, только если оно не имеет отношения к какой-то части приложения, которая сейчас невидима. Например, если у вас есть приложение, которое работает и с электронной почтой и с календарём, вам захочется сделать видимыми всплывающие уведомления об электронной почте, когда пользователь видит календарь, и уведомления о событиях календаря, когда он работает с электронной почтой. В данном случаае установка e.cancel в true не позволит отобразиться всплывающему уведомлению.

    В событии ) для того, чтобы узнать подробности об этом.

    Советы по отладке

    При использовании push-уведомлений, практика показывает, что если уведомления не доставляются на устройство, обычно это не из-за проблемы с WNS. Вот списко того, что надо проверить (Спасибо Гансу Андерсену за этот список):

  • Проверьте статус возврата ваших запросов HTTP POST к WNS. Если возвращается ответ HTTP 200, проверьте X-WNS-NotificationStatus и другие полученные заголовки. В частности, ищите статус "Received", который показывает, что уведомление доставлено клиенту.
  • Не обнаружив ничего убедительного в заголовках, запустите Просмотр журналов событий (Event Viewer) и проверьте события в разделе Журналы приложений и служб > Microsoft > Windows > Push Notifications Platform > Operational ( Application And Services Logs > Microsoft > Windows > Push Notifications Platform > Operational) для того, чтобы посмотреть на деятельность по приему уведомлений.
  • Кроме того, посмотрите в разделе Журналы приложений и служб > Microsoft > Windows > Immersive-Shell > Microsoft-Windows-TWinUI > Operational (Application And Services Logs > Microsoft > Windows > Immersive-Shell > Microsoft-Windows-TWinUI > Operational) для того, чтобы увидеть, есть ли здесь сообщения об ошибках, связанные с обработкой XML, примерно в то время, когда вы ожидаете поступление уведомления.
  • Если даже с XML всё в порядке, обновление может не отобразиться, если изображение, указанное в нём, либо слишком большое (в пискелях, или по размеру файла), если оно имеет неподходящий формат (например, TIF), если изображение повреждено, если сервер, обрабатывающий запрос на получение изображения, не может обработать параметры запроса для плитки (масштабирование, контрастность, язык), или если сервер столкнулся с другой ошибкой, которую можно обнаружить в его собственных журналах.
  • Если обновление появляется, но после значительной задержки, это может означать либо внутренние задержки или другие задержки в сети, связанные с инфраструктурой плиток и уведомлений. Если это происходит, просто примите к сведению, что мир не всегда совершенен и операции иногда приходится повторять!
  • Windows Azure Toolkit и Windows Azure Mobile Services

    Очевидно, много работы нужно для создания службы, которая может принимать URI канала и отправлять уведомления через WNS. Признавая это, Windows Azure Toolkit (http://watwindows8.codeplex.com/) снова предлагает некоторые решения. Рассмотрение всех подробностей выходит за рамки этого курса, но ссылки ниже помогут вам начать с этим разрибаться. В частности, "Пример уведомлений Azure" (http://watwindows8.codeplex.com/wikipage?title=Notifications%20Sample%20%E2%80%93%20C%23%20and%20JavaScript) и "Пример о необработанных уведомлениях" (http://watwindows8.codeplex.com/wikipage?title=Raw%20Notifications%20Sample), так же "Пример рабочего процесса push-уведомлений" (http://watwindows8.codeplex.com/wikipage?title=Push%20Notification%20Worker%20SamplereferringTitle=Documentation). Вот полезное видео на сайте Channel 9: "Эпизод 73 – Ник Харрис о push-уведомлениях для Windows 8" (http://channel9.msdn.com/Shows/Cloud+Cover/Episode-73-Nick-Harris-on-Push-Notifications-for-Windows-8). Дополнительные ресурсы, весьма вероятно, будут опубликованы после того, как была написана эта лекция, поэтому поиск в Интернете позволит вам найти больше материалов.

    Кроме того, посмотрите на "Мобильные сервисы Windows Azure" (http://www.windowsazure.com/en-us/develop/mobile/?fb=ru-ru), которые помогут вам создать масштабируемую серверную часть приложения, в том числе – структурированные облачные данные, проверку подлинности, и push-уведомления. Этот новые сервисы, на момент написания, поэтому у меня нет ссылок на другие ресурсы, но, совершенно очевидно, их стоит изучить.

    Фоновые задачи и приложения экрана блокировки

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

    Позвольте мне повторить здесь, что мы уже видели ряд сценариев, где пользователь может ожидать некоторой деятельности, связанной с приложением без необходимости запуска приложения. Периодические обновления плиток, push-уведомления, запланированные всплывающие уведомления и даже передача данных через контракт Общий доступ производят полезную деятельность , когда приложение приостановлено или не исполняется. Приложения так же могут настраивать фоновую передачу данных, которая выполняется, когда приложение не запущено, как мы увидим в Главе 3. А возможность фонового воспроизведения музыки предоставлена для специального класса приложений, которым нужно выполняться для поддержки сеансов связи VoIP, воспроизведения аудио, онлайновых бесед и так далее.

    Что нам осталось рассмотреть – так это те самые небольшие фрагменты кода приложения, которые Windows может запускать в ответ на различные триггеры. Триггеры, в некоторых случаях, могут подвергнуться дальнейшей настройке в соответствии с дополнительными условиями, в итоге фоновая задача исполняется только тогда, когда в этом есть реальная необходимость. Всё это делается для уменьшения количества фоновой деятельности, которая истощает батареи устройства. Некоторые типы триггеров, на самом деле, требуют, чтобы пользователь поместил приложение на экран блокировки для того, чтобы преднамеренно ограничить количество приложений, которые могут реагировать на эти триггеры. Более того, Windows так же ограничивает процессорное время, которое могут потреблять подобные фоновые задачи:

  • Фоновые задачи экрана блокировки: две секунды общего времени процессора за 15 минут.
  • Другие фоновые задачи: одна секунда общего времени процессора каждые два часа.
  • Использование сетевого соединения так же ограничено в связи с затратами энергии батарей. Что это за ограничение, я не могу точно сказать, так как система анализирует использование энергии более пристально, нежели количество переданной информации. Средства оценки предела можно найти в материале "Поддержка приложения с помощью фоновых задач" (http://msdn.microsoft.com/library/windows/apps/hh977046.aspx). (Пока мы говорим об этом, вам, возможно, будет интересно посмотреть "Руководство и контрольный список для фоновых задач" (http://msdn.microsoft.com/library/windows/apps/Hh977043.aspx), документ "Введение в фоновые задачи" ( http://www.microsoft.com/en-us/download/details.aspx?displaylang=enid=27411), и материал "Поддержание производительности при работе приложения в фоновом режиме — фоновые задачи" (http://blogs.msdn.com/b/windowsappdev_ru/archive/2012/06/01/10313828.aspx) в блоге для разработчиков приложений для Windows 8).

    Возможно, вы подумали: "Ничего себе! Разве Windows 8 на самом деле имеет подобные ограничения?".

    Коротко говоря – да, так как Windows не только стремится сэкономить энергию батарей для приложений переднего плана, с которыми работает пользователь, но так же она стремится к тому, чтобы от приложений переднего плана у пользователя остались бы наилучшие впечатления. Это подразумевает, что система не хочет столкнуться с фоновыми приложениями, которые, если им это позволить, занимают столько ресурсов, сколько смогут. (Разработчики фоновых служб всегда найдут оправдание для захвата ресурсов!).

    Возможно, вы попадали в такую ситуацию, когда вы запускаете приложение, но его запуск занимает целую вечность, так как некие таинственные службы интенсивно используют жёсткий диск, передают данные по сети, нагружают процессор и так далее. Я, например, в подобной ситуации разбираюсь в чём дело, с помощью Диспетчера задач и Монитора ресурсов, после чего останавливаю любой процесс, который пожирает ресурсы моей системы – и будь что будет. Именно возникновения подобных впечатлений у пользователя и пытается избежать Windows 8.

    "Хорошо", - скажете вы (при условии, что я, в некоторой степени, вас убедил), - "Означает ли это, что нет способа для выполнения некоторой фоновой работы наподобие индексирования данных, создания экскизов изображения, обработки видео и так далее?".

    На самом деле, есть способы для того, чтобы это сделать. Во-первых, когда приложение находится на переднем плане, оно может делать подобные вещи в любых объёмах, так как оно, в конечно счете, отвечает за то, какие впечатления у пользователя создаст взаимодействие с ним. (Приложения, написанные на JavaScript, могут для подобных целей, использовать рабочие веб-процессы для того, чтобы убрать выполнение подобных задач из потока пользовательского интерфейса, а так же – передавать задачи компонентам WinRT, которые выполняют их дела в других потока и асинхронно возвращают результат. Мы ознакомимся с этим в Главе 5.).

    Во-вторых, когда устройство подключено к сети переменного тока, а не работает от батарей, Windows позволяет фоновым задачам, запущенным для обслуживания триггеров, работать по 15 минут или дольше (в зависимости от нужд приложения). Здесь всё еще применимы ограничения ресурсов процессора, которые они могут потреблять, но задачи, которые не задействуют пользовательский интерфейс, который не разрешено использовать фоновым задачам – могут выполнить несколько миллиардов инструций за одну или две секунду на гигагерцовом процессоре!

    Что мы имеем в итоге, так это то, что существует три различных класса фоновых задач и связанных с ними триггеров:

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

    Фоновые задачи в манифесте

    Все фоновые задачи для приложения объявляются в манифесте, где каждое объявление указывает на тип задачи и на код, который должен исполняться для выполнения этой задачи, как показано на рис 6.1. Мы видели этот раздел манифеста в Главе 4 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript", где мы выбирали пункт Звук (Audio) для приложения, которое воспроизводит в фоновом режиме музыку. Что касается других параметров, то Системное событие (System Event) используется для первых двух классов вышеперечисленных задач, опции Канал управления (Control Channel), Таймер (Timer) и Push-уведомления (Push Notification) предназначены для задач, которые связаны с приложениями экрана блокировки.

    (рис 6.1) Редактор манифеста при объявлении фоновых задач. Показаны параметры для объявления Фоновые задачи (Background Tasks) из выпадающего списка Доступные объявления (Available Declarations) (слева), и типы фоновых задач (в центре), и поле Начальная страница (Start Page) для указания JavaScript-кода, который нужно исполнить для задачи (внизу). Фоновые задачи так же могут быть написаны на других языках, в подобных случаях используются поля Исполняемый файл (Executable) и Точка входа (Entry Point)

    Во всех случаях, поле Начальная страница (Start Page) – это то место, где вы указываете JavaScript-файл, который будет исполняться для этой задачи независимо от приложения, передавая ему информацию лишь через папки данных приложения, вы, на самом деле, можете использовать здесь любой язык, какой хотите. Учитывая квоты на процессорное время, написание фоновых задач на языке вроде C++ или C# позволит вам выполнять некоторые задачи более эффективно, и в подобном случае вы будете использовать поле Точка входа (Point field )(если задача реализована в виде DLL, которая находится в пакете приложения), и, возможно, поле Исполняемый файл (Executable) (если задача реализована с помощью EXE-файла, который так же расположен в пакете приложения) для идентификации кода модуля и конкретной функции для вызова.

    Полезно отметить, что даже хотя в поле Начальная страница (Start Page) для JavaScript ожидается указание страницы, там, на самом деле, может быть лишь код для фоновой задачи – вы получите ошибку, если попытаетесь задать в этом поле HTML-файл. (Для того, чтобы говорить точнее, фоновые задачи на JavaScript – это рабочие веб-процессы, простые и понятные). А почему фоновые задачи не могут отображать пользовательский интерфейс, так это потому, что Windows не загрузит HTML или CSS-код, лишь JavaScript! Таким образом, отправляя обновления плиток, индикаторов событий и всплывающие уведомления – это все дела, связанные с пользовательским интерфейсом, которые могут выполнять фоновые задачи. Для выполнения чего-то другого, фоновая задача должна записать некоторое значение в папку данных приложения, а это значение должно, с помощью обработчиков событий для фоновых задач, получить и обработать основное приложение, что мы скоро увидим.

    Вы можете заметить, что параметр Системное событие (System Event) в редакторе манифеста не предусматривает поля, где вы можете задать триггер для задачи. Это выполняется в коде, при создании задачи, как мы увидим в ближайшее время.

    Создание и регистрация фоновой задачи

    Объявление фоновой задачи в манифесте – это лишь объявление, которое сообщает системе о том, что приложение намеревается использовать фоновую задачу. Приложение должно зарегистрировать фоновую задачу из кода для того, чтобы она могла исполняться, что реализуется с помощью ) (его родительское пространство имен содержит всё, к чему мы будем обращаться в контексте фоновых задач). Проще говоря, вы создаете экземпляр средства для создания фоновой задачи, задаёте его свойства name и taskEntryPoint, вызываете его методы setTrigger и addCondition для указания того, когда следует запускать фоновую задачу, и затем вызываете register.

    Обычный код для этого можно найти в примере "Фоновая задача" (http://code.msdn.microsoft.com/windowsapps/Background-Task-Sample-9209ade9), в js/global.js.

    Этот модуль объявляет глобальный объект BackgroundTaskSample, который содержит свойства и методы. Нас здесь интересует метод, который называется registerBackgroundTask, он регистрирует заданную точку входа (имя JavaScript-файла или имя класса в C#, Visual Basic, или C++), с заданным именем и применяет некоторые триггеры и условия.

    var BackgroundTaskSample = {
    // Свойства, содержащие имена и точки входа для задач примера опущены
    
    //
    // Регистрация фоновой задачи с заданными taskEntryPoint, taskName, trigger,
    // и condition (дополнительно).
    //
    "registerBackgroundTask": function (taskEntryPoint, taskName, trigger, condition) {
    var builder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder();
    
    builder.name = taskName; builder.taskEntryPoint = taskEntryPoint; builder.setTrigger(trigger);
    
    if (condition !== null) {
    builder.addCondition(condition);
    }
    
    var task = builder.register(); BackgroundTaskSample.attachProgressAndCompletedHandlers(task);
    
    // [Опущен код, отражающий особенности примера]
    
    // Удаление предыдущего статуса завершения из локальных параметров.
    var settings = Windows.Storage.ApplicationData.current.localSettings;
    settings.values.remove(taskName);
    },

    В этом коде метод ), с помощью которого управляют зарегистрированной задачей. У зарегистрированной задачи есть свойство name и назначенное системой свойство taskId, последнее из них вы можете использовать для сохранения данных приложения, которые уникальны для задачи. Так же у него есть метод unregister, который вы можете вызвать для отмены регистрации, и два события: completed и progress. Обработчики для этих событий назначают обычным способом, с помощью addEventListener, как показано в функции BackgroundTaskSample.attachProgressAndCompletedHandlers в примере:

    "attachProgressAndCompletedHandlers": function (task) {
     task.addEventListener("progress",
     new BackgroundTaskSample.progressHandler(task).onProgress);
     task.addEventListener("completed",
     new BackgroundTaskSample.completeHandler(task).onCompleted);
     },

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

    Здесь присутствует одно статическое свойство, BackgroundTaskRegistration.allTasks, объект IMapView , с помощью которого вы можете получить свои зарегистрированные задачи и получить для каждого отдельный объект BackgroundTaskRegistration.

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

    Имея подобную структуру, мы можем задаться вопросом: что мы делаем для настройки триггеров и условий? Ответ на этот вопрос – это то, что различает разные виды фоновых задач.

    Условия

    Конкретные условия вы можете задать с помощью объекта ), который является экземпляром класса ). Фоновая задача, зарегистрированная с одним или большим количеством условий – каждый вызов addCondition приводит к добавлению очередного условия – будет запланирована к выполнению только если все условия выполняются.

    Каждый экземпляр может иметь один из следующих типов, заданных в перечислении SystemConditionType: internetAvailable (интернет-подключение доступно), internetNotAvailable (интернет-подключение не доступно), sessionConnected (пользователь вошёл в систему), sessionDisconnected (пользователь вышел из системы), userPresent (пользователь в настоящий момент занят какими-то делами), и userNotPresent (пользователь ничего не делает некоторое время).

    Очевидно, каждая пара из этих условий является взаимоисключающей: если вы зарегистрировали задачу с условиями internetAvailable и internetNotAvailable, Windows поймёт, что вы никогда не планируете, чтобы эта задача когда-нибудь запускалась, поэтому система оставит её сидеть на обочине и никогда не побеспокоит! С другой стороны, вы можете использовать эти условия для того, чтобы быть уверенным, что ваша задача выполняется только тогда, когда нужна. Если вам нужно запустить фоновую задачу, которая обновляет канал push-уведомлений, например, нет смысла этого делать при отсутствии подключения к Интернету. (В следующем разделе, "Задачи для триггеров обслуживания", мы увидим пример). С другой стороны, если у вас есть фоновая задача, исполнение которой никогда не должно совпадать с активной работой пользователя, вы можете добавить условие userNotPresent.

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

    Задачи для триггеров обслуживания

    Фоновые задачи, использующие триггеры обслуживания, вероятно, являются наиболее общим типом задач – они содержат какой-либо код, который нужно периодически запускать, но только тогда, когда система подключена к источнику питания . Подобные задачи отлично подхдят для "проверки на что-либо", или для другой деятельности, которую нужно выполнять периодически, но при этом не важно – когда точно это произойдёт. Например, триггеры обслуживания не подходят для чего-то вроде синхронизации данных с сервером, так как это должно происходить своевременно, и это лучше будет реализовать с помощью API фоновой передачи данных, которое мы рассмотрим в Главе 3.

    Триггер обслуживания – то, что вы передаете в ). При создании экземпляра предоставляют два параметра. Первый – это необходимый период обновления (свойство freshnessTime, в минутах), всегда следует использовать наибольший период, подходящий для конкретного сценария. Система будет всегда ожидать, как минимум, прохождения этого периода, перед первым запуском задачи. Второй параметр – это флаг, который указывает на то, нужно ли запустить задачу лишь один раз (свойство oneShot).

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

    var background = Windows.ApplicationModel.Background;
      var pushNotificationsTaskName = "UpdateChannels";
      var maintenanceInterval = 10 * 24 * 60; // 10 дней
    
      var taskBuilder = new background.BackgroundTaskBuilder();
      var trigger = new background.MaintenanceTrigger(maintenanceInterval, false);
      taskBuilder.setTrigger(trigger);
      taskBuilder.taskEntryPoint = "js\\backgroundTask.js";
      taskBuilder.name = pushNotificationsTaskName;
    
      var internetCondition = new background.SystemCondition(background.SystemConditionType.internetAvailable);
      taskBuilder.addCondition(internetCondition);
    
      taskBuilder.register();

    Так как срок действия URI канала – 30 дней, пример создаёт триггер, предназначенный для исполнения каждые 10 дней (10 дней * 24 часа в день * 60 минут в часе). Так же сюда разумно добавлено условие internetAvailable, так как не имеет смысла пытаться обновить URI канала, когда нет подключения к Интернету.

    Саму задачу можно найти в файле примера js/backgroundTask.js, что отражено в свойстве taskEntryPoint:

    (function () {
    // Импорт вспомогательного объекта Notifier
    importScripts("//Microsoft.WinJS.1.0/js/base.js");
    importScripts("notifications.js");
    
    var closeFunction = function () {
    close();
    };
    
    var notifier = new SampleNotifications.Notifier();
    notifier.renewAllAsync().done(closeFunction, closeFunction);
    })();

    Код задачи использует пару других скриптовых файла, importScripts, второй из которых, notifications.js, это набор вспомогательных функций образца для уведомлений, где renewAllAsync обновляет список, в котором находятся URI канала, ранее сохраненные приложением.

    Важно. Вы так же можете заметить, что обработчики завершения и ошибки задаваемые в promise-объекте из функции ). Фоновые задачи в приложении, написанном на JavaScript, запускаются в областе видимости рабочего веб-процесса, таким образом, глобальная область в этом коде – это WorkerGlobalScope, а не window. Данный вызов позволяет убедиться в закрытии независимо работающей фоновой задачи и гарантирует, что ресурсы, которые были выделены для задачи, соответствующим образом освобождены.

    Врезка: Экземпляр задачи и острочка фоновой задачи

    В фоновой задаче JavaScript, Windows.UI.WebUI.WebUIBackgroundTaskInstance.current содержит объект WebUIBackgroundTaskInstanceRuntimeClass (http://msdn.microsoft.com/library/windows/apps/windows.ui.webui.webuibackgroundtaskinstanceruntimeclass.aspx), который предоставляет дополнительные сведения о выполняющейся задаче: её instanceId, связанный с ней объект BackgroundTaskRegistration в свойстве task, свойство progress, в котором задача может сохранить процентное значение степени её выполнения, флаг succeeded , который позволяет указать, что задача завершена, свойство suspendedСount (показывает, сколько раз был приостановлена задача при превышении ограничений), и событие canceled , которое сообщает о том, что задача будет закрыта.

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

    Задачи для системных триггеров (не для экрана блокировки)

    Следующий класс фоновых задача содержит следующие привязки к различным системным триггерам, в частности, экземпляры класса ). Объект триггера создают с помощью ключевого слова new и передают два параметра: значение SystemTriggerType value (доступное потом как свойство triggerType) и флаг логического типа oneShot. Эти триггеры могут работать независимо от экрана блокировки, они описаны в следующей таблице:

    SystemTriggerType Когда вызывается и сценарии использования
    internetAvailable Стало доступно подключение к Интернету. Это обычно используется для приложений, которым нужно запустить процесс синхронизации, когда восстанавливается подключение к Интернету. Обратите внимание на то, что этот триггер отличается от условия с тем же самым именем.
    lockScreenApplicationAdded Пользователь добавил прилоежение на экран блокировки, что указывает на то, что фоновые задачи, зависимые от экрана блокировки теперь будут исполняться.
    lockScreenApplicationRemoved Пользователь удалил приложение с экрана блокировки, что указывает на то, что фоновые задачи, зависимые от экрана блокировки, теперь исполняться не будут.
    networkStateChange Изменение сетевых условий (стоимости, типа подключения и так далее). Исполняющееся приложение может обнаружить то же самое с помощью события ).
    onlineIdConnectedStateChange Учетная запись Microsoft пользователя изменена. Это сравнительно редкое событие, но триггер является основным средством для любых приложений, которые кэшируют любые части сведений из учетной записи Microsoft для собственных целей идентификации пользователя.
    servicingComplete Завершено бновление приложения из Магазина Windows. Этот триггер можно использовать, например, для выполнения миграции данных приложения с одной версии на другую как только произойдёт обновлении. Подробнее о версиях данных приложения вы можете узнать в Главе 2 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript".
    timeZoneChange Изменен часовой пояс или осуществлен переход на летнее или зимнее время. Приложение в этот момент может обновить данные о географическом местоположении, настроить внутренние механизмы, связанные с учетом времени. Это может быть важно для настройки запланированных уведомлений.

    В примере "Фоновая задача" есть несколько примеров этих триггеров. В Сценарии 1, js/sample-background-task-with-condition.js, мы можем видеть использование триггера timeZoneChange и условия userPresent (здесь BackgroundTaskSample это вспомогательный объект из global.js):

    BackgroundTaskSample.registerBackgroundTask(BackgroundTaskSample.sampleBackgroundTaskEntryPoint,
      BackgroundTaskSample.sampleBackgroundTaskWithConditionName,
      new Windows.ApplicationModel.Background.SystemTrigger(
      Windows.ApplicationModel.Background.SystemTriggerType.timeZoneChange, false),
      new Windows.ApplicationModel.Background.SystemCondition(
      Windows.ApplicationModel.Background.SystemConditionType.userPresent));

    Это явно тот случай, когда я хотел бы использовать другую переменную для того, чтобы каждый раз не вводить обозначение пространства имен Windows.ApplicationModel.Background, но вы, по крайней мере, не ошибетесь, читая этот код! В любом случае, тот же пример, в Сценарии 4 и js/global.js, так же показывает использования триггера servicingComplete со вспомогательной функцией registerServicingCompleteTask, которая так же проверят, была ли задача уже зарегистрирована:

    "registerServicingCompleteTask": function () {
    // Проверяет, была ли уже зарегистрирована фоновая задача servicingComplete.
    var iter =
    Windows.ApplicationModel.Background.BackgroundTaskRegistration.allTasks.first();
    var hascur = iter.hasCurrent;
    while (hascur) {
    var cur = iter.current.value;
    if (cur.name === BackgroundTaskSample.servicingCompleteTaskName) { BackgroundTaskSample.updateBackgroundTaskStatus(
    BackgroundTaskSample.servicingCompleteTaskName, true);
    return;
    }
    hascur = iter.moveNext();
    }
    
    // Если эта фоновая задача еще не была зарегистрирована.
    BackgroundTaskSample.registerBackgroundTask(
    BackgroundTaskSample.servicingCompleteTaskEntryPoint,
    BackgroundTaskSample.servicingCompleteTaskName,
    new Windows.ApplicationModel.Background.SystemTrigger(
    Windows.ApplicationModel.Background.SystemTriggerType.servicingComplete, false),
    null);
    },

    В примере, задачи, связанные с данными триггерами, реализованы на C# в WinRT-компонентах, которые можно найти в проекте Tasks решения примера. Я не буду показывать здесь их код, так как мы посмотрим на стандартную структуру компонентов WinRT в Главе 5. Однако, это показывает, что мы можем использовать подход с применением разных языков для фоновых задача. В подобных случаях поле Точка входа (Entry Point) для задач в манифесте указывает на класс/метод C#, который реализует фоновую задачу, как, например, Tasks.ServicingComplete. Если вы перейдете на страницу примера "Фоновая задача" (http://code.msdn.microsoft.com/windowsapps/Background-Task-Sample-9209ade9), вы так же можете загрузить C# и C++-версии примеры для того, чтобы увидеть более структурные варианты.

    Задачи, зависимые от экрана блокировки и триггеры

    Последняя группа фоновых задач, это те, которые требуют, чтобы приложение было добавлено на экран блокировки. Для них существует четыре применимых опции ) (Таймер), ) (Push-уведомления), и ) (Канал управления). Они описаны в следующей таблице вместе с указанием доступных примеров, демонстрирующих их использование:

    SystemTriggerType Когда вызываются, сценарии и примеры
    SystemTriggerType.controlChannelReset Смотрите ControlChannelTrigger ниже.
    SystemTriggerType.sessionConnected Пользователь вошел в систему с экрана блокировки.
    SystemTriggerType.userAway Устройство перешло в неактивный режим (например, отключился экран) в результате отсутствия активности пользователям.
    SystemTriggerType.userPresent Пользователь проявил активность в режиме неактивности устройства.
    Windows.Networking.Sockets.ControlChannelTrigger Оповещения реального времени поступают через канал управления (control channel), то есть – через сетевой канал, обычно использующий сокеты или другие сетевые средства передачи данных, если нет возможности использовать WNS и необработанных уведомления для тех же самых целей. Данный триггер используется в приложениях организации связи в реальном времени, такой, как VoIP, IM, элеатронная почта, таким образом, эти возможности "всегда достижимы", если пользователь поместит их на экран блокировки. Мы рассмотрим сетевые средства передачи данных в Главе 3, но эта тема, в полном объеме, находится за пределами данного курса. Обратитесь к материалу "Настройка параметров фонового подключения" (http://msdn.microsoft.com/library/windows/apps/Hh771189.aspx) в документации, а так же – к следующим примерам, все из которых написаны на C# или C++ и не доступны в JavaScript-варианте:
  • Пример "ControlChannelTrigger StreamSocket" ( http://code.msdn.microsoft.com/windowsapps/ControlChannelTrigger-TCP-20c56711)
  • Пример "ControlChannelTrigger XmlHttpRequest" (http://code.msdn.microsoft.com/windowsapps/ControlChannelTrigger-6aedf1bc)
  • Пример "ControlChannelTrigger StreamWebSocket" (http://code.msdn.microsoft.com/windowsapps/ControlChannelTrigger-91f6bed8 )
  • Пример "HTTP-клиент ControlChannelTrigger" ( http://code.msdn.microsoft.com/windowsapps/ControlChannelTrigger-HTTP-9d7a6b3d)
  • SystemTriggerType.controlChannelReset используется для управления фоновой задачей для изменений в канале управления вместо событий самого канала.
    TimeTrigger Заданный срок действия триггера. Это показано в Сценарии 5 примера "Фоновая задача" (http://code.msdn.microsoft.com/windowsapps/Background-Task-Sample-9209ade9) (смотрите ниже).
    PushNotificationTrigger Необработанное push-уведомление для приложения поступило от WNS. Так как Windows не может непосредственно обрабатывать такие уведомления, этот вид фоновых задач необходим для того, чтобы выполнять действия, основанные на необработанных уведомлениях, когда приложение не исполняется. Выполняющееся приложение, с другой стороны, может использовать событие pushnotificationreceived, как описано выше. Кроме того, вы можете обратиться к примеру "Необработанные уведомления" ( http://code.msdn.microsoft.com/windowsapps/Raw-notifications-sample-3bc28c5d).

    Примечание. В имитаторе Visual Studio работа с экраном блокировки не поддерживается. для отладки приложений экрана блокировки, вам нужно использовать опции отладки Локальный компьютер (Local Machine) или Удалённый компьютер (Remote Machine).

    Фоновые задачи для этих триггеров создаются и регистрируются так, как мы уже видели. Например, TimeTrigger, создаётся с указанием интервалам freshnessTime (в минутах) и флага oneShot, как показано в Сценарии 5 примера "Фоновая задача" (js/time-trigger-background-task.js):

    BackgroundTaskSample.registerBackgroundTask(
     BackgroundTaskSample.sampleBackgroundTaskEntryPoint,
     BackgroundTaskSample.timeTriggerTaskName,
     new Windows.ApplicationModel.Background.TimeTrigger(15, false), null);

    ) для того, чтобы позволить пользователю добавить навигационное приложение на экран блокировки, чтобы оно могло более последовательно отслеживать его перемещения. Вообще говоря, навигационное приложение обычно не особенно полезно на экране блокировки, преимущественно потому что оно не может показывать карту! Лучше, таким образом, использовать API Windows.System.Display.DisplayRequest для того, чтобы предотвратить отображение экрана блокировки.

    Создание ), в Сценарии 1 (js/scenario1.js):

    function registerBackgroundTask() {
    // Регистрирует фоновую задачу для необработанных уведомлений
    var taskBuilder = new background.BackgroundTaskBuilder();
    var trigger = new background.PushNotificationTrigger();
    taskBuilder.setTrigger(trigger);
    taskBuilder.taskEntryPoint = sampleTaskEntryPoint;
    taskBuilder.name = sampleTaskName;
    
    var task = taskBuilder.register();
    task.addEventListener("completed", backgroundTaskComplete);
    }

    Хотя и можно выполнить вызов . У приложения нет возможности этим управлять – всё, что оно может сделать, запросив соответствующие данные – это убедиться в том, что доступно для выбора пользователем в соответствующем разделе Настроек ПК (PC Settings).

    Запрос выполняется с помощью метода Windows.ApplicationModel.Background.BackgroundExecutionManager.requestAccessAsync; даннй вызов следует выполнить до регистрации фоновой задачи (снова смотрите Сценарий 5 примера "Фоновая задача"):

    Windows.ApplicationModel.Background.BackgroundExecutionManager.requestAccessAsync();

    Когда этот вызов осуществляется впервые, он вызывает окно для получения согласия пользователя, которое показано на рис 6.2. Если пользователь выбирает вариант Разрешить (Allow), приложение появится в соответствующем разделе Параметров ПК (PC Settings) в качестве опции для добавления на начальный экран, в противном случае этого не произойдет. Как и в случае с другими разрешениями, пользователи могут изменять свое мнение позже, воспользовавшись настройками Разрешений (Permissions), как показано на рис 6.3.

    (рис 6.2) Вопрос, который задаётся пользователю, если приложению нужен доступ к экрану блокировки (рис 6.3) Параметр экрана блокировки на панели настройки Разрешений (Permissions) приложения, которому нужен подобный доступ

    Для того, чтобы увидеть полную демонстрацию, обратитесь к примеру "Приложения экрана блокировки" (http://code.msdn.microsoft.com/windowsapps/Lock-screen-apps-sample-9843dc3a). В Сценарии 1 он показываеть, как запрашивать доступ к экрану блокировки и проверять результат – значение из перечисления BackgroundAccessStatus (http://msdn.microsoft.com/library/windows/apps/windows.applicationmodel.background.backgroundaccessstatus.aspx). Он так же показываеть выполнение запросов и отключение этого доступа с помощью методов getAccessStatus и removeAccess объекта BackgroundExecutionManager.

    Сценарий 2, в свою очередь, показывает отправку уведомлений индикатора событий на экран блокировки, вместе с обновлением текста около часов, если приложение выбрано для отображения этого текста. Здесь нет ничего особенного, если речь идёт об экране блокировки: подобные обновления происходят точно так же, как и для плитки приложения. Разница лишь в том, что эти обновления отображаются на экране блокировки. В случае с индикаторами событий, глиф уведомления отображается вместе с изображением, которое задает параметр Эмблема (Badge Logo), заданный в разделе Интерфейс приложения > Уведомления (Application UI > Notifications) манифеста (рис 6.1). Повторяя из ранее упомянутого, это изображение может иметь лишь белые и прозрачные пиксели и должно быть представлено в трех размерах для разного уровня масштабирования: 24x24 (100%), 33x33 (140%), и 43x43 (180%).

    Сценарий 3, наконец, показывает, как добавить дополнительные плитки на экран блокировки, независимо от плитки приложения. Для того чтобы дополнительная плитка была доступна для экрана блокировки, подразумевая, что приложение уже запросило доступ к экрану блокировки, вам нужно установить следующие два свойства объекта ), которые мы как-то упоминали: lockScreenBadgeLogo и lockScreenDisplayBadgeAndTileText. Если дополнительная плитка присутствует на начальном экране, эти свойства так же делают её доступной на странице Параметров ПК (PC Settings) для экрана блокировки.

    Отладка фоновых задач

    К данному моменту вы уже, возможно, запустили фоновую задачу TimeTrigger в Сценарии 5 примера "Фоновые задачи", и хотя с того времени прошло уже больше 15 минут (может быть больше 30 минут, если вы просто пропустили 15-минутное окно, когда таймеры объединились), вы, возможно, всё еще ждете, пока пройдёт этот период. Значит ли это, что ваша жизнь при отладке фоновых задач будет состоять из сплошного ожидания?

    К счастью, ответ на этот вопрос – "Нет" и "Возможно". То есть, отладчик Visual Studio знает о зарегистрированных фоновых задачах и предоставляет их список в выпадающем меню Приостановить (Suspend) на панели инструментов:

    Выбор одной из этих команд немедленно вызовет фоновую задачу, так что вам не придется ждать или пытаться активировать триггер по-настоящему. Первое предостережение заключается в том, что если свойство триггера oneShot установлено в true и он уже был вызван, снова он вызван не будет. Второе предостережение заключается в том, что если вы запускаете JavaScript-приложение с фоновыми задачами, написанными на других языках, вам нужно изменить тип отладчика для основного проекта приложения с Только скрипт (Script Only) на Управляемый (Managed) или Машинный (Native), как показано ниже, иначе вы не сможете устанавливать точки останова в модулях, написанных на других языках.

    Третье предостережение заключается в том, что фоновые задачи, которые используют ControlChannelTrigger, PushNotificationTrigger, и SystemTriggerType.SmsReceived не отображаются в вышеупомянутом меню Visual Studio.

    Таким образом, может возникнуть необходимость воспользоваться проверенными методами вывода диагностических данных для того, чтобы понять, что происходит с вашей задачей и наблюдать за событиями в Просмотре событий (Event Viewer) на предмет ошибок при активации. Подробнее об этих методах можно узнать в материале "Отладка фоновой задачи" (http://msdn.microsoft.com/library/windows/apps/jj542415.aspx).

    И, наконец, еще раз отмечу, что фоновые задачи не поддерживаются в имитаторе Visual Studio, как и динамические плитки, уведомления и многие другие механизмы, упомянутые в этой лекции. Вам нужно использовать, вместо этого, опции Локальный компьютер (Local Machine) или Удалённый компьютер (Remote Machine).

    Что мы только что изучили (Ух ты!)

  • Обновления плиток – основной и дополнительных, обновления индикаторов событий, всплывающие уведомления, фоновые задачи, из которых приложение может отправлять обновления плиток и уведомления – это то, как приложение делает свой вклад в общий динамизм системы даже тогда, когда оно не исполняется.
  • Обновления и уведомления, конечно, могут быть отправлены из исполняющегося приложения, но существуют другие методы для доставки подобных обновлений, когда приложение не исполняется. Обновления могут быть запланированы для показа через некоторое время, приложение может настроить систему для периодического запроса некоего сервиса на предмет обновлений для плиток и индикаторов событий. Приложения так же могут настраивать push-уведомления, которые исходят от веб-сервиса и отправляются клиенту посредством Windows Push Notification Service (WNS).
  • Обновления плиток отправляют с использованием полезных данных XML на основе предопределенных шаблонов. Обычно данные включают в себя обновления и для квадратных, и для прямоугольных плиток, так как польозватель может выбрать, какая именно плитка будет отображаться. XML может ссылаться на изображения как из локальных, так и из удаленных источников, изображение не может быть больше, чем 1024x1024 пикселя, его размер не должен превышать 200 Кб.
  • Плитка в любое время может циклически отображать до пяти обновлений, каждое из которых может быть заменено отдельно от других.
  • Приложения, имеющие особое содержимое, которое пользователю может быть интересно прикрепить на Начальном экране в качестве дополнительной плитки, предоставляют команды Прикрепить (Pin) и Открепить (Unpin). Дополнительные плитки, при запуске приложения со специальными аргументами запуска, так же могут принимать обновления динамических плиток.
  • Индикаторы событий – это маленькие значки (глифы) или числа, которые могут отображаться на любой плитке. Обновления индикаторов событий отправляются с помощью тех же самых механизмов, что и обновления плиток, но работают они самостоятельно.
  • Всплывающие уведомления (toasts) – это уведомления, которые появляются для того, чтобы оповестить пользователя о новой информации, сделать напоминание и так далее. Они могут быть настроены для проигрывания звуков, установлены для повторения через заданный интервал, запланированы для появления в будущем. Как и дополнительные плитки, всплывающие уведомления, при активации, запускают приложение со специальными стартовыми аргументами.
  • Периодические обновления для плиток и индикаторов событий предусматривают передачу Windows URI веб-сервиса для вызова через выбранный интервал – от 30 минут до 24 часов. Периодические обновления – это самый простой и наименее затратный способ для обновления плитки с помощью веб-сервиса.
  • Push-уведомления для плиток, индикаторов событий, всплывающих уведомлений, и необработанные уведомления (содержащие любые необходимые данные), можно использовать для обновлений, привязанных к конкретному пользователю и производимых с высокой частотой. Их использование включает в себя создание веб-сервиса, который связывается с WNS для отправки подобных уведомлений по заданным URI каналов, процесс, который сложнее и затратнее, чем работа с периодическими обновлениями.
  • Фоновые задачи – это небольшие фрагменты кода, которые приложение настраивает на запуск при срабатывании определенного триггера, такого, как изменения в условиях подключения к сети, таймера, приём push-уведомления, и при обновлении программы. Однако приложениям никогда не следует зависеть от фоновых задач, так как они всегда находится под управлением пользователя.
  • Триггеры фоновых задач могут быть тонко настроены с использованием специальных условий для того, чтобы избежать исполнения задач тогда, когда в этом нет необходимости (например, тогда, когда нет подключения к Интернету).
  • Для работы некоторых триггеров требуется, чтобы приложение было добавлено на экран блокировки. Такие приложения сначала должны запросить доступ, что зависит от решения пользователя, и пользователь должен добавить приложение посредством Параметров ПК (PC Settings). Получив подобную привилегию, приложения могут отправлять обновления значков и текста на экран блокировки.
  • Посредством триггеров обслуживания, приложения могут настраивать задачи, которые исполняются периодически, когда устройство подключено к источнику питания.
  • Страницы:

    Вот мы и добрались до того места этой лекции, где мы можем отвлечься от исполняющихся приложений и посмотреть на больше интересных вещей, которые происходят в глубинах системы. Раньше, в "Периодических обновлениях", мы узнали, что самый короткий интервал, который может использовать этот метод, слишком велик по компьтерным меркам: 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 (Повторно открыть канал и отправить на сервер). При этом должна сработать точка останова в сервисе, что позволить вам пошагово исполнить код, который обрабатывает запрос. Здесь вы можете обнаружить, что запрос содержит значения ).

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

    Прежде чем сервис сможет отправлять обновления, он должен пройти проверку подлинности с помощью 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_credentialsclient_id=ms-app%3a%2f%2fS-1-15-2-2972962901-2322836549-3722629029-13452385
      79-3987825745-2155616079-650196962client_secret=Vex8L9WOFZuj95euaLrvSH7XyoDhLJc7scope=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 заниматься деталями их доставки.

    Необработанные уведомления (Сервис)

    Если вы, в качестве типа push-уведомления используете wns/raw, полезные данные, включенные в уведомление могут быть чем угодно, а не только XML, но их размер не может превышать 5 Кб.

    Конечно, Windows не может непосредственно что-либо сделать с этими данными, таким образом приложение должно предоставить обработчик для приёма этих уведомлений, как рассказано в следующем разделе.

    Приём уведомлений (приложение)

    Выполняющееся приложение принимает push-уведомление посредством PushNotificationChannel.onpushnotificationreceived. Это, опять же, нужно для обработки полезной информации из wns/raw уведомлений, но может использоваться и для других видов уведомлений. Если приложение не исполняется, то, конечно, оно не может принять это событие. Вместо этого, приложение должно присуствовать на экране блокировки с фоновой задачей PushNotificationTrigger, предназначенной для этой цели (смотрите "Задачи, зависимые от экрана блокировки и триггеры" ниже в этой лекции). Этот код затем принимает полезные данные XML, обрабатывает их и отправляет, при необходимости, либо обновления плиток, либо индикаторов событий, либо всплывающие уведомления. Помимо сохранения некоторых данных в папки данных приложения, это, на самом деле, всё, что могут делать фоновые задачи, но этого достаточно для сохранения ощущения динамичности приложений и для приглашения пользователей к запуску приложений.

    В выполняющемся приложения вызывается событие pushnotificationreceived так же для других типов уведомлений. Сценарий 3 примера показывает это в его обработчике событий – я, для упрощения, слегка изменил этот код:

    function startListening() {
     // Предполагаем, что канал получен и проверен
     channel.addEventListener("pushnotificationreceived", pushNotificationReceivedHandler);
     }
     function pushNotificationReceivedHandler(e) {
     // Извлекаем полезные данные уведомления для каждого типа уведомлений
    
     var notificationPayload;
     switch (e.notificationType) {
     case pushNotifications.PushNotificationType.toast:
     notificationPayload = e.toastNotification.content.getXml();
     break;
    
     case pushNotifications.PushNotificationType.tile: notificationPayload = e.tileNotification.content.getXml(); break;
    
     case pushNotifications.PushNotificationType.badge:
     notificationPayload = e.badgeNotification.content.getXml();
     break;
    
     case pushNotifications.PushNotificationType.raw:
     notificationPayload = e.rawNotification.content;
     break;
     }
    
     // Обработка уведомления: установите e.cancel в true для подавления автоматической обработки.
     }

    Последняя часть в вышеприведенных комментариях важна. Когда вы принимаете событие в исполняющемся приложении, не нужно показывать всплывающее уведомление, только если оно не имеет отношения к какой-то части приложения, которая сейчас невидима. Например, если у вас есть приложение, которое работает и с электронной почтой и с календарём, вам захочется сделать видимыми всплывающие уведомления об электронной почте, когда пользователь видит календарь, и уведомления о событиях календаря, когда он работает с электронной почтой. В данном случаае установка e.cancel в true не позволит отобразиться всплывающему уведомлению.

    В событии ) для того, чтобы узнать подробности об этом.

    Советы по отладке

    При использовании push-уведомлений, практика показывает, что если уведомления не доставляются на устройство, обычно это не из-за проблемы с WNS. Вот списко того, что надо проверить (Спасибо Гансу Андерсену за этот список):

  • Проверьте статус возврата ваших запросов HTTP POST к WNS. Если возвращается ответ HTTP 200, проверьте X-WNS-NotificationStatus и другие полученные заголовки. В частности, ищите статус "Received", который показывает, что уведомление доставлено клиенту.
  • Не обнаружив ничего убедительного в заголовках, запустите Просмотр журналов событий (Event Viewer) и проверьте события в разделе Журналы приложений и служб > Microsoft > Windows > Push Notifications Platform > Operational ( Application And Services Logs > Microsoft > Windows > Push Notifications Platform > Operational) для того, чтобы посмотреть на деятельность по приему уведомлений.
  • Кроме того, посмотрите в разделе Журналы приложений и служб > Microsoft > Windows > Immersive-Shell > Microsoft-Windows-TWinUI > Operational (Application And Services Logs > Microsoft > Windows > Immersive-Shell > Microsoft-Windows-TWinUI > Operational) для того, чтобы увидеть, есть ли здесь сообщения об ошибках, связанные с обработкой XML, примерно в то время, когда вы ожидаете поступление уведомления.
  • Если даже с XML всё в порядке, обновление может не отобразиться, если изображение, указанное в нём, либо слишком большое (в пискелях, или по размеру файла), если оно имеет неподходящий формат (например, TIF), если изображение повреждено, если сервер, обрабатывающий запрос на получение изображения, не может обработать параметры запроса для плитки (масштабирование, контрастность, язык), или если сервер столкнулся с другой ошибкой, которую можно обнаружить в его собственных журналах.
  • Если обновление появляется, но после значительной задержки, это может означать либо внутренние задержки или другие задержки в сети, связанные с инфраструктурой плиток и уведомлений. Если это происходит, просто примите к сведению, что мир не всегда совершенен и операции иногда приходится повторять!
  • Windows Azure Toolkit и Windows Azure Mobile Services

    Очевидно, много работы нужно для создания службы, которая может принимать URI канала и отправлять уведомления через WNS. Признавая это, Windows Azure Toolkit (http://watwindows8.codeplex.com/) снова предлагает некоторые решения. Рассмотрение всех подробностей выходит за рамки этого курса, но ссылки ниже помогут вам начать с этим разрибаться. В частности, "Пример уведомлений Azure" (http://watwindows8.codeplex.com/wikipage?title=Notifications%20Sample%20%E2%80%93%20C%23%20and%20JavaScript) и "Пример о необработанных уведомлениях" (http://watwindows8.codeplex.com/wikipage?title=Raw%20Notifications%20Sample), так же "Пример рабочего процесса push-уведомлений" (http://watwindows8.codeplex.com/wikipage?title=Push%20Notification%20Worker%20SamplereferringTitle=Documentation). Вот полезное видео на сайте Channel 9: "Эпизод 73 – Ник Харрис о push-уведомлениях для Windows 8" (http://channel9.msdn.com/Shows/Cloud+Cover/Episode-73-Nick-Harris-on-Push-Notifications-for-Windows-8). Дополнительные ресурсы, весьма вероятно, будут опубликованы после того, как была написана эта лекция, поэтому поиск в Интернете позволит вам найти больше материалов.

    Кроме того, посмотрите на "Мобильные сервисы Windows Azure" (http://www.windowsazure.com/en-us/develop/mobile/?fb=ru-ru), которые помогут вам создать масштабируемую серверную часть приложения, в том числе – структурированные облачные данные, проверку подлинности, и push-уведомления. Этот новые сервисы, на момент написания, поэтому у меня нет ссылок на другие ресурсы, но, совершенно очевидно, их стоит изучить.

    Фоновые задачи и приложения экрана блокировки

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

    Позвольте мне повторить здесь, что мы уже видели ряд сценариев, где пользователь может ожидать некоторой деятельности, связанной с приложением без необходимости запуска приложения. Периодические обновления плиток, push-уведомления, запланированные всплывающие уведомления и даже передача данных через контракт Общий доступ производят полезную деятельность , когда приложение приостановлено или не исполняется. Приложения так же могут настраивать фоновую передачу данных, которая выполняется, когда приложение не запущено, как мы увидим в Главе 3. А возможность фонового воспроизведения музыки предоставлена для специального класса приложений, которым нужно выполняться для поддержки сеансов связи VoIP, воспроизведения аудио, онлайновых бесед и так далее.

    Что нам осталось рассмотреть – так это те самые небольшие фрагменты кода приложения, которые Windows может запускать в ответ на различные триггеры. Триггеры, в некоторых случаях, могут подвергнуться дальнейшей настройке в соответствии с дополнительными условиями, в итоге фоновая задача исполняется только тогда, когда в этом есть реальная необходимость. Всё это делается для уменьшения количества фоновой деятельности, которая истощает батареи устройства. Некоторые типы триггеров, на самом деле, требуют, чтобы пользователь поместил приложение на экран блокировки для того, чтобы преднамеренно ограничить количество приложений, которые могут реагировать на эти триггеры. Более того, Windows так же ограничивает процессорное время, которое могут потреблять подобные фоновые задачи:

  • Фоновые задачи экрана блокировки: две секунды общего времени процессора за 15 минут.
  • Другие фоновые задачи: одна секунда общего времени процессора каждые два часа.
  • Использование сетевого соединения так же ограничено в связи с затратами энергии батарей. Что это за ограничение, я не могу точно сказать, так как система анализирует использование энергии более пристально, нежели количество переданной информации. Средства оценки предела можно найти в материале "Поддержка приложения с помощью фоновых задач" (http://msdn.microsoft.com/library/windows/apps/hh977046.aspx). (Пока мы говорим об этом, вам, возможно, будет интересно посмотреть "Руководство и контрольный список для фоновых задач" (http://msdn.microsoft.com/library/windows/apps/Hh977043.aspx), документ "Введение в фоновые задачи" ( http://www.microsoft.com/en-us/download/details.aspx?displaylang=enid=27411), и материал "Поддержание производительности при работе приложения в фоновом режиме — фоновые задачи" (http://blogs.msdn.com/b/windowsappdev_ru/archive/2012/06/01/10313828.aspx) в блоге для разработчиков приложений для Windows 8).

    Возможно, вы подумали: "Ничего себе! Разве Windows 8 на самом деле имеет подобные ограничения?".

    Коротко говоря – да, так как Windows не только стремится сэкономить энергию батарей для приложений переднего плана, с которыми работает пользователь, но так же она стремится к тому, чтобы от приложений переднего плана у пользователя остались бы наилучшие впечатления. Это подразумевает, что система не хочет столкнуться с фоновыми приложениями, которые, если им это позволить, занимают столько ресурсов, сколько смогут. (Разработчики фоновых служб всегда найдут оправдание для захвата ресурсов!).

    Возможно, вы попадали в такую ситуацию, когда вы запускаете приложение, но его запуск занимает целую вечность, так как некие таинственные службы интенсивно используют жёсткий диск, передают данные по сети, нагружают процессор и так далее. Я, например, в подобной ситуации разбираюсь в чём дело, с помощью Диспетчера задач и Монитора ресурсов, после чего останавливаю любой процесс, который пожирает ресурсы моей системы – и будь что будет. Именно возникновения подобных впечатлений у пользователя и пытается избежать Windows 8.

    "Хорошо", - скажете вы (при условии, что я, в некоторой степени, вас убедил), - "Означает ли это, что нет способа для выполнения некоторой фоновой работы наподобие индексирования данных, создания экскизов изображения, обработки видео и так далее?".

    На самом деле, есть способы для того, чтобы это сделать. Во-первых, когда приложение находится на переднем плане, оно может делать подобные вещи в любых объёмах, так как оно, в конечно счете, отвечает за то, какие впечатления у пользователя создаст взаимодействие с ним. (Приложения, написанные на JavaScript, могут для подобных целей, использовать рабочие веб-процессы для того, чтобы убрать выполнение подобных задач из потока пользовательского интерфейса, а так же – передавать задачи компонентам WinRT, которые выполняют их дела в других потока и асинхронно возвращают результат. Мы ознакомимся с этим в Главе 5.).

    Во-вторых, когда устройство подключено к сети переменного тока, а не работает от батарей, Windows позволяет фоновым задачам, запущенным для обслуживания триггеров, работать по 15 минут или дольше (в зависимости от нужд приложения). Здесь всё еще применимы ограничения ресурсов процессора, которые они могут потреблять, но задачи, которые не задействуют пользовательский интерфейс, который не разрешено использовать фоновым задачам – могут выполнить несколько миллиардов инструций за одну или две секунду на гигагерцовом процессоре!

    Что мы имеем в итоге, так это то, что существует три различных класса фоновых задач и связанных с ними триггеров:

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

    Фоновые задачи в манифесте

    Все фоновые задачи для приложения объявляются в манифесте, где каждое объявление указывает на тип задачи и на код, который должен исполняться для выполнения этой задачи, как показано на рис 6.1. Мы видели этот раздел манифеста в Главе 4 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript", где мы выбирали пункт Звук (Audio) для приложения, которое воспроизводит в фоновом режиме музыку. Что касается других параметров, то Системное событие (System Event) используется для первых двух классов вышеперечисленных задач, опции Канал управления (Control Channel), Таймер (Timer) и Push-уведомления (Push Notification) предназначены для задач, которые связаны с приложениями экрана блокировки.

    (рис 6.1) Редактор манифеста при объявлении фоновых задач. Показаны параметры для объявления Фоновые задачи (Background Tasks) из выпадающего списка Доступные объявления (Available Declarations) (слева), и типы фоновых задач (в центре), и поле Начальная страница (Start Page) для указания JavaScript-кода, который нужно исполнить для задачи (внизу). Фоновые задачи так же могут быть написаны на других языках, в подобных случаях используются поля Исполняемый файл (Executable) и Точка входа (Entry Point)

    Во всех случаях, поле Начальная страница (Start Page) – это то место, где вы указываете JavaScript-файл, который будет исполняться для этой задачи независимо от приложения, передавая ему информацию лишь через папки данных приложения, вы, на самом деле, можете использовать здесь любой язык, какой хотите. Учитывая квоты на процессорное время, написание фоновых задач на языке вроде C++ или C# позволит вам выполнять некоторые задачи более эффективно, и в подобном случае вы будете использовать поле Точка входа (Point field )(если задача реализована в виде DLL, которая находится в пакете приложения), и, возможно, поле Исполняемый файл (Executable) (если задача реализована с помощью EXE-файла, который так же расположен в пакете приложения) для идентификации кода модуля и конкретной функции для вызова.

    Полезно отметить, что даже хотя в поле Начальная страница (Start Page) для JavaScript ожидается указание страницы, там, на самом деле, может быть лишь код для фоновой задачи – вы получите ошибку, если попытаетесь задать в этом поле HTML-файл. (Для того, чтобы говорить точнее, фоновые задачи на JavaScript – это рабочие веб-процессы, простые и понятные). А почему фоновые задачи не могут отображать пользовательский интерфейс, так это потому, что Windows не загрузит HTML или CSS-код, лишь JavaScript! Таким образом, отправляя обновления плиток, индикаторов событий и всплывающие уведомления – это все дела, связанные с пользовательским интерфейсом, которые могут выполнять фоновые задачи. Для выполнения чего-то другого, фоновая задача должна записать некоторое значение в папку данных приложения, а это значение должно, с помощью обработчиков событий для фоновых задач, получить и обработать основное приложение, что мы скоро увидим.

    Вы можете заметить, что параметр Системное событие (System Event) в редакторе манифеста не предусматривает поля, где вы можете задать триггер для задачи. Это выполняется в коде, при создании задачи, как мы увидим в ближайшее время.

    Создание и регистрация фоновой задачи

    Объявление фоновой задачи в манифесте – это лишь объявление, которое сообщает системе о том, что приложение намеревается использовать фоновую задачу. Приложение должно зарегистрировать фоновую задачу из кода для того, чтобы она могла исполняться, что реализуется с помощью ) (его родительское пространство имен содержит всё, к чему мы будем обращаться в контексте фоновых задач). Проще говоря, вы создаете экземпляр средства для создания фоновой задачи, задаёте его свойства name и taskEntryPoint, вызываете его методы setTrigger и addCondition для указания того, когда следует запускать фоновую задачу, и затем вызываете register.

    Обычный код для этого можно найти в примере "Фоновая задача" (http://code.msdn.microsoft.com/windowsapps/Background-Task-Sample-9209ade9), в js/global.js.

    Этот модуль объявляет глобальный объект BackgroundTaskSample, который содержит свойства и методы. Нас здесь интересует метод, который называется registerBackgroundTask, он регистрирует заданную точку входа (имя JavaScript-файла или имя класса в C#, Visual Basic, или C++), с заданным именем и применяет некоторые триггеры и условия.

    var BackgroundTaskSample = {
    // Свойства, содержащие имена и точки входа для задач примера опущены
    
    //
    // Регистрация фоновой задачи с заданными taskEntryPoint, taskName, trigger,
    // и condition (дополнительно).
    //
    "registerBackgroundTask": function (taskEntryPoint, taskName, trigger, condition) {
    var builder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder();
    
    builder.name = taskName; builder.taskEntryPoint = taskEntryPoint; builder.setTrigger(trigger);
    
    if (condition !== null) {
    builder.addCondition(condition);
    }
    
    var task = builder.register(); BackgroundTaskSample.attachProgressAndCompletedHandlers(task);
    
    // [Опущен код, отражающий особенности примера]
    
    // Удаление предыдущего статуса завершения из локальных параметров.
    var settings = Windows.Storage.ApplicationData.current.localSettings;
    settings.values.remove(taskName);
    },

    В этом коде метод ), с помощью которого управляют зарегистрированной задачей. У зарегистрированной задачи есть свойство name и назначенное системой свойство taskId, последнее из них вы можете использовать для сохранения данных приложения, которые уникальны для задачи. Так же у него есть метод unregister, который вы можете вызвать для отмены регистрации, и два события: completed и progress. Обработчики для этих событий назначают обычным способом, с помощью addEventListener, как показано в функции BackgroundTaskSample.attachProgressAndCompletedHandlers в примере:

    "attachProgressAndCompletedHandlers": function (task) {
     task.addEventListener("progress",
     new BackgroundTaskSample.progressHandler(task).onProgress);
     task.addEventListener("completed",
     new BackgroundTaskSample.completeHandler(task).onCompleted);
     },

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

    Здесь присутствует одно статическое свойство, BackgroundTaskRegistration.allTasks, объект IMapView , с помощью которого вы можете получить свои зарегистрированные задачи и получить для каждого отдельный объект BackgroundTaskRegistration.

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

    Имея подобную структуру, мы можем задаться вопросом: что мы делаем для настройки триггеров и условий? Ответ на этот вопрос – это то, что различает разные виды фоновых задач.

    Условия

    Конкретные условия вы можете задать с помощью объекта ), который является экземпляром класса ). Фоновая задача, зарегистрированная с одним или большим количеством условий – каждый вызов addCondition приводит к добавлению очередного условия – будет запланирована к выполнению только если все условия выполняются.

    Каждый экземпляр может иметь один из следующих типов, заданных в перечислении SystemConditionType: internetAvailable (интернет-подключение доступно), internetNotAvailable (интернет-подключение не доступно), sessionConnected (пользователь вошёл в систему), sessionDisconnected (пользователь вышел из системы), userPresent (пользователь в настоящий момент занят какими-то делами), и userNotPresent (пользователь ничего не делает некоторое время).

    Очевидно, каждая пара из этих условий является взаимоисключающей: если вы зарегистрировали задачу с условиями internetAvailable и internetNotAvailable, Windows поймёт, что вы никогда не планируете, чтобы эта задача когда-нибудь запускалась, поэтому система оставит её сидеть на обочине и никогда не побеспокоит! С другой стороны, вы можете использовать эти условия для того, чтобы быть уверенным, что ваша задача выполняется только тогда, когда нужна. Если вам нужно запустить фоновую задачу, которая обновляет канал push-уведомлений, например, нет смысла этого делать при отсутствии подключения к Интернету. (В следующем разделе, "Задачи для триггеров обслуживания", мы увидим пример). С другой стороны, если у вас есть фоновая задача, исполнение которой никогда не должно совпадать с активной работой пользователя, вы можете добавить условие userNotPresent.

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

    Задачи для триггеров обслуживания

    Фоновые задачи, использующие триггеры обслуживания, вероятно, являются наиболее общим типом задач – они содержат какой-либо код, который нужно периодически запускать, но только тогда, когда система подключена к источнику питания . Подобные задачи отлично подхдят для "проверки на что-либо", или для другой деятельности, которую нужно выполнять периодически, но при этом не важно – когда точно это произойдёт. Например, триггеры обслуживания не подходят для чего-то вроде синхронизации данных с сервером, так как это должно происходить своевременно, и это лучше будет реализовать с помощью API фоновой передачи данных, которое мы рассмотрим в Главе 3.

    Триггер обслуживания – то, что вы передаете в ). При создании экземпляра предоставляют два параметра. Первый – это необходимый период обновления (свойство freshnessTime, в минутах), всегда следует использовать наибольший период, подходящий для конкретного сценария. Система будет всегда ожидать, как минимум, прохождения этого периода, перед первым запуском задачи. Второй параметр – это флаг, который указывает на то, нужно ли запустить задачу лишь один раз (свойство oneShot).

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

    var background = Windows.ApplicationModel.Background;
      var pushNotificationsTaskName = "UpdateChannels";
      var maintenanceInterval = 10 * 24 * 60; // 10 дней
    
      var taskBuilder = new background.BackgroundTaskBuilder();
      var trigger = new background.MaintenanceTrigger(maintenanceInterval, false);
      taskBuilder.setTrigger(trigger);
      taskBuilder.taskEntryPoint = "js\\backgroundTask.js";
      taskBuilder.name = pushNotificationsTaskName;
    
      var internetCondition = new background.SystemCondition(background.SystemConditionType.internetAvailable);
      taskBuilder.addCondition(internetCondition);
    
      taskBuilder.register();

    Так как срок действия URI канала – 30 дней, пример создаёт триггер, предназначенный для исполнения каждые 10 дней (10 дней * 24 часа в день * 60 минут в часе). Так же сюда разумно добавлено условие internetAvailable, так как не имеет смысла пытаться обновить URI канала, когда нет подключения к Интернету.

    Саму задачу можно найти в файле примера js/backgroundTask.js, что отражено в свойстве taskEntryPoint:

    (function () {
    // Импорт вспомогательного объекта Notifier
    importScripts("//Microsoft.WinJS.1.0/js/base.js");
    importScripts("notifications.js");
    
    var closeFunction = function () {
    close();
    };
    
    var notifier = new SampleNotifications.Notifier();
    notifier.renewAllAsync().done(closeFunction, closeFunction);
    })();

    Код задачи использует пару других скриптовых файла, importScripts, второй из которых, notifications.js, это набор вспомогательных функций образца для уведомлений, где renewAllAsync обновляет список, в котором находятся URI канала, ранее сохраненные приложением.

    Важно. Вы так же можете заметить, что обработчики завершения и ошибки задаваемые в promise-объекте из функции ). Фоновые задачи в приложении, написанном на JavaScript, запускаются в областе видимости рабочего веб-процесса, таким образом, глобальная область в этом коде – это WorkerGlobalScope, а не window. Данный вызов позволяет убедиться в закрытии независимо работающей фоновой задачи и гарантирует, что ресурсы, которые были выделены для задачи, соответствующим образом освобождены.

    Врезка: Экземпляр задачи и острочка фоновой задачи

    В фоновой задаче JavaScript, Windows.UI.WebUI.WebUIBackgroundTaskInstance.current содержит объект WebUIBackgroundTaskInstanceRuntimeClass (http://msdn.microsoft.com/library/windows/apps/windows.ui.webui.webuibackgroundtaskinstanceruntimeclass.aspx), который предоставляет дополнительные сведения о выполняющейся задаче: её instanceId, связанный с ней объект BackgroundTaskRegistration в свойстве task, свойство progress, в котором задача может сохранить процентное значение степени её выполнения, флаг succeeded , который позволяет указать, что задача завершена, свойство suspendedСount (показывает, сколько раз был приостановлена задача при превышении ограничений), и событие canceled , которое сообщает о том, что задача будет закрыта.

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

    Задачи для системных триггеров (не для экрана блокировки)

    Следующий класс фоновых задача содержит следующие привязки к различным системным триггерам, в частности, экземпляры класса ). Объект триггера создают с помощью ключевого слова new и передают два параметра: значение SystemTriggerType value (доступное потом как свойство triggerType) и флаг логического типа oneShot. Эти триггеры могут работать независимо от экрана блокировки, они описаны в следующей таблице:

    SystemTriggerType Когда вызывается и сценарии использования
    internetAvailable Стало доступно подключение к Интернету. Это обычно используется для приложений, которым нужно запустить процесс синхронизации, когда восстанавливается подключение к Интернету. Обратите внимание на то, что этот триггер отличается от условия с тем же самым именем.
    lockScreenApplicationAdded Пользователь добавил прилоежение на экран блокировки, что указывает на то, что фоновые задачи, зависимые от экрана блокировки теперь будут исполняться.
    lockScreenApplicationRemoved Пользователь удалил приложение с экрана блокировки, что указывает на то, что фоновые задачи, зависимые от экрана блокировки, теперь исполняться не будут.
    networkStateChange Изменение сетевых условий (стоимости, типа подключения и так далее). Исполняющееся приложение может обнаружить то же самое с помощью события ).
    onlineIdConnectedStateChange Учетная запись Microsoft пользователя изменена. Это сравнительно редкое событие, но триггер является основным средством для любых приложений, которые кэшируют любые части сведений из учетной записи Microsoft для собственных целей идентификации пользователя.
    servicingComplete Завершено бновление приложения из Магазина Windows. Этот триггер можно использовать, например, для выполнения миграции данных приложения с одной версии на другую как только произойдёт обновлении. Подробнее о версиях данных приложения вы можете узнать в Главе 2 курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript".
    timeZoneChange Изменен часовой пояс или осуществлен переход на летнее или зимнее время. Приложение в этот момент может обновить данные о географическом местоположении, настроить внутренние механизмы, связанные с учетом времени. Это может быть важно для настройки запланированных уведомлений.

    В примере "Фоновая задача" есть несколько примеров этих триггеров. В Сценарии 1, js/sample-background-task-with-condition.js, мы можем видеть использование триггера timeZoneChange и условия userPresent (здесь BackgroundTaskSample это вспомогательный объект из global.js):

    BackgroundTaskSample.registerBackgroundTask(BackgroundTaskSample.sampleBackgroundTaskEntryPoint,
      BackgroundTaskSample.sampleBackgroundTaskWithConditionName,
      new Windows.ApplicationModel.Background.SystemTrigger(
      Windows.ApplicationModel.Background.SystemTriggerType.timeZoneChange, false),
      new Windows.ApplicationModel.Background.SystemCondition(
      Windows.ApplicationModel.Background.SystemConditionType.userPresent));

    Это явно тот случай, когда я хотел бы использовать другую переменную для того, чтобы каждый раз не вводить обозначение пространства имен Windows.ApplicationModel.Background, но вы, по крайней мере, не ошибетесь, читая этот код! В любом случае, тот же пример, в Сценарии 4 и js/global.js, так же показывает использования триггера servicingComplete со вспомогательной функцией registerServicingCompleteTask, которая так же проверят, была ли задача уже зарегистрирована:

    "registerServicingCompleteTask": function () {
    // Проверяет, была ли уже зарегистрирована фоновая задача servicingComplete.
    var iter =
    Windows.ApplicationModel.Background.BackgroundTaskRegistration.allTasks.first();
    var hascur = iter.hasCurrent;
    while (hascur) {
    var cur = iter.current.value;
    if (cur.name === BackgroundTaskSample.servicingCompleteTaskName) { BackgroundTaskSample.updateBackgroundTaskStatus(
    BackgroundTaskSample.servicingCompleteTaskName, true);
    return;
    }
    hascur = iter.moveNext();
    }
    
    // Если эта фоновая задача еще не была зарегистрирована.
    BackgroundTaskSample.registerBackgroundTask(
    BackgroundTaskSample.servicingCompleteTaskEntryPoint,
    BackgroundTaskSample.servicingCompleteTaskName,
    new Windows.ApplicationModel.Background.SystemTrigger(
    Windows.ApplicationModel.Background.SystemTriggerType.servicingComplete, false),
    null);
    },

    В примере, задачи, связанные с данными триггерами, реализованы на C# в WinRT-компонентах, которые можно найти в проекте Tasks решения примера. Я не буду показывать здесь их код, так как мы посмотрим на стандартную структуру компонентов WinRT в Главе 5. Однако, это показывает, что мы можем использовать подход с применением разных языков для фоновых задача. В подобных случаях поле Точка входа (Entry Point) для задач в манифесте указывает на класс/метод C#, который реализует фоновую задачу, как, например, Tasks.ServicingComplete. Если вы перейдете на страницу примера "Фоновая задача" (http://code.msdn.microsoft.com/windowsapps/Background-Task-Sample-9209ade9), вы так же можете загрузить C# и C++-версии примеры для того, чтобы увидеть более структурные варианты.

    Задачи, зависимые от экрана блокировки и триггеры

    Последняя группа фоновых задач, это те, которые требуют, чтобы приложение было добавлено на экран блокировки. Для них существует четыре применимых опции ) (Таймер), ) (Push-уведомления), и ) (Канал управления). Они описаны в следующей таблице вместе с указанием доступных примеров, демонстрирующих их использование:

    SystemTriggerType Когда вызываются, сценарии и примеры
    SystemTriggerType.controlChannelReset Смотрите ControlChannelTrigger ниже.
    SystemTriggerType.sessionConnected Пользователь вошел в систему с экрана блокировки.
    SystemTriggerType.userAway Устройство перешло в неактивный режим (например, отключился экран) в результате отсутствия активности пользователям.
    SystemTriggerType.userPresent Пользователь проявил активность в режиме неактивности устройства.
    Windows.Networking.Sockets.ControlChannelTrigger Оповещения реального времени поступают через канал управления (control channel), то есть – через сетевой канал, обычно использующий сокеты или другие сетевые средства передачи данных, если нет возможности использовать WNS и необработанных уведомления для тех же самых целей. Данный триггер используется в приложениях организации связи в реальном времени, такой, как VoIP, IM, элеатронная почта, таким образом, эти возможности "всегда достижимы", если пользователь поместит их на экран блокировки. Мы рассмотрим сетевые средства передачи данных в Главе 3, но эта тема, в полном объеме, находится за пределами данного курса. Обратитесь к материалу "Настройка параметров фонового подключения" (http://msdn.microsoft.com/library/windows/apps/Hh771189.aspx) в документации, а так же – к следующим примерам, все из которых написаны на C# или C++ и не доступны в JavaScript-варианте:
  • Пример "ControlChannelTrigger StreamSocket" ( http://code.msdn.microsoft.com/windowsapps/ControlChannelTrigger-TCP-20c56711)
  • Пример "ControlChannelTrigger XmlHttpRequest" (http://code.msdn.microsoft.com/windowsapps/ControlChannelTrigger-6aedf1bc)
  • Пример "ControlChannelTrigger StreamWebSocket" (http://code.msdn.microsoft.com/windowsapps/ControlChannelTrigger-91f6bed8 )
  • Пример "HTTP-клиент ControlChannelTrigger" ( http://code.msdn.microsoft.com/windowsapps/ControlChannelTrigger-HTTP-9d7a6b3d)
  • SystemTriggerType.controlChannelReset используется для управления фоновой задачей для изменений в канале управления вместо событий самого канала.
    TimeTrigger Заданный срок действия триггера. Это показано в Сценарии 5 примера "Фоновая задача" (http://code.msdn.microsoft.com/windowsapps/Background-Task-Sample-9209ade9) (смотрите ниже).
    PushNotificationTrigger Необработанное push-уведомление для приложения поступило от WNS. Так как Windows не может непосредственно обрабатывать такие уведомления, этот вид фоновых задач необходим для того, чтобы выполнять действия, основанные на необработанных уведомлениях, когда приложение не исполняется. Выполняющееся приложение, с другой стороны, может использовать событие pushnotificationreceived, как описано выше. Кроме того, вы можете обратиться к примеру "Необработанные уведомления" ( http://code.msdn.microsoft.com/windowsapps/Raw-notifications-sample-3bc28c5d).

    Примечание. В имитаторе Visual Studio работа с экраном блокировки не поддерживается. для отладки приложений экрана блокировки, вам нужно использовать опции отладки Локальный компьютер (Local Machine) или Удалённый компьютер (Remote Machine).

    Фоновые задачи для этих триггеров создаются и регистрируются так, как мы уже видели. Например, TimeTrigger, создаётся с указанием интервалам freshnessTime (в минутах) и флага oneShot, как показано в Сценарии 5 примера "Фоновая задача" (js/time-trigger-background-task.js):

    BackgroundTaskSample.registerBackgroundTask(
     BackgroundTaskSample.sampleBackgroundTaskEntryPoint,
     BackgroundTaskSample.timeTriggerTaskName,
     new Windows.ApplicationModel.Background.TimeTrigger(15, false), null);

    ) для того, чтобы позволить пользователю добавить навигационное приложение на экран блокировки, чтобы оно могло более последовательно отслеживать его перемещения. Вообще говоря, навигационное приложение обычно не особенно полезно на экране блокировки, преимущественно потому что оно не может показывать карту! Лучше, таким образом, использовать API Windows.System.Display.DisplayRequest для того, чтобы предотвратить отображение экрана блокировки.

    Создание ), в Сценарии 1 (js/scenario1.js):

    function registerBackgroundTask() {
    // Регистрирует фоновую задачу для необработанных уведомлений
    var taskBuilder = new background.BackgroundTaskBuilder();
    var trigger = new background.PushNotificationTrigger();
    taskBuilder.setTrigger(trigger);
    taskBuilder.taskEntryPoint = sampleTaskEntryPoint;
    taskBuilder.name = sampleTaskName;
    
    var task = taskBuilder.register();
    task.addEventListener("completed", backgroundTaskComplete);
    }

    Хотя и можно выполнить вызов . У приложения нет возможности этим управлять – всё, что оно может сделать, запросив соответствующие данные – это убедиться в том, что доступно для выбора пользователем в соответствующем разделе Настроек ПК (PC Settings).

    Запрос выполняется с помощью метода Windows.ApplicationModel.Background.BackgroundExecutionManager.requestAccessAsync; даннй вызов следует выполнить до регистрации фоновой задачи (снова смотрите Сценарий 5 примера "Фоновая задача"):

    Windows.ApplicationModel.Background.BackgroundExecutionManager.requestAccessAsync();

    Когда этот вызов осуществляется впервые, он вызывает окно для получения согласия пользователя, которое показано на рис 6.2. Если пользователь выбирает вариант Разрешить (Allow), приложение появится в соответствующем разделе Параметров ПК (PC Settings) в качестве опции для добавления на начальный экран, в противном случае этого не произойдет. Как и в случае с другими разрешениями, пользователи могут изменять свое мнение позже, воспользовавшись настройками Разрешений (Permissions), как показано на рис 6.3.

    (рис 6.2) Вопрос, который задаётся пользователю, если приложению нужен доступ к экрану блокировки (рис 6.3) Параметр экрана блокировки на панели настройки Разрешений (Permissions) приложения, которому нужен подобный доступ

    Для того, чтобы увидеть полную демонстрацию, обратитесь к примеру "Приложения экрана блокировки" (http://code.msdn.microsoft.com/windowsapps/Lock-screen-apps-sample-9843dc3a). В Сценарии 1 он показываеть, как запрашивать доступ к экрану блокировки и проверять результат – значение из перечисления BackgroundAccessStatus (http://msdn.microsoft.com/library/windows/apps/windows.applicationmodel.background.backgroundaccessstatus.aspx). Он так же показываеть выполнение запросов и отключение этого доступа с помощью методов getAccessStatus и removeAccess объекта BackgroundExecutionManager.

    Сценарий 2, в свою очередь, показывает отправку уведомлений индикатора событий на экран блокировки, вместе с обновлением текста около часов, если приложение выбрано для отображения этого текста. Здесь нет ничего особенного, если речь идёт об экране блокировки: подобные обновления происходят точно так же, как и для плитки приложения. Разница лишь в том, что эти обновления отображаются на экране блокировки. В случае с индикаторами событий, глиф уведомления отображается вместе с изображением, которое задает параметр Эмблема (Badge Logo), заданный в разделе Интерфейс приложения > Уведомления (Application UI > Notifications) манифеста (рис 6.1). Повторяя из ранее упомянутого, это изображение может иметь лишь белые и прозрачные пиксели и должно быть представлено в трех размерах для разного уровня масштабирования: 24x24 (100%), 33x33 (140%), и 43x43 (180%).

    Сценарий 3, наконец, показывает, как добавить дополнительные плитки на экран блокировки, независимо от плитки приложения. Для того чтобы дополнительная плитка была доступна для экрана блокировки, подразумевая, что приложение уже запросило доступ к экрану блокировки, вам нужно установить следующие два свойства объекта ), которые мы как-то упоминали: lockScreenBadgeLogo и lockScreenDisplayBadgeAndTileText. Если дополнительная плитка присутствует на начальном экране, эти свойства так же делают её доступной на странице Параметров ПК (PC Settings) для экрана блокировки.

    Отладка фоновых задач

    К данному моменту вы уже, возможно, запустили фоновую задачу TimeTrigger в Сценарии 5 примера "Фоновые задачи", и хотя с того времени прошло уже больше 15 минут (может быть больше 30 минут, если вы просто пропустили 15-минутное окно, когда таймеры объединились), вы, возможно, всё еще ждете, пока пройдёт этот период. Значит ли это, что ваша жизнь при отладке фоновых задач будет состоять из сплошного ожидания?

    К счастью, ответ на этот вопрос – "Нет" и "Возможно". То есть, отладчик Visual Studio знает о зарегистрированных фоновых задачах и предоставляет их список в выпадающем меню Приостановить (Suspend) на панели инструментов:

    Выбор одной из этих команд немедленно вызовет фоновую задачу, так что вам не придется ждать или пытаться активировать триггер по-настоящему. Первое предостережение заключается в том, что если свойство триггера oneShot установлено в true и он уже был вызван, снова он вызван не будет. Второе предостережение заключается в том, что если вы запускаете JavaScript-приложение с фоновыми задачами, написанными на других языках, вам нужно изменить тип отладчика для основного проекта приложения с Только скрипт (Script Only) на Управляемый (Managed) или Машинный (Native), как показано ниже, иначе вы не сможете устанавливать точки останова в модулях, написанных на других языках.

    Третье предостережение заключается в том, что фоновые задачи, которые используют ControlChannelTrigger, PushNotificationTrigger, и SystemTriggerType.SmsReceived не отображаются в вышеупомянутом меню Visual Studio.

    Таким образом, может возникнуть необходимость воспользоваться проверенными методами вывода диагностических данных для того, чтобы понять, что происходит с вашей задачей и наблюдать за событиями в Просмотре событий (Event Viewer) на предмет ошибок при активации. Подробнее об этих методах можно узнать в материале "Отладка фоновой задачи" (http://msdn.microsoft.com/library/windows/apps/jj542415.aspx).

    И, наконец, еще раз отмечу, что фоновые задачи не поддерживаются в имитаторе Visual Studio, как и динамические плитки, уведомления и многие другие механизмы, упомянутые в этой лекции. Вам нужно использовать, вместо этого, опции Локальный компьютер (Local Machine) или Удалённый компьютер (Remote Machine).

    Что мы только что изучили (Ух ты!)

  • Обновления плиток – основной и дополнительных, обновления индикаторов событий, всплывающие уведомления, фоновые задачи, из которых приложение может отправлять обновления плиток и уведомления – это то, как приложение делает свой вклад в общий динамизм системы даже тогда, когда оно не исполняется.
  • Обновления и уведомления, конечно, могут быть отправлены из исполняющегося приложения, но существуют другие методы для доставки подобных обновлений, когда приложение не исполняется. Обновления могут быть запланированы для показа через некоторое время, приложение может настроить систему для периодического запроса некоего сервиса на предмет обновлений для плиток и индикаторов событий. Приложения так же могут настраивать push-уведомления, которые исходят от веб-сервиса и отправляются клиенту посредством Windows Push Notification Service (WNS).
  • Обновления плиток отправляют с использованием полезных данных XML на основе предопределенных шаблонов. Обычно данные включают в себя обновления и для квадратных, и для прямоугольных плиток, так как польозватель может выбрать, какая именно плитка будет отображаться. XML может ссылаться на изображения как из локальных, так и из удаленных источников, изображение не может быть больше, чем 1024x1024 пикселя, его размер не должен превышать 200 Кб.
  • Плитка в любое время может циклически отображать до пяти обновлений, каждое из которых может быть заменено отдельно от других.
  • Приложения, имеющие особое содержимое, которое пользователю может быть интересно прикрепить на Начальном экране в качестве дополнительной плитки, предоставляют команды Прикрепить (Pin) и Открепить (Unpin). Дополнительные плитки, при запуске приложения со специальными аргументами запуска, так же могут принимать обновления динамических плиток.
  • Индикаторы событий – это маленькие значки (глифы) или числа, которые могут отображаться на любой плитке. Обновления индикаторов событий отправляются с помощью тех же самых механизмов, что и обновления плиток, но работают они самостоятельно.
  • Всплывающие уведомления (toasts) – это уведомления, которые появляются для того, чтобы оповестить пользователя о новой информации, сделать напоминание и так далее. Они могут быть настроены для проигрывания звуков, установлены для повторения через заданный интервал, запланированы для появления в будущем. Как и дополнительные плитки, всплывающие уведомления, при активации, запускают приложение со специальными стартовыми аргументами.
  • Периодические обновления для плиток и индикаторов событий предусматривают передачу Windows URI веб-сервиса для вызова через выбранный интервал – от 30 минут до 24 часов. Периодические обновления – это самый простой и наименее затратный способ для обновления плитки с помощью веб-сервиса.
  • Push-уведомления для плиток, индикаторов событий, всплывающих уведомлений, и необработанные уведомления (содержащие любые необходимые данные), можно использовать для обновлений, привязанных к конкретному пользователю и производимых с высокой частотой. Их использование включает в себя создание веб-сервиса, который связывается с WNS для отправки подобных уведомлений по заданным URI каналов, процесс, который сложнее и затратнее, чем работа с периодическими обновлениями.
  • Фоновые задачи – это небольшие фрагменты кода, которые приложение настраивает на запуск при срабатывании определенного триггера, такого, как изменения в условиях подключения к сети, таймера, приём push-уведомления, и при обновлении программы. Однако приложениям никогда не следует зависеть от фоновых задач, так как они всегда находится под управлением пользователя.
  • Триггеры фоновых задач могут быть тонко настроены с использованием специальных условий для того, чтобы избежать исполнения задач тогда, когда в этом нет необходимости (например, тогда, когда нет подключения к Интернету).
  • Для работы некоторых триггеров требуется, чтобы приложение было добавлено на экран блокировки. Такие приложения сначала должны запросить доступ, что зависит от решения пользователя, и пользователь должен добавить приложение посредством Параметров ПК (PC Settings). Получив подобную привилегию, приложения могут отправлять обновления значков и текста на экран блокировки.
  • Посредством триггеров обслуживания, приложения могут настраивать задачи, которые исполняются периодически, когда устройство подключено к источнику питания.
  • Вернуться к учебному плану