Flutter урок по GPS геолокации (перевод урока с дополнениями)
Егор Долгов · 06.06.2019GPS стала стандартной функцией современного смартфона. Обычно используется приложениями, чтобы обнаружить местонахождение устройства.
Это перевод статьи Flutter - GPS Geolocation Tutorial [EN]. Перевод подготовлен Михайловой Марией. В статье вставлены дополнения и пояснения которых нет в оригинале.
Это руководство покажет вам как получить доступ к местонахождению устройства во Flutter, используя GPS, включая то как получить разрешения, текущее местоположение и постоянное его обновление.
Зависимости
Пакет geolocator (геолакатор) во Flutter предоставляет геолакационные функции. Добавьте его в ваш файл pubspec.yaml и запустите команду packages get (получить пакеты).
В оригинале используется версия geolocator: ^3.0.1 , на момент публикации этого перевода, самая последняя версия ^5.0.0. Но для ее работы на Android требуется совершить переход к AndroidX (смотрите как это сделать тут https://flutter.su/note/146 ). Без этого перехода - приложение будет вылетать при запросе к методам geolocator.
dependencies {
...
geolocator: ^5.0.0
...
}
Разрешения
Вам нужно добавить разрешения в каждую платформу.
Для Android
Нужны разрешения ACCESS_FINE_LOCATION и ACCESS_COARSE_LOCATION .
Добавьте их в AndroidManifest.xml путь к файлу: <app dir>/android/app/src/main/AndroidManifest.xml
В документации, https://flutter.dev/docs/deployment/android#review-the-app-manifest , указан именно этот путь. Но уже сейчас в новых flutter проектах есть еще несколько файлов AndroidManifest.xml в директории debug и main . В них указаны разрешения на использование сети:
<uses-permission android:name="android.permission.INTERNET"/>
По видимому, документация скоро обновится и будет указано в каком именно манифесте должны быть указаны разрешения.
Сообщение о предоставлении разрешения на использование геолокации.
Для IOS
Нужно NSLocationWhenInUseUsageDescription разрешение. Добавьте его в файл Info.plist .
NSLocationWhenInUseUsageDescription
This app needs access to location when open.
Пример кода
Ниже представлена структура кода этого руководства. Нам нужно создать экземпляр Geolocator (геолокатора) и сохранить значение последней Position (позиции). Приложение будет использовать значение Position , чтобы показать широту и долготу.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
class GeolocationExampleState extends State {
Geolocator _geolocator;
Position _position;
@override
void initState() {
super.initState();
_geolocator = Geolocator();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Geolocation Example'),
),
body: Center(
child: Text(
'Latitude: ${_position != null ? _position.latitude.toString() : '0'},'
' Longitude: ${_position != null ? _position.longitude.toString() : '0'}'
)
),
);
}
}
Проверьте разрешения
Если вы добавили правильные разрешения, приложению будет дано разрешение для доступа к местоположению устройства, используя GPS. В Андроид 6.0 и выше, он попросит пользователя дать разрешения. Но если вам нужно проверить есть ли у приложения разрешение на доступ к местоположению, вы сможете это сделать программно. Чтобы сделать проверку, используйте метод checkGeolocationPermissionStatus который возвращает значение Future . Как вариант, для iOS, вы можете отдельно выбрать locationAlways и locationWhenInUse , устанавливая locationPermission опциональный параметр, тип которого GeolocationPermission .
void checkPermission() {
_geolocator.checkGeolocationPermissionStatus().then((status) { print('status: $status'); });
_geolocator.checkGeolocationPermissionStatus(locationPermission: GeolocationPermission.locationAlways).then((status) { print('always status: $status'); });
_geolocator.checkGeolocationPermissionStatus(locationPermission: GeolocationPermission.locationWhenInUse)..then((status) { print('whenInUse status: $status'); });
}
Значения:
- GeolocationStatus.denied - если пользователь отклонил разрешение;
- GeolocationStatus.granted - если пользователь согласился.
Получить текущее местоположение
Получить текущее местонахождение очень легко. Просто используйте метод getCurrentPosition , который возвращает Future<Location>. Вы можете использовать опцию desiredAccuracy .
await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high)
Иногда процесс получения текущего местонахождения может быть не выполнен. К примеру, если пользователь выключает сенсор GPS. Если он был выключен с самого начала, это может быть причиной ошибки, поэтому мы должны ее отследить. Есть также вероятность того что GPS выключен когда процесс поиска локации уже идет. Это может привести к прерыванию процесса, и следовательно, лучше добавить задержку его исполнения.
void updateLocation() async {
try {
Position newPosition = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high).timeout(new Duration(seconds: 5));
setState(() {
_position = newPosition;
});
} catch (e) {
print('Error: ${e.toString()}');
}
}
Ниже приведены описания значений каждого LocationAccuracy .
Название описания lowest (самое низкое). Местонахождение точно в пределах дистанции в 3000м на iOS и 500м на Android.
- low (низкая) локация точна в пределах 1000м на iOS и 500м на Android.
- medium (средняя) локация точна в пределах 10м на iOS и между 0м и 100м на Android.
- high (высокая) локация точна в пределах 10м на iOS и между 0м и 100м на Android.
- best (лучшая) локация точна в пределах ~0м на iOS и между 0м и 100м на Android. Точность локации bestForNavigation оптимизирована для iOS и соответствует LocationAccuracy.best на Android.
Трансляция обновления местонахождения
Чтобы получить обновленное местоположение, вы фактически можете поместить код выше в тело цикла. Но существует способ лучше и точнее. Вы можете использовать getPositionStream , который возвращает Stream<Subscription>. Вы также можете настроить требуемое значение изменения местоположения перед тем как слушатель будет уведомлен, используя distanceFilter .
LocationOptions locationOptions = LocationOptions(accuracy: LocationAccuracy.high, distanceFilter: 1);
StreamSubscription positionStream = _geolocator.getPositionStream(locationOptions).listen((Position position) {_position = position;});
Листинг программы
Ниже представлен полный код данного руководства:
В оригинальный код добавлен метод setState() для обновления положения в реальном времени
StreamSubscription positionStream = _geolocator.getPositionStream(locationOptions).listen((Position position) { setState(() {
_position = position;
});});
Можно скопировать этот код и запустить приложение:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Geolocation',
home: GeolocationExample(),
);
}
}
class GeolocationExampleState extends State {
Geolocator _geolocator;
Position _position;
void checkPermission() {
_geolocator.checkGeolocationPermissionStatus().then((status) { print('status: $status'); });
_geolocator.checkGeolocationPermissionStatus(locationPermission: GeolocationPermission.locationAlways).then((status) { print('always status: $status'); });
_geolocator.checkGeolocationPermissionStatus(locationPermission: GeolocationPermission.locationWhenInUse)..then((status) { print('whenInUse status: $status'); });
}
@override
void initState() {
super.initState();
_geolocator = Geolocator();
LocationOptions locationOptions = LocationOptions(accuracy: LocationAccuracy.high, distanceFilter: 1);
checkPermission();
updateLocation();
StreamSubscription positionStream = _geolocator.getPositionStream(locationOptions).listen((Position position) { setState(() {
_position = position;
});});
}
void updateLocation() async {
try {
Position newPosition = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high)
.timeout(new Duration(seconds: 5));
setState(() {
_position = newPosition;
});
} catch (e) {
print('Error: ${e.toString()}');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Startup Name Generator'),
),
body: Center(
child: Text(
'Latitude: ${_position != null ? _position.latitude.toString() : '0'},'
' Longitude: ${_position != null ? _position.longitude.toString() : '0'}'
)
),
);
}
}
class GeolocationExample extends StatefulWidget {
@override
GeolocationExampleState createState() => new GeolocationExampleState();
}
Результат работы программы определение местоположения, GPS координаты, на Flutter.