Приложение для работы с геоданными на Flutter

Недавно возникла необходимость сделать простое мобильное приложение для работы со своей геопозицией и отображением ее на карте. В одной из прошлых статей я написал как можно сделать простое мобильное приложение на 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, у которой тоже можно настроить таймаут для сбора телеметрии.

Ссылки

  1. Working with Geolocation and Geocoding in Flutter
 
comments powered by Disqus