Сетевое взаимодействие
События подключения
Обычно запущенное приложение интересуется изменениями сетевого подключения. Таким образом оно может предпринять необходимые шаги для отключения или включения определенной функциональности, для оповещения пользователя, синхронизации данных после нахождения в состоянии отключения от сети и так далее. Для этого приложению нужно лишь прослушивать событие NetworkInformation.onnetworkstatuschanged ( http://msdn.microsoft.com/library/windows/apps/windows.networking.connectivity.networkinformation.networkstatuschanged.aspx), которые вызывается, когда происходит серьезное изменение в иерархии объектов, которые мы только что видели (и не забудьте, это событие исходит из объекта WinRT). Например, событие вызывается, если меняется уровень подключения в профиле. Оно так же вызывается, если меняется профиль Интернета, как когда устройство перемещается между разными сетями, или когда, при применении лимитированного плана передачи данных, приближается или исчерпывается его ограничение, то есть, когда пользователь начинает беспокоиться о каждом мегабайте переданных данных. Коротко говоря, это событие обычно прослушивают для обновления любого внутреннего состояния приложения, зависящего от характеристик сети и установки любых флагов, используемых для настройки сетевого поведения приложения. Это особенно важно при переходах между режимом работы в сети и автономной работы и при переходах между безлимитными и лимитированными сетями. Windows, в свою очередь, так же отслеживает это событие для того, чтобы настроить собственное поведение, например, в реализации функций API фоновой передачи данных.
Примечание. Приложения для Магазина Windows, написанные на JavaScript так же могут использовать простые события window.nagivator.ononline и window.navigator.onoffline для отслеживания состояния подключений. Так же, свойство window.navigator.onLine property может принимать значения true или false в соответствии с состоянием подключения. Эти события, однако, не оповестят об изменении профилей соединений, стоимости или других аспектов, которые не связаны с базовой доступностью интернет-соединения.
Вы можете поэкспериментировать с событием networkstatuschanged в Сценарии 5 примера "Информация о сети". При подключении или отключении от сети, или при выполнении других изменений, пример обновит выводимые сведения для текущего Интернет-профиля, если он доступен (вот код, взятый из js/network-status-change.js):
var networkInfo = Windows.Networking.Connectivity.NetworkInformation; // Напоминаю, что для этого WinRT-события может понадобиться removeEventListener networkInfo.addEventListener("networkstatuschanged", onNetworkStatusChange); function onNetworkStatusChange(sender) { internetProfileInfo = "Network Status Changed: \n\r"; var internetProfile = networkInfo.getInternetConnectionProfile(); if (internetProfile === null) { // Сообщение об ошибке } else { internetProfileInfo += getConnectionProfileInfo(internetProfile) + "\n\r"; // Отображение информации } internetProfileInfo = ""; }
Конечно, прослушивание этого события полезно только если приложение исполняется, но что, если это не так? В подобном случае приложению нужно зарегистрировать фоновую задачу, как обсуждалось в конце Главы 2, для триггера networkStateChange (http://msdn.microsoft.com/library/windows/apps/windows.applicationmodel.background.systemtriggertype.aspx), обычно, при необходимости, с применением условий internetAvailable или internetNotAvailable. Пример "Фоновая задача для определения состояния сети" ( http://code.msdn.microsoft.com/windowsapps/Network-status-background-957eb3eb) предоставляет демонстрацию этого, объявляя фоновую задачу в манифесте, с C#-точкой входа для NetworkStatusTask.NetworkStatusBackgroundTask. Задача зарегистрирована в js/network-status-with-internet-present.js (с использованием вспомогательных функций из js/global.js, как обычно делается в примерах использования фоновых задач):
BackgroundTaskSample.registerBackgroundTask(BackgroundTaskSample.sampleBackgroundTaskEntryPoint, BackgroundTaskSample.sampleBackgroundTaskWithConditionName, new Windows.ApplicationModel.Background.SystemTrigger( Windows.ApplicationModel.Background.SystemTriggerType.networkStateChange, false), new Windows.ApplicationModel.Background.SystemCondition( Windows.ApplicationModel.Background.SystemConditionType.internetAvailable));
Фоновая задача в BackgroundTask.cs просто записывает имя Интернет-профиля и id сетевого адаптера в область локальных данных приложения в ответ на триггер. Эти значения выводятся на экран в completeHandler в js/global.js. Реальное приложение, конечно, будет делать что-то более полезное, например, активировать фоновую передачу данных для синхронизации данных при восстановлении соединения. Несмотя на это, пример представляет необходимую для реализации подобных механизмов базовую структуру.
Кроме того, очень важно помнить о том, что состояние сети может измениться, когда приложение приостановлено. Приложениям, которые отслеживают событие networkstatuschanged, следует так же обновлять свое состояние, связанное с соединением в обработчике возобновления работы.
В качестве последнего замечания, хочу посоветовать вам обратиться к материалу "Диагностика и отладка ошибок сетевых подключений" (http://msdn.microsoft.com/library/windows/apps/hh770534.aspx), который содержит руководство по реализации реакции приложения на изменения состояния сети и по обработке сетевых ошибок.
Сведения о стоимости передачи данных
Если вы когда-нибудь оказывались в 3G-роуминге со смартфоном, который настроен на автоматическую загрузку электронной почты, вы, возможно, научились на собственном горьком опыте отключать синхронизацию в подобных обстоятельствах. Я однажды ехал из штата Вашингтон в Канаду, не представляя, что я плачу $15 за мегабайт за возможность загружать большие почтовые вложения. Конечно, я, как законопослушный гражданин, не смотрел на телефон, пока вел машину (пишу это и подмигиваю!) для того, чтобы заметить, что я в роуминге. А через несколько недель я узнал, что такое "шоковый счет"!
Дело в том, что если пользователь решит, что ваше приложение в ответе за подобное поведение, независимо от того, прав ли он, вряд ли в Магазине Windows у вашего приложения появятся хорошие оценки и отзывы! Таким образом, очень важно обращаться внимание на изменения в стоимости профилей подключения, которыми вы пользуетесь, обычно это касается Интернет-профиля. Всегда проверяйте это при старте, в обработчике события networkstatuschanged и в обработчике возобновления работы.
Вы, и, хочу добавить, все ваши пользователи, могут отслеживать использование приложением сети на закладке App History (Журнал приложений) в Task Manager (Диспетчер задач), как показано ниже. Убедитесь, что вы развернули область просмотра, нажав на More Details (Подробнее) в нижнем левом углу, если вы не видите того, что приведено на рисунке. Вы можете видеть здесь использование трафика по показателям Network (Сеть) и Metered Network (Сеть с учетом трафика), а так же – сведения о сетевом трафике, потребленном при обновлении плиток:
Программно, как было сказано выше, профиль предоставляет информацию об использовании сети посредством методов getConnectionCost и getDataPlanStatus methods. Первый метод возвращает объект ConnectionCost (http://msdn.microsoft.com/library/windows/apps/windows.networking.connectivity.connectioncost.aspx) с четырьмя свойствами:
- networkCostType значение типа NetworkCostType ( http://msdn.microsoft.com/library/windows/apps/windows.networking.connectivity.networkcosttype.aspx), может принимать значения: unknown, unrestricted (дополнительная плата не взимается), fixed (неограниченное, до достижения лимита), и variable (взимается плата на основе учета количества переданных байтов или мегабайтов).
- roaming Значение логического типа, которое указывает на то, подключены ли вы к сети, которая находится за пределами нормальной зоны покрытия вашего оператора, что подразумевает возможность дополнительной платы. Приложению следует весьма консервативно пользоваться сетью, если это значение установлено в true.
- approachingDataLimit Логическое значение, показывает, что использование данных в сети фиксированного (fixed) типа (смотрите networkCostType) приближается к лимиту тарифного плана.
- overDataLimit Логическое значение, которое показывает, что лимит фиксированного тарифного плана превышен и за передачу данных взимается дополнительная плата. Если это значение установлено в true, приложению следует весьма консервативно пользоваться сетью, как и в случае, когда свойство roaming равно true.
Второй метод, getDataPlanStatus, возвращает объект DataPlanStatus (http://msdn.microsoft.com/library/windows/apps/windows.networking.connectivity.dataplanstatus.aspx) со следующими свойствами:
- dataPlanLimitInMegabytes Максимальный объем передачи данный, который разрешен для подключения в каждом тарифном цикле.
- dataPlanUsage Объект DataPlanUsage (http://msdn.microsoft.com/library/windows/apps/windows.networking.connectivity.dataplanusage.aspx) с одинаково важными свойствами megabytesUsed и lastSyncTime (UTC), которое показывает, когда megabytesUsed было обновлено в последний раз.
- maxTransferSizeInMegabytes Максимальный рекомендованный объем данных, переданных в одной сетевой операции. Это свойство отражает скорее не возможности самого лимитированного подключения (как следует из документации), а скорее соответствующий верхний предел для передачи данных в этой сети.
- nextBillingCycle Дата и время в формате UTC, указывающие на то, когда закончится тарифный цикл, что приведет к сбрасыванию dataPlanUsage в ноль.
- inboundBitsPerSecond и outboundBitsPerSecond указывают на номинальную скорость передачи данных по данному соединению.
Пользуясь всеми этими свойствами мы можем принять обоснованное решение о сетевой активности приложения, и/или предупредить пользователя о возможных дополнительных затратах. Очевидно, когда параметр networkCostType имеет значение unrestricted, вы можете делать все, что хотите. С другой стороны, когда тип соединения имеет значение variable и пользователь платить за каждый байт, особенно, когда значение roaming установлено в true, вам понадобится уведомить пользователя о таком состоянии дел и предоставить параметры, с помощью которых пользователь сможет ограничить сетевую деятельность приложения, если не вовсе остановить такую деятельность. В конце концов, пользователь может решить, что определенные виды данных ему нужны. Например, он должен иметь возможность установки качества потокового видео, указывать, нужно ли загружать сообщения электронной почты, или лишь их заголовки, указать нужно ли загружать изображения, указать, нужно ли производить кэширование сетевых данных, иметь возможность выключить фоновое потоковое аудио и так далее.
Подобные настройки, кстати, могут включать в себя параметры, касающиеся плиток, индикаторов событий и других уведомлений, которые могут быть включены, и, таким образом, генерировать сетевой трафик. Если вы, кроме того, используете фоновую передачу данных, вы можете задасть политику управления стоимостью и для данных, отправленных в сеть, и для загруженных данных.
Приложение, конечно, спросит у пользователя разрешения для выполнения каждой сетевой операции. Здесь решают вы и ваш дизайнер – когда задавать подобные вопросы и как часть. В свою очередь, "Сертификационные требования к приложениям для Windows 8" (http://msdn.microsoft.com/library/windows/apps/hh694083.aspx) (раздел 4.5.) требуют, чтобы вы задавали пользователю вопрос о любой передаче данных, объем которой превышает один мегабайт, когда свойства roaming и overDataLimit установлены в true, и когда производите любую передачу данных в условиях превышания maxTransferSizeInMegabytes.
Для сетей фиксированного (fixed) типа, когда объем передачи данных не ограничен параметром dataPlanLimitInMegabytes, мы сталкиваемся с ситуациями, в которых становятся интересными другие параметры. Например, если overDataLimit уже установлен в значение true, вы можете запросить подтверждение пользователя на передачу дополнительного объема информации, или просто отложить подобную операцию до наступления nextBillingCycle. Или, если approachingDataLimit установлено в true (или даже когда это не так), вы можете определить, может ли какая-либо операция превысить данное ограничения. Здесь становится полезным метод профиля соединения getLocalUsage, так как с помощью него можно получить объект DataUsage за заданный период (смотрите материал "Получение данных об использовании подключения за определенный период" ( http://msdn.microsoft.com/library/windows/apps/hh465162.aspx). Вызовите getLocalUsage с заданным периодом между lastSyncTime и DateTime.now(). Затем добавьте полученное значение к megabytesUsed и вычтите результат из dataPlanLimitInMegabytes. Это скажет вам, сколько еще данных вы можете передать, не приведя к дополнительным расходам и сможете получить данные для того, чтобы иметь основания задать пользователю вопрос: "Загрузка этого файла приведет к превышению ограничений вашего тарифного плана. Желаете продолжить?"
В целях упрощения, вы можете рассматривать знание сведений о стоимости подключения в виде трех схем поведени: обычной, консервативной и требующей согласия пользователя, что описано в материале "Краткое руководство: управление тарифными ограничениями в сети с лимитным тарифным планом" (http://msdn.microsoft.com/library/windows/apps/hh750310.asp x). Более общие сведения об управлении соединением в сетях с лимитными тарифными планами можно найти в материале "Разработка подключенных приложений" (http://msdn.microsoft.com/library/windows/apps/hh465399.aspx). Оба материала предоставляют дополнительные сведения о том, как принимать решения, о которых мы здесь говорили. В итоге, предотвращение "шоковых счетов" - и создание отличных приложений, учитывающих стоимость сетевого подключения – это достойное вложение усилий.