Разработка для Sailfish OS: использование средств геолокации

в 10:47, , рубрики: gps, QML, qt, sailfish os, геолокация, разработка мобильных приложений, Разработка под Sailfish OS

Здравствуйте! Данная статья является продолжением цикла статей, посвящённых разработке приложений для мобильной платформы Sailfish OS. На этот раз речь пойдёт о том, как можно реализовать в приложении получение информации о географическом положении устройства, отображение карты с текущим местоположением и пройденным маршрутом.

Приложение GPS-трекер

Для демонстрации возможностей API геолокации мы будем использовать приложение GPS-трекер, которое включает в себя все базовые функции, связанные с геолокацией:

  • Просмотр карты местности на экране телефона.
  • Запись текущего GPS-трека и отображение пройденного пути.
  • Сохранение GPS-трека в память устройства.
  • Отображение записанных и загруженных GPS-треков из памяти устройства.
  • Ведение списка точек интереса с возможностью включения / выключения их отображения на карте.
  • Перемещение карты к выбранной точке интереса.

Средства работы с географическими данными

Платформа Sailfish OS использует стандартные классы фреймворка Qt для предоставления приложениям доступа к геолокационной информации. В свою очередь, фреймворк Qt предоставляет две подсистемы для работы с данными: Qt Positioning и Qt Location. Первая подсистема позволяет получить информацию о текущем местоположении устройства, а вторая предоставляет средства для отображения этой информации на карте. В статье мы рассмотрим только использование QML-типов (без C++-классов), так как этого обычно достаточно для реализации основных сценариев использования координат в приложениях.

Получение данных о местоположении с помощью Qt Positioning

Описание координат в Positioning API

Для описания координат используется тип Position, содержащий в себе большое количество полей, которые можно разделить на несколько групп.

К первой относится информация о местоположении: в неё входит свойство coordinate, ссылающееся на экземпляр соответствующего типа coordinate, а также свойства altitudeValid, latitudeValid и longitudeValid, которые показывают, были ли соответствующие свойства установлены или нет. Также для каждой координаты хранится время (timestamp), когда она была получена.

Во вторую группу входят свойства, связанные с координатами, и которые могут быть дополнительно получены с GPS-датчика или вычислены путём агрегации последовательности измеренных координат: скорость движения по поверхности земли (speed), скорость вертикального движения (verticalSpeed), направление движения (direction), а также соответствующие свойства с суффиксом Valid, которые указывают были ли соответствующие свойства установлены.

Сам тип coordinate является достаточно простым и содержит информацию о географическом положении (latitude, longitude, altitude) и о том, являются ли указанные ширина и долгота корректными (isValid). Тип предоставляет дополнительные методы для вычисления расстояния между координатами (distanceTo), азимута между координатами (azimuth), а также вычисления координаты по расстоянию и азимута (atDistanceAndAzimuth).

Источник данных о географическом положении

Для получения текущих координат устройства необходимо использовать тип PositionSource. Данный объект предоставляет доступ к текущей позиции через свойство position. Пока источник для получения информации не установлен, данное свойство пусто.

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

  • NoPositioningMethods — никакие методы не поддерживаются.
  • SatellitePositioningMethods — можно получить данные со спутника.
  • NonSatellitePosititiongMethods — можно получить данные с мобильной сети.
  • AllPosititiongMethods — поддерживаются все виды позиционирования.

Устройства под управлением операционной системы Sailfish OS поддерживают все перечисленные выше методы. И вы можете выбрать необходимые, установив свойство preferredPosititioningMethods в одно из указанных выше значений. Сначала будут использованы данные источники, затем источник по умолчанию. Если ни один из перечисленных источников не будет доступен, то свойство valid будет содержать false.

Стоит отметить, что на эмуляторе Sailfish OS у вас не будет возможности воспользоваться никакими источниками данных из перечисленных. Для решения этой задачи придётся прибегнуть к отдельному механизму, который мы обсудим позже.

Частота обновления информации о местоположении определяется с помощью свойства updateInterval. Не стоит устанавливать это значение слишком коротким — слишком частые обновления приведут к избыточному энергопотреблению. Для управления получением данных можно воспользоваться слеудющими методами:

  • start для запуска;
  • stop для остановки;
  • NonSatellitePosititiongMethods — можно получить данные с мобильной сети.
  • update для принудительного обновления местоположения.

Запускать и останавливать можно также декларативным способом — с помощью установки свойства active: присваивание ему положительного значения равносильно вызову метода start.

Когда источник данных активен, то он начинает обновлять свойство position. Оно может быть привязано к другим свойствам с помощью механизма байндинга (binding) в QML. Кроме того, вы можете использовать сигнал onPositionChanged, чтобы обрабатывать новые значения координат по мере их получения из источника данных.

Использование Qt Positioning в Sailfish OS

Для использования информации о географическом положении в ваших приложениях необходимо в список зависимостей добавить пакет qt5-qtdeclarative-import-positioning. Его необходимо указать в списке Requires YAML-файла вашего проекта. После добавления содержимое может выглядеть следующим образом:

Requires:
- sailfishsilica-qt5 >= 0.10.9
- qt5-qtdeclarative-import-positioning

Затем в QML-файле нам необходимо подключить модуль Qt Positioning и создать элемент PositionSource. Рассмотрим короткий пример.

import QtPositioning 5.2
PositionSource {
    id: src
    updateInterval: 1000
    active: true

    onPositionChanged: {
        var coord = src.position.coordinate;
        console.log("Coordinate:", coord.longitude, coord.latitude);
    }
}

В данном примере мы не настраиваем большинство свойств PositionSource и используем значения по умолчанию. Настраивается только свойство active, которому присваиваем значение true. Как только страница с данным элементом будет загружена, будет начат поиск местоположения.

Мы определяем обработчик события onPositionChanged, в котором сначала получаем доступ к текущей координате, а затем используем полученную ссылку для вывода ширины и долготы текущей координаты.

Отладка логики работы с PositionSource

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

Для решения этих проблем удобно использовать свойство nmeaSource типа PositionSource. Данное свойство принимает URL файла, в котором записан GPS-трек в формате NMEA. Данный формат менее распространён у нас по сравнению с GPX, однако, вы можете воспользоваться одним из онлайн-преобразователей для получения таких файлов из имеющихся у вас GPX-треков.

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

PositionSource {
  id: positionSource
  active: true
  nmeaSource: "/usr/share/project/qml/nmea.log"
}

В этом случае PositionSource будет предоставлять данные из указанного файла. Важно помнить, что установка этого значения отключает объект PositionSource от реального источника данных. Если вы хотите использовать реальный источник, то придётся пересоздать такой объект.

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

Отображение карт и информации на них с помощью Qt Location

Модуль Qt Location предоставляет широкий набор классов, которые позволяют реализовать показ пользователю карты, информации на этой карте, построение маршрутов и поиск точек интереса (points of interest, POI) относительно текущей географической координаты. Хорошее введение в большинство возможностей данного модуля можно прочитать в официальной документации. Мы не можем осветить все особенности работы с картами, поэтому остановимся только на следующих моментах: как организовать показ карты в приложении, как показать маркер на карте и как показать пройденный путь.

Краткий обзор ключевых типов Qt Location

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

На платформе Sailfish OS доступны два плагина: OpenStreetMap и HERE WeGo. Вы можете выбрать один из них, установив свойство plugin карты равным osm или here соответственно (для использования here необходимо получить API-ключ). Выбор карт зависит от качества их покрытия для конкретных территорий, на которых вы собираетесь использовать приложение. Также необходимо указать требуемый плагин в зависимостях вашего приложения, как будет показано ниже.

Для управления областью просмотра карты необходимо использовать свойство center, указывающее координаты центра изображения, а также свойство zoomLevel, указывающее степень приближения к карте. В свойство center необходимо записать координаты в соответствии с типом coordinate, который мы упомянули ранее в разделе по работе с Positioning API.

Отображение карты в Sailfish OS

Для использования модуля Qt Location в вашем приложении необходимо обеспечить установку всех необходимых зависимостей на устройство. Обязательной зависимостью является модуль Qt Positioning, а также как минимум один из провайдеров географических данных. Ниже приведён пример секции YAML-файла, в котором указаны все возможные зависимости.

Requires:
  - qt5-qtdeclarative-import-positioning
  - qt5-qtdeclarative-import-location
  - qt5-plugin-geoservices-osm
  - qt5-plugin-geoservices-here

Из двух последних пакетов можно оставить один, если вы планируете использовать только один провайдер географической информации.

Теперь можно размещать все необходимые компоненты на странице приложения. Рассмотрим минимальный пример отображения карты.

import QtPositioning 5.3
import QtLocation 5.0
import Sailfish.Silica 1.0
import QtQuick 2.0
Page {
  PositionSource {
    id: positionSource
    active: true
  }
  Plugin {
    id: osmPlugin
    allowExperimental: true
    preferred: ["osm"]
  }
  Rectangle {
    anchors.fill: parent
    Map {
      id: map
      anchors.fill: parent
      plugin: osmPlugin
      center: positionSource.position.coordinate
    }
  }
}

Сначала мы подключаем модули Qt Positioning и Qt Location, чтобы все необходимые нам типы стали доступны на странице.

В основе страницы лежит объект Page, предоставляемый библиотекой Sailfish Silica. На странице мы формируем источник данных о местоположении, который сразу активируем, а также плагин для географических данных. В качестве источника этих данных используем OpenStreetMap.

Основным видимым элементом страницы является прямоугольник, который заполняет всё доступное на странице пространство, а уже в нём определена карта. Такое устройство необходимо, чтобы обойти баг, который присутствует в некоторых версиях Sailfish OS. Карту мы настраиваем следующим образом: настраиваем плагин и связываем свойство center карты с координатой, которую предоставляет источник данных.

Добавление элементов на карту

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

Для отображения текущего местоположения мы воспользовались типом MapQuickItem. Он позволяет расположить на поверхности карты произвольный объект, например, объект Image, отображающий маркер. Рассмотрим детально его использование.

Map {
  MapQuickItem {
    coordinate: positionSource.position.coordinate
    anchorPoint.x: image.width / 2
    anchorPoint.y: image.height
    sourceItem: Image {
      id: image
      width: 35
      height: 50
      source: "file:buttons/main_marker.png”
    }
  }
}

Мы объявили данный объект как дочерний объект к Map, таким образом связав их вместе. Для позиционирования объекта мы указали свойство coordinate, которое связали с текущим географическим положением мобильного устройства. Также было использовано свойство anchorPoint, которое позволило отодвинуть изображение маркера таким образом, чтобы его острие указывало на текущую позицию.

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

Map {	
  MapPolyline {
    id: mapline
    line.width: 3
    line.color: 'blue
  }
}

Объект данного типа должен быть декларирован как дочерний по отношению к Map. Мы также настроили цвет и ширину отображения текущего трека.

Для добавления новых точек к линии отвечает следующий код:

PositionSource {
  id: positionSource
  active: true
  onPositionChanged: {
    mapline.addCoordinate(position.coordinate)
  }
}

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

Для отображения набора точек интереса мы использовали тип MapItemView. Данный тип представляет собой реализацию подхода MVC для карт: вам необходимо определить модель для отображения, а также вид для каждого элемента данной модели. Если вы знакомы с тем как наполнять списки элементов в QML, то работа с данным компонентом не составит труда.

Рассмотрим основные аспекты применения данной модели в приложении.

Map {
  MapItemView {
    id: mapView
    model: MapViewModel { }
    delegate: mapPlace
  }
  Component {
    id: mapPlace
    MapQuickItem {
      coordinate: QtPositioning.coordinate(latitude, longitude)
      anchorPoint.x: imagePlace.width / 2
      anchorPoint.y: imagePlace.height
      sourceItem: Image {
        id: imagePlace
        width: 35
        height: 50
        source: "file:buttons/additional_marker.png"
      }
    }
  }
}

Мы определили объект MapItemView дочерним объектом к Map — таким образом его элементы тоже будут отображаться на карте. В качестве модели мы использовали стандартную модель MapViewModel, элементами которой выступают объекты с указанными свойствами latitude и longitude.

Делегатом объекта mapView мы указали компонент mapPlace, который содержит уже знакомый нам MapQuickItem. Отличие данного элемента от предыдущего состоит в том, что тип coordinate нам приходится создавать явно с помощью соответствующего метода типа QtPositioning, а также в указании другого изображения для отображения маркера точки интереса.

Приложение готово. Его можно установить на свой телефон, воспользовавшись ресурсом OpenRepos.net. Вы также можете посмотреть на исходный код приложения, который доступен в нашем репозитории на bitbucket.

Заключение

В данной статье были рассмотрены особенности использования средств геолокации при разработке для Sailfish OS. Приложение, разработанное в рамках данной статьи, можно установить на свой телефон, воспользовавшись ресурсом OpenRepos.net. Вы также можете посмотреть на исходный код приложения, который доступен в нашем репозитории на bitbucket.

Автор: FRUCT

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js