Недавно возникла необходимость сделать простое мобильное приложение для работы со своей геопозицией и отображением ее на карте. В одной из прошлых статей я написал как можно сделать простое мобильное приложение на flutter. Поэтому для текущей задачи я решил использовать его же.
Выбор библиотек
Для определения геопозиции у flutter’а есть несколько библиотек, например location или geolocator. Подробнее с ними можно ознакомиться здесь. Я для себя выбрал location
.
После выбора библиотеки для работы с локацией, нужно найти библиотеку для работы с картой для отображения геопозиции. Я выбрал для себя flutter_map, основанный на javasrcipt бибилиотеке Leaflet.
Создание приложения
Для доступа к gps необходимо предоставить приложению разрешения.
Для этого в Android манифест нужно добавить:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Для iOS в Info.plist:
<key>NSLocationAlwaysUsageDescription</key>
<string>Needed to access location</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Needed to access location</string>
В файл pubspec.yaml
необходимо добавить следующие зависимости:
dependencies:
flutter_map:
location:
Код приложения будет следующий:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong/latlong.dart';
import 'package:location/location.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'TMS Client',
theme: ThemeData(
primarySwatch: Colors.blueGrey,
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() {
return _HomePageState();
}
}
class _HomePageState extends State<HomePage> {
Marker _marker;
Timer _timer;
int _markerIndex = 0;
Location location = Location();
@override
void initState() {
super.initState();
_timer = Timer.periodic(Duration(seconds: 1), (_) {
setState(() {
location.getLocation().then((p) {
_marker = Marker(
width: 80.0,
height: 80.0,
point: LatLng(p.latitude, p.longitude),
builder: (ctx) => Container(
child: Icon(Icons.directions_car),
),
);
});
});
});
}
@override
void dispose() {
super.dispose();
_timer.cancel();
}
@override
Widget build(BuildContext context) {
if (_marker == null) {
return new Container();
}
return Scaffold(
appBar: new AppBar(title: new Text("Карта")),
body: FlutterMap(
options: new MapOptions(
center: _marker.point,
zoom: 12.0,
),
layers: [
new TileLayerOptions(
urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
subdomains: ['a', 'b', 'c'],
),
MarkerLayerOptions(markers: <Marker>[_marker]),
],
),
);
}
}
Как видно из кода, тут созадется виджет с состоянием, который раз в секунду получает координаты с помощью функции location.getLocation()
и создает маркер, который отрисовывается на карте.
Ну а дальше собствтенно отрисовывается карта с помощью виджета FlutterMap
с центрированием в точке маркера. В качестве слоя подолжки я буду использовать тайлы openstreetmap с помощью TileLayerOptions
(так же есть возможность использовать Mapbox например). А для того чтобы ее обновлялось местоположение маркера исользуется специальный слой MarkerLayerOptions
.
Теперь осталось установить приложение в телефон, для этого нужно выполнить комнды:
flutter build app
flutter install
В итоге получилось следующее приложение:

Заключение
Разработка данного приложения у меня заняла где-то полдня от момнета начала работы до деплоя на телефон. Дальше не составит труда можернизировать это приложение под то, чтобы оно передавало телеметрию на сервер, для сбора статистики например.
Также надо отметить, что можно собирать телеметрию не по таймеру как в примере, а с помощью функции onLocationChanged
, у которой тоже можно настроить таймаут для сбора телеметрии.