Блог Сергея Байдачного

Мой блог о технологиях

Отслеживание местоположения

leave a comment »

 

Определение местоположения и интеграции с картами являются ключевыми элементами многих приложений. В этой части мы поговорим об определении местоположения устройства пользователя, которое может быть использовано для отображения информации на карте, при внедрении GPS координат в объекты, связанные с какой-то активностью и во многих других задачах. Windows Phone 8 позволяет использовать все доступные механизмы по определению позиции устройства, это GPS датчик, через Wi-Fi сеть или используя сеть мобильного оператора. Тут все зависит от предпочтений разработчика – точность или время определения позиции.

Начнем с того, что разработчик может найти в Windows Phone 8 сразу два программных интерфейса по определению местоположения. Один интерфейс является частью Silverlight и присутствовал еще в Windows Phone 7, а второй – частью Windows Runtime. Сохранить интерфейс в Silverlight требует поддержка старых приложений, а добавление нового интерфейса в Windows Runtime объясняется необходимостью использования его и в С++ приложениях. Ведь если Вы создаете симпатичный 3D навигатор, то тут без DirectX никак не обойтись, а это означает, что DirectX приложения должны иметь возможность использовать интерфейс по определению местоположения. Если внимательно читать документацию, то можно заметить, что Microsoft не рекомендует использовать старый Silverlight интерфейс по определению местоположения даже в том случае, если Ваше приложение разрабатывается на C#. Старый интерфейс хоть и остался, но никак не развивался и предлагает значительно меньше возможностей. Поэтому далее мы будем использовать только интерфейс из Windows Runtime.

Получение позиции и отслеживание изменений

Начнем наш обзор с механизма по определению позиции устройства без отслеживания изменений. Тут первым делом необходимо настроить проект, задекларировав в приложении возможность по определению местоположения. Тут можно использовать как графический редактор манифеста, так и редактировать XML непосредственно, добавив декларацию ID_CAP_LOCATION:

 

<Capabilities>
  <Capability Name="ID_CAP_NETWORKING" />
  <Capability Name="ID_CAP_LOCATION" />
</Capabilities>

 

В отличие от Windows 8 в платформе телефона отсутствует компонент, который проверяет обращение к небезопасному API и нотифицирует пользователя. Поэтому, первым делом, перед использованием механизма по определению местоположения, необходимо получить разрешение у пользователя. Это можно сделать с помощью обычного MessageBox. В случае, если пользователь не согласен предоставлять местоположение, то приложение не имеет право использовать этот функционал. Естественно, что подобное поведение приложения проверяется «в ручном» режиме при сертификации.

В Windows 8 есть еще одна замечательная фишка: помимо автоматической нотификации пользователя, приложение получало автоматически созданный раздел в пункте меню Settings на стандартной панели Windows 8. В этом разделе сохранялись все настройки пользователя относительно небезопасного API. Используя созданный раздел, пользователь всегда мог разрешить или запретить доступ к тому или иному небезопасному API (камере, микрофону, местоположению и др.). В телефоне такой возможности нет, да и не очень понятно, где бы можно было создать подобный раздел. Поэтому, независимо от ответа пользователя, разработчик должен предоставить дополнительный механизм, который позволит изменять выбранные настройки. Механизм должен быть понятен и легко доступен пользователю и обычно представлен кнопкой Настройки в панели приложения.

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

Перейдем к классам, позволяющим определить местоположение. Тут всего один класс Geolocator с двумя методами (формально один, но перегруженный), двумя событиями и пятью свойствами. Класс находится в пространстве имен Windows.Devices.Geolocation и представляет собой часть Windows Runtime. Поэтому подключать какие-то дополнительные сборки нет необходимости.

Обратимся к свойствам этого класса. Вот их список и назначение:

· DesiredAccurancy – свойство позволяет задать один из двух режимов определения позиции: Default и High. В первом случае местоположение будет определятся максимально эффективным способом с точки зрения ресурсов и времени. Во втором случае полученное местоположение будет подобрано исходя из максимальной точности. Подобное поведение можно было задать и в предыдущих версиях платформы, но это не устраивало разработчиков, так как механизм не предоставлял тонкой настройки. Поэтому следующее свойство более интересно;

· DesiredAccurancyInMeters – позволяет задать точность определения местоположения в метрах. Если установлено это свойство в значение отличное от null, то DesiredAccurancy игнорируется, а поиск местоположения происходит с той точностью, которую определяет DesiredAccurancyInMeters. Несомненно, это более гибкий механизм, который может быть использован в задачах любой сложности;

· LocationStatus – это свойство позволяет узнать готовность объекта Geolocator к получению данных, принимая значение перечислимого типа PositionStatus. На мой взгляд тут одно полезное значение, которое нужно проверять всякий раз, когда Вы решите получить позицию, это PositionStatus.Disabled. Ведь если пользователь разрешил определение местоположения внутри приложения, это вовсе не означает, что он не запретил определение местоположения в глобальный настройках телефона. Это также нужно проверить и значение Disabled это показывает;

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

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

Итак, со свойствами мы познакомились и можно приступать к определению местоположения. Для этого используется метод GetGeopositionAsync, который имеет две сигнатуры вызова. В первом случае метод не принимает параметров и ориентируется на свойства объекта. А вот во втором случае разработчик уже может задать два параметра типа TimeSpan. Второй параметр будет определять время, которое отводится на поиск позиции (после чего будет сгенерирован Time Out, если позиция не найдена). Первый параметр более интересный и позволяет задать «возраст» позиции. Дело в том, что Windows Phone умет кэшировать местоположение и в ситуации, когда текущую позицию найти не удается, имеет привычку возвращать данные из кэша. Это доставляло массу проблем разработчикам, так как часто нельзя было гарантировать достоверность данных. Теперь проблема решена и контроль кэша обеспечивается полностью. В дополнении хотелось бы отметить, что оба метода используют новый подход async/await для вызова асинхронных методов. Подобный подход отсутствует в Silverlight, но все новые API вызываются именно так.

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

 

private async void OneShotLocation_Click()
{
   //переменную следует выбрать откуда-то из хранилища настроек пользователя
   //и установить в реальное значение
   bool isAllow=true;

   Geolocator geolocator = new Geolocator();

   if (geolocator.LocationStatus == PositionStatus.Disabled)
   {
       if (MessageBox.Show(
           "Определение позиции заблокировано. Перейти к настройкам телефона?",
           "Ошибка настроек", MessageBoxButton.OKCancel)==MessageBoxResult.OK)
       {
           await Launcher.LaunchUriAsync(new Uri("ms-settings-location:"));
       }
       return;
   }

   geolocator.DesiredAccuracyInMeters = 50;

   if (!isAllow)
   {
       if (MessageBox.Show(
           "Разрешить определение позиции устройства для приложения?",
           "Настройки", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
       {
           //сохранить выбранное значение для дальнейшего использования
           //чтобы в следующий раз им заполнять isAllow
       }
       else
       {
           return;
       }
   }

   try
   {
       Geoposition geoposition = await geolocator.GetGeopositionAsync(
           TimeSpan.FromMinutes(5),
           TimeSpan.FromSeconds(10)
           );

       MessageBox.Show(String.Format(
           "Местоположение получено! Позиция: {0}, {1}", 
           geoposition.Coordinate.Latitude, geoposition.Coordinate.Longitude));

   }
   catch (Exception ex)
   {
       MessageBox.Show("Что-то случилось странное!");
   }
}

 

Если приложению необходимо не просто получить позицию устройства, а отслеживать ее изменение, то тут в дело вступают два события, описанные в классе Geolocator, это PositionChanged и StatusChanged. Первое событие генерируется, когда происходит отправка приложению новой позиции. В основном тут и происходит вся логика работы. Второе событие генерируется всякий раз, когда происходит изменение состояния Geolocator. Например, при работе приложения пользователь может пойти в настройки и выключить определение положения для всего устройства. Обратите внимание, что для того, чтобы отслеживание положения заработало, достаточно привязать к этим событиям свои обработчики, а для выключения – удалить обработчики.

Отслеживание местоположения в фоне

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

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

 

<Tasks>
  <DefaultTask Name="_default" NavigationPage="MainPage.xaml">
    <BackgroundExecution>
      <ExecutionType Name="LocationTracking"/>
    </BackgroundExecution>
  </DefaultTask>
</Tasks>

 

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

· Приложение прекратило отслеживать местоположение;

· Пользователь завершил Background процесс, используя глобальные настройки телефона для приложений;

· Пользователь запретил использование Location служб в ходе работы приложения;

· Недостаточно памяти;

· Прошло более 4-х часов после начала работы приложения в фоне;

· Пользователь запустил другое приложение по отслеживанию позиции и оно также ушло в фон;

· В телефоне включена экономия заряда батареи.

Естественно, перед завершением работы, приложение получает соответствующую нотификацию и может успеть отправить уведомление пользователю о своей безвременной кончине. Что делать очень даже желательно.

Теперь поговорим об ограничениях. Первое из ограничений состоит в том что подобный функционал работает только для XAML приложений. То есть, если Вы пишете программу на чистом С++/DirectX, то это работать не будет.

Поскольку приложение работает в фоне, то следующие ограничения касаются доступа к обновлению интерфейса и таким ресурсам как камера и микрофон. Но если с камерой и микрофоном понятно, то с интерфейсом нужно бороться дополнительно. Фактически разработчику нужен некоторый механизм, который позволит определять, когда приложение запущено в фоне и вызывать части кода по обновлению интерфейса только в том случае, если приложение работает в обычном режиме. Для этих целей можно объявить обработчик события RunningInBackground, которое ассоциировано с приложение и может быть задекларировано в файле App.xaml:

 

<Application.ApplicationLifetimeObjects
    <shell:PhoneApplicationService
       Launching="Application_Launching" 
       Closing="Application_Closing"
       Activated="Application_Activated" 
       Deactivated="Application_Deactivated"
       RunningInBackground="PhoneApplicationService_RunningInBackground"/>
</Application.ApplicationLifetimeObjects>

 

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

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

Зная, как определить местоположение можно переходить к работе с картами.

Реклама

Written by Sergiy Baydachnyy

11.12.2012 в 13:07

Опубликовано в Windows Phone

Tagged with

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: