Мобильные приложения часто нуждаются в данных о положении устройства в пространстве (акселерометр, гироскоп) и его географических координатах. В Qt для этого есть два модуля: Qt Sensors — для работы с физическими датчиками устройства, и Qt Positioning — для определения геолокации через GPS, Wi-Fi или сотовые сети.
Qt Sensors: чтение акселерометра
Подключение модуля в CMake:
find_package(Qt6 REQUIRED COMPONENTS Sensors Qml Quick)
target_link_libraries(MyApp PRIVATE Qt6::Sensors Qt6::Qml Qt6::Quick)
Пример на QML — чтение данных акселерометра:
import QtQuick
import QtSensors
Item {
id: root
width: 400; height: 400
Accelerometer {
id: accel
active: true
dataRate: 50 // частота опроса в Гц
onReadingChanged: {
console.log("x:", reading.x, "y:", reading.y, "z:", reading.z)
}
}
// Визуализация наклона устройства
Rectangle {
width: 40; height: 40
color: "tomato"
radius: 20
x: root.width / 2 - width / 2 + accel.reading.x * 10
y: root.height / 2 - height / 2 + accel.reading.y * 10
}
}
Тот же пример на C++:
#include <QAccelerometer>
#include <QAccelerometerReading>
QAccelerometer *sensor = new QAccelerometer(this);
sensor->setDataRate(50);
QObject::connect(sensor, &QAccelerometer::readingChanged, [sensor]() {
QAccelerometerReading *reading = sensor->reading();
qDebug() << "x:" << reading->x()
<< "y:" << reading->y()
<< "z:" << reading->z();
});
sensor->start();
Пояснения к коду
dataRateзадаёт желаемую частоту опроса в герцах; реальная частота зависит от возможностей конкретного датчика устройства.- Свойство
readingобновляется автоматически и доступно через сигналreadingChanged. - Помимо
Accelerometer, доступныGyroscope,Magnetometer,LightSensor,ProximitySensor,RotationSensorи другие — все они следуют одинаковому паттерну API.
Qt Positioning: получение геолокации
Подключение модуля:
find_package(Qt6 REQUIRED COMPONENTS Positioning Qml Quick)
target_link_libraries(MyApp PRIVATE Qt6::Positioning Qt6::Qml Qt6::Quick)
Пример на QML:
import QtQuick
import QtPositioning
Item {
PositionSource {
id: positionSource
updateInterval: 5000 // запрашивать координаты каждые 5 секунд
active: true
onPositionChanged: {
var coord = positionSource.position.coordinate
console.log("Широта:", coord.latitude,
"Долгота:", coord.longitude,
"Точность:", positionSource.position.horizontalAccuracy)
}
onSourceErrorChanged: {
if (sourceError !== PositionSource.NoError)
console.log("Ошибка геолокации:", sourceError)
}
}
Text {
anchors.centerIn: parent
text: positionSource.position.coordinate.latitude + ", " +
positionSource.position.coordinate.longitude
}
}
Аналог на C++:
#include <QGeoPositionInfoSource>
#include <QGeoPositionInfo>
QGeoPositionInfoSource *source = QGeoPositionInfoSource::createDefaultSource(this);
if (source) {
source->setUpdateInterval(5000);
connect(source, &QGeoPositionInfoSource::positionUpdated,
this, [](const QGeoPositionInfo &info) {
QGeoCoordinate coord = info.coordinate();
qDebug() << "Координаты:" << coord.latitude() << coord.longitude();
});
source->startUpdates();
}
Пояснения к коду
PositionSourceавтоматически выбирает наилучший доступный источник координат на устройстве (GPS, сеть, эмулятор позиции в desktop-режиме).QGeoPositionInfoSource::createDefaultSource()возвращаетnullptr, если на платформе нет доступного провайдера позиционирования — это обязательно нужно проверять перед использованием.horizontalAccuracyпоказывает радиус точности в метрах — полезно для отображения пользователю достоверности координат.
Запрос геокодирования (адрес ↔ координаты)
#include <QGeoCodingManager>
#include <QGeoServiceProvider>
QGeoServiceProvider provider("osm"); // OpenStreetMap-провайдер
QGeoCodingManager *geocodingManager = provider.geocodingManager();
if (geocodingManager) {
QGeoCodeReply *reply = geocodingManager->geocode("Москва, Красная площадь");
QObject::connect(reply, &QGeoCodeReply::finished, [reply]() {
if (reply->error() == QGeoCodeReply::NoError && !reply->locations().isEmpty()) {
QGeoCoordinate coord = reply->locations().first().coordinate();
qDebug() << "Найдены координаты:" << coord;
}
});
}
Разрешения на мобильных платформах
На Android и iOS доступ к датчикам и геолокации требует явного запроса разрешений у пользователя в runtime. В Qt6 для этого предусмотрен модуль Qt Core с классом QPermission:
#include <QCoreApplication>
#include <QPermissions>
QLocationPermission locationPermission;
locationPermission.setAccuracy(QLocationPermission::Precise);
switch (qApp->checkPermission(locationPermission)) {
case Qt::PermissionStatus::Undetermined:
qApp->requestPermission(locationPermission, [](const QPermission &permission) {
if (qApp->checkPermission(permission) == Qt::PermissionStatus::Granted)
qDebug() << "Доступ к геолокации разрешён";
});
break;
case Qt::PermissionStatus::Denied:
qDebug() << "Доступ к геолокации запрещён пользователем";
break;
case Qt::PermissionStatus::Granted:
qDebug() << "Доступ уже есть";
break;
}
Также не забудьте добавить соответствующие разрешения в AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Подводные камни
- Эмуляторы и desktop без GPS. На десктопе
QGeoPositionInfoSourceможет возвращать координаты только если настроен симулятор позиции (например, черезQGeoPositionInfoSourceFactoryс тестовым backend) — не рассчитывайте на реальные данные при разработке на ПК. - Различная точность датчиков на разных устройствах. Не все Android-устройства имеют гироскоп или магнитометр — всегда проверяйте
QSensor::isFeatureSupported()или соответствующий метод перед использованием. - Энергопотребление. Частый опрос GPS (
updateIntervalменьше 1000 мс) серьёзно увеличивает расход батареи — выбирайте интервал обновления исходя из реальных потребностей приложения. - Разрешения нужно запрашивать асинхронно и обрабатывать случай отказа пользователя gracefully — без падения приложения и с понятным сообщением о том, почему функциональность недоступна.
- iOS требует дополнительных строк в Info.plist (
NSLocationWhenInUseUsageDescriptionи т.п.) — без них приложение будет отклонено при публикации в App Store.
Совет
Перед запросом доступа к датчикам или геолокации объясните пользователю, зачем это нужно приложению (например, через диалог-объяснение до системного запроса разрешения) — это заметно повышает процент пользователей, дающих согласие, по сравнению с прямым системным запросом без контекста.