How to Add Location Tracking to Your App Using Syncfusion Flutter Maps
Tags: flutter, dart, mobile, webdev
Published: 2020-11-02 10:46:11

---
title: How to Add Location Tracking to Your App Using Syncfusion Flutter Maps
published: true
date: 2020-10-28 10:00:10 UTC
tags: flutter, dart, mobile, webdev
canonical_url: https://www.syncfusion.com/blogs/post/how-to-add-location-tracking-to-your-app-using-syncfusion-flutter-maps.aspx
cover_image: https://www.syncfusion.com/blogs/wp-content/uploads/2020/10/How-to-Add-Location-Tracking-to-Your-App-Using-Syncfusion-Flutter-Maps-672x372.png
---
The [Syncfusion Flutter Maps](https://www.syncfusion.com/flutter-widgets/flutter-maps) widget is a data-visualization library written natively in the [Dart](https://dart.dev/) language. It displays a geographical area from GeoJSON data. It has highly interactive and customizable features that enrich the end-user experience by presenting the data of the regions in more intuitive ways. An introduction blog about the Maps widget can be read [here](https://dev.to/sureshmohan/introducing-the-new-maps-widget-in-flutter-544k-temp-slug-4970983).

In this blog, we are going to focus on one of the most important features in most real-world applications, like e-commerce apps: location tracking. For example, use it to check out the current location of an order at any given time. Though there are many ways to visualize this data, maps would be the perfect one for most cases. This can be done with the Syncfusion Flutter Maps widget using some of its built-in features.

We are going to combine the [markers](https://help.syncfusion.com/flutter/maps/markers) feature in the Maps widget with the [geolocator](https://pub.dev/packages/geolocator) and [geocoding](https://pub.dev/packages/geocoding) packages for the location tracking feature in the Flutter application. We will discuss adding the markers in the Maps widget and how they can be used to denote locations in the maps along with custom widgets.

Let’s start exploring them!

## Add Flutter Maps to your application

This section explains the procedure to add the Flutter Maps widget to your application.

1. Add the [Syncfusion Flutter Maps ](https://pub.dev/packages/syncfusion_flutter_maps)dependency to the pubspec.yaml file.
```dart
dependencies:
  syncfusion_flutter_maps: ^18.2.44-beta   

```
2. Run the following command to get the required packages.  

| `$ flutter pub get` |

3. Now, import the library using the following code.
```dart
import 'package:syncfusion_flutter_maps/maps.dart';  

```
4. After importing the package, initialize the Maps widget as a child to any widget, like in the following code example.
```dart
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Center(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: SfMaps(),
          ),
        ),
      ),
    );
  }
```
5. Add the GeoJSON file for the shape layer. Here, we are going to render the USA map. Get this [usa.json](https://www.syncfusion.com/blogs/wp-content/uploads/2020/09/usa.json.zip) file and add it to the  **assets**  folder and in the pubspec.yaml file of your application. The actual geographical rendering is done in each [MapShapeLayer](https://pub.dev/documentation/syncfusion_flutter_maps/latest/maps/MapShapeLayer-class.html) method using the [delegate](https://pub.dev/documentation/syncfusion_flutter_maps/latest/maps/MapShapeLayer/delegate.html) property. The path of the .json file that contains the GeoJSON data has to be set to the [MapShapeLayerDelegate.shapeFile](https://pub.dev/documentation/syncfusion_flutter_maps/latest/maps/MapShapeLayerDelegate/shapeFile.html), as shown in the following code snippet. The [MapShapeLayerDelegate.shapeDataField](https://pub.dev/documentation/syncfusion_flutter_maps/latest/maps/MapShapeLayerDelegate-class.html) is used to refer to the unique field name in the .json file to identify each shape.
```dart
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Center(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: SfMaps(
              layers: [
                MapShapeLayer(
                  delegate: MapShapeLayerDelegate(
                    shapeFile: 'assets/usa.json',
                    shapeDataField: 'name',
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
```

After executing the above code, we will get output like in the following screenshot.

![Flutter Maps](https://www.syncfusion.com/blogs/wp-content/uploads/2020/10/Flutter-Maps.png)<figcaption>Flutter Maps</figcaption>

After finishing the initial rendering, it’s time to add markers in it.

## Adding markers

Markers can be easily positioned on maps at the required latitude and longitude. Markers provide built-in shapes to display, such as circles, squares, triangles, and diamonds. Or use a custom widget as a marker, like cars for the cab-booking apps, bikes for food delivery apps, and so on.

If you want to add markers in the loading time itself, you can refer to this link in our [user guide](https://help.syncfusion.com/flutter/maps/markers#adding-markers). Here, we are going to focus on adding markers dynamically alone for our use case. For this, you will need the help of the [MapShapeLayerController](https://pub.dev/documentation/syncfusion_flutter_maps/latest/maps/MapShapeLayerController-class.html) class. It allows you to modify the markers collection dynamically by adding, removing, updating, and deleting the markers.

In the following code snippet, we will see how we can add a marker dynamically at a specific latitude and longitude using the [insertMarker](https://pub.dev/documentation/syncfusion_flutter_maps/latest/maps/MapLayerController/insertMarker.html) method in the[ MapShapeLayerController](https://pub.dev/documentation/syncfusion_flutter_maps/latest/maps/MapShapeLayerController-class.html) class. Here, I am adding a built-in marker at Washington, D.C., on the button click for demo purposes. In the upcoming sections, we will add markers at the current destination locations and we will update the other marker’s location whenever the location changes.

Once the[ insertMarker](https://pub.dev/documentation/syncfusion_flutter_maps/latest/maps/MapLayerController/insertMarker.html) method is called, the [markerBuilder](https://pub.dev/documentation/syncfusion_flutter_maps/latest/maps/MapLayer/markerBuilder.html) property will be called for the respective index. This is where you have to return the MapMarker, which can be changed based on the current index.

Refer to the following code example.

```dart
class _LocationTrackerBlogState extends State {
  
  final MapShapeLayerController _layerController = MapShapeLayerController();

  @override
  void dispose() {
    _layerController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Center(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Column(
              children: [
                SfMaps(
                  layers: [
                    MapShapeLayer(
                      controller: _layerController,
                      delegate: MapShapeLayerDelegate(
                        shapeFile: 'assets/usa.json',
                        shapeDataField: 'name',
                      ),
                      markerBuilder: (BuildContext context, int index) {
                        return MapMarker(
                          latitude: 38.8951,
                          longitude: -77.0364,
                        );
                      },
                    ),
                  ],
                ),
                FlatButton(
                  child: Text('Add marker'),
                  onPressed: () {
                    _layerController.insertMarker(0);
                  },
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
```

After executing this code example, we will get output like the following .gif image.  
 ![Adding Markers to the Flutter Maps](https://www.syncfusion.com/blogs/wp-content/uploads/2020/10/Adding-Markers-to-the-Flutter-Maps.gif)

## Let’s improve the application UI

Before tracking the real-time location, let’s make some UI improvements in the application. We will not dive deep into the UI design part here. Don’t get startled by the sudden increase in total lines of codes. All of the widgets used here are very basic and there are already many references and articles for them.

You can see some of the  **onPressed** callbacks are left empty. This is where the actual marker updates the location tracking when it happens. We will get to that shortly.

```dart 
class _LocationTrackerBlogState extends State {
  
  final MapShapeLayerController _layerController = MapShapeLayerController();
  final TextEditingController _currentLocationTextController =
      TextEditingController();
  final TextEditingController _destinationLocationTextController =
      TextEditingController();

  double _distanceInMiles;
  
  Position _currentPosition, _destinationPosition;

  @override
  void dispose() {
    _layerController.dispose();
    _currentLocationTextController.dispose();
    _destinationLocationTextController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFF096770),
      body: SafeArea(
        child: Column(
          children: [
            //Title widget
            Padding(
              padding: const EdgeInsets.all(20.0),
              child: Text(
                'Location Tracker',
                style: TextStyle(
                    fontSize: 30,
                    color: Colors.white,
                    fontWeight: FontWeight.bold),
              ),
            ),
            Row(
              children: [
                //Current location text field.
                Expanded(
                  child: Container(
                    padding: EdgeInsets.all(10),
                    child: TextField(
                      controller: _currentLocationTextController,
                      style: TextStyle(color: Colors.white),
                      decoration: InputDecoration(
                        contentPadding: EdgeInsets.only(
                            left: 10, right: 3, top: 3, bottom: 3),
                        enabledBorder: const OutlineInputBorder(
                          borderSide: const BorderSide(color: Colors.white),
                        ),
                        focusedBorder: const OutlineInputBorder(
                          borderSide: const BorderSide(color: Colors.white),
                        ),
                        hintText: 'Current location',
                        hintStyle: TextStyle(color: Colors.white),
                      ),
                    ),
                  ),
                ),
                //Current location clickable icon.
                IconButton(
                  icon: Icon(
                    Icons.my_location,
                    color: Colors.white,
                  ),
                  tooltip: 'My location',
                  onPressed: () async {},
                )
              ],
            ),
            Row(
              children: [
                //Destination location text field.
                Expanded(
                  child: Container(
                    padding: EdgeInsets.all(10),
                    child: TextField(
                      controller: _destinationLocationTextController,
                      style: TextStyle(color: Colors.white),
                      decoration: InputDecoration(
                        hintStyle: TextStyle(color: Colors.white),
                        contentPadding: EdgeInsets.only(
                            left: 10, right: 3, top: 3, bottom: 3),
                        hintText: 'Enter the destination',
                        enabledBorder: const OutlineInputBorder(
                          borderSide: const BorderSide(color: Colors.white),
                        ),
                        focusedBorder: const OutlineInputBorder(
                          borderSide: const BorderSide(color: Colors.white),
                        ),
                      ),
                    ),
                  ),
                ),
                //Destination location clickable icon.
                IconButton(
                  icon: Icon(
                    Icons.search,
                    color: Colors.white,
                  ),
                  tooltip: 'Search',
                  onPressed: () async {},
                )
              ],
            ),
            //Maps widget container
            Container(
              child: Expanded(
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: SfMaps(
                    layers: [
                      MapShapeLayer(
                          controller: _layerController,
                          delegate: MapShapeLayerDelegate(
                            shapeFile: 'assets/usa.json',
                            shapeDataField: 'name',
                      )),
                    ],
                  ),
                ),
              ),
            ),
            //Widget for starting location and stopping location
            //tracking. It also shows the current distance between the
            //current and destination location in miles.
            Card(
              child: Padding(
                padding: const EdgeInsets.all(20.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: [
                    RichText(
                      text: TextSpan(
                        children: [
                          TextSpan(
                              text: '${_distanceInMiles?.toStringAsFixed(2) ?? '-'} miles.',
                              style: TextStyle(
                                  fontSize: 20,
                                  fontStyle: FontStyle.italic,
                                  color: Colors.black)),
                          TextSpan(
                              text: '${'-'} miles.',
                              style: TextStyle(
                                  fontWeight: FontWeight.bold,
                                  fontSize: 20,
                                  color: Colors.black))
                        ],
                      ),
                    ),
                    SizedBox(height: 10),
                    Row(
                      children: [
                        OutlineButton(
                          child: Text('Navigate'),
                          textColor: Colors.black,
                          onPressed: () async {},
                        ),
                        SizedBox(
                          width: 15,
                        ),
                        OutlineButton(
                          child: Text('Remove tracker'),
                          onPressed: () {},
                        )
                      ],
                    ),
                  ],
                ),
              ),
            )
          ],
        ),
      ),
    );
  }          

```

After executing this code example, we will get output like the following .gif image.  
 ![Location Tracker](https://www.syncfusion.com/blogs/wp-content/uploads/2020/10/Location-Tracker.png)

## Flutter geolocation plugins

From this point, we will need the help of two popular packages in the pub.dev file i.e. the [geolocator](https://pub.dev/packages/geolocator) and [geocoding](https://pub.dev/packages/geocoding). It provides some of the interesting features out of the box. Though there are many, we will make use of the below features and combine them with Syncfusion Flutter Maps widget.

- Get the current location of the device.
- Get continuous location updates.
- Calculate the distance (in meters) between the two geocoordinates.

### Adding the required plugins

Add the [geolocator](https://pub.dev/packages/geolocator) and [geocoding](https://pub.dev/packages/geocoding) packages in the pubspec.yaml file.

```dart 
dependencies:
  syncfusion_flutter_maps: ^18.2.54-beta
  geolocator: ^6.0.0+4
  geocoding: ^1.0.3
```

Then, run the following command.

| `$ flutter pub get ` |

### Adding the necessary permissions

It is mandatory to enable the few platform-specific permissions in the Android and iOS projects. Since, the steps are specified clearly in the [documentation](https://pub.dev/packages/geolocator#usage) of the package itself, I am not going to repeat them again here.

Please make sure these lines are added in the **android/app/src/main/AndroidManifest.xml**.  
 ![Add these lines of code in android/app/src/main/AndroidManifest.xml](https://www.syncfusion.com/blogs/wp-content/uploads/2020/10/Add-these-lines-of-code-in-androidappsrcmainAndroidManifest.xml_.png)

And in the **ios/Runner/Info.plist** , the following lines of code should be there.  
 ![Add thes lines of code in ios/Runner/Info.plist](https://www.syncfusion.com/blogs/wp-content/uploads/2020/10/Add-thes-lines-of-code-in-iosRunnerInfo.plist_.png)

## Adding a marker at the current location

In the **onPressed** callback of the **Icons.my\_location** , we will request the current location through the [getCurrentPosition](https://pub.dev/documentation/geolocator/latest/geolocator/getCurrentPosition.html) method. We will use the [MapShapeLayerController.insertMarker](https://pub.dev/documentation/syncfusion_flutter_maps/latest/maps/MapLayerController/insertMarker.html) method to add the marker at the current location. We will also request the current location’s address from the [placemarkFromCoordinates](https://pub.dev/documentation/geocoding/latest/geocoding/placemarkFromCoordinates.html) method by passing the obtained current latitude and longitude as the arguments. The current location’s address will be updated in the TextField by setting the \_currentLocationTextController.text.

Refer to the following code.

```dart  
IconButton(
   icon: Icon(
           Icons.my_location,
           color: Colors.white,
        ),
    tooltip: 'My location',
    onPressed: () async {
        _currentPosition = await getCurrentPosition(
               desiredAccuracy: LocationAccuracy.high);
        List addresses = await placemarkFromCoordinates(
        _currentPosition.latitude, _currentPosition.longitude);
        _currentLocationTextController.text = addresses[0].name;
        _layerController.insertMarker(0);
    },
 )
```

The **markerBuilder** will now look like this.

```dart  
MapShapeLayer(
    controller: _layerController,
    markerBuilder: (BuildContext context, int index) {
      if (index == 0) {
        //current position
        return MapMarker(
            latitude: _currentPosition.latitude,
            longitude: _currentPosition.longitude,
            child: Icon(Icons.location_on));
      }
      return null;
    },
    delegate: MapShapeLayerDelegate(
      shapeFile: 'assets/usa.json',
      shapeDataField: 'name',
    )),
```

After executing this code example, we will get output like the following .gif image.

![Adding a Marker at the Current Location](https://www.syncfusion.com/blogs/wp-content/uploads/2020/10/current_location.gif)<figcaption>Adding a marker at the current location</figcaption>

You can see that both the TextField and marker updated properly. In the emulator location, I have set the current location as **San Francisco International Airport**. If you are using a real device, the actual location will be shown to you.

## Adding a marker at the destination location

In the **onPressed** callback of the **Icons.search,** we will get the latitude and longitude of the destination address from the [locationFromAddress](https://pub.dev/documentation/geocoding/latest/geocoding/locationFromAddress.html) method. This will accept the address as an argument. This latitude and longitude will then be used to add a marker at the destination location. You can get the current address as a string from the  **\_destinationLocationTextController.text**.

There is also an API for finding the distance between the current and destination locations. You can use the [distanceBetween](https://pub.dev/documentation/geolocator/latest/geolocator/distanceBetween.html) method for this requirement. It will accept the current and destination latitude and longitude coordinates as inputs and return the distance in meters. We will do a simple math calculation to convert this to miles.

Refer to the following code example.

```dart  
IconButton(
  icon: Icon(
    Icons.search,
    color: Colors.white,
  ),
  tooltip: 'Search',
  onPressed: () async {
    List places = await locationFromAddress(
        _destinationLocationTextController.text);
    _destinationPosition = Position(
        longitude: places[0].longitude,
        latitude: places[0].latitude);
    _layerController.insertMarker(1);

    //1 mile = 0.000621371 * meters
    setState(() {
     _distanceInMiles = distanceBetween(
      _currentPosition.latitude,
      _currentPosition.longitude,
      _destinationPosition.latitude,
      _destinationPosition.longitude) *
      0.000621371;
    });
  },
)
```

Then, the process will be the same as the previous one. The **markerBuilder** will now look like the following.

```dart  
MapShapeLayer(
    controller: _layerController,
    markerBuilder: (BuildContext context, int index) {
      if (index == 0) {
        //current position
        return MapMarker(
            latitude: _currentPosition.latitude,
            longitude: _currentPosition.longitude,
            child: Icon(Icons.location_on));
      } else if (index == 1) {
        //destination position
        return MapMarker(
            latitude: _destinationPosition.latitude,
            longitude: _destinationPosition.longitude,
            child: Icon(Icons.location_on));
      }
      return null;
    },
    delegate: MapShapeLayerDelegate(
      shapeFile: 'assets/usa.json',
      shapeDataField: 'name',
    )),
```

After executing this code example, we will get output like the following .gif image.

![Adding a marker at the destination location](https://www.syncfusion.com/blogs/wp-content/uploads/2020/10/Adding-a-marker-at-the-destination-location.gif)<figcaption>Adding a marker at the destination location</figcaption>

## Updating the marker to the current location

We now have a current location and a destination location. Let’s add another marker and update its position whenever the current location changes. Once the **Navigate** button is clicked, we will add another marker, a flight icon, in the current location. As the location changes, this icon will move towards the destination. For listening to the location changes, we will use the [getPositinoStream()](https://pub.dev/documentation/geolocator/latest/geolocator/getPositionStream.html) method. Whenever the callback is called, we will update the position of this marker using the [MapShapeLayerController.updateMarkers()](https://pub.dev/documentation/syncfusion_flutter_maps/latest/maps/MapLayerController/updateMarkers.html) method. We will also update the  **\_distanceInMiles** field, which in turn will update the  **TextSpan,** which shows the remaining distance.

Refer to the following code example.

```dart
  OutlineButton(
  child: Text('Navigate'),
  textColor: Colors.black,
  onPressed: () async {
    _layerController.insertMarker(2);
    _positionStream = getPositionStream()
        .listen((Position position) {
      _currentPosition = position;
      //1 mile = 0.000621371 * meters
      setState(() {
        _distanceInMiles = distanceBetween(
            _currentPosition.latitude,
            _currentPosition.longitude,
            _destinationPosition.latitude,
            _destinationPosition.longitude) *
            0.000621371;
      });
      _layerController.updateMarkers([2]);
    });
  },
),
```

The **markerBuilder** will now look like the following.

```dart  
MapShapeLayer(
    controller: _layerController,
    markerBuilder: (BuildContext context, int index) {
      if (index == 0) {
        //current position
        return MapMarker(
            latitude: _currentPosition.latitude,
            longitude: _currentPosition.longitude,
            child: Icon(Icons.location_on));
      } else if (index == 1) {
        //destination position
        return MapMarker(
            latitude: _destinationPosition.latitude,
            longitude: _destinationPosition.longitude,
            child: Icon(Icons.location_on));
      } else if (index == 2) {
        //flight current position
        return MapMarker(
            latitude: _currentPosition.latitude,
            longitude: _currentPosition.longitude,
            child: Transform.rotate(
                      angle: 45,
                      child: Icon(Icons.flight)),
               );
         }
      return null;
    },
    delegate: MapShapeLayerDelegate(
      shapeFile: 'assets/usa.json',
      shapeDataField: 'name',
    )),
```

After executing this code example, we will get output like the following .gif image.

![Updating the marker to the current location](https://www.syncfusion.com/blogs/wp-content/uploads/2020/10/Updating-the-marker-to-the-current-location.gif)<figcaption>Updating the marker to the current location</figcaption>

## Stopping the location tracking

Whenever we want to stop the location tracking, we can use the [cancel()](https://api.flutter.dev/flutter/dart-async/StreamSubscription/cancel.html) method of the [StreamSubscription](https://api.flutter.dev/flutter/dart-async/StreamSubscription-class.html). This will stop the stream listening. You can then use the [MapShapeLayerController.removeMarkerAt()](https://pub.dev/documentation/syncfusion_flutter_maps/latest/maps/MapLayerController/removeMarkerAt.html) method to remove the marker.

Refer to the following code example.

```dart  
OutlineButton(
  child: Text('Remove tracker'),
  onPressed: () {
    _layerController.removeMarkerAt(2);
    _positionStream.cancel();
  },
)
```

After executing this code example, we will get output like the following .gif image.

![Stopping the location tracking](https://www.syncfusion.com/blogs/wp-content/uploads/2020/10/remove_marker.gif)<figcaption>Stopping the location tracking</figcaption>

## Conclusion

In this blog post, I walked you through how the [Syncfusion Flutter Maps](https://www.syncfusion.com/flutter-widgets/flutter-maps) widget can be used for location tracking in your Flutter application with the help of the awesome [geolocator](https://pub.dev/packages/geolocator) and [geocoding](https://pub.dev/packages/geocoding) packages. Try out this widget and share your feedback in the comments section below.

You can check out the complete [user guide](https://help.syncfusion.com/flutter/maps/) and see our samples in this [GitHub location](https://github.com/syncfusion/flutter-examples). Additionally, you can check out our demo apps in the [Google Play Store](https://play.google.com/store/apps/details?id=com.syncfusion.flutter.examples&hl=en), [App Store](https://apps.apple.com/in/app/syncfusion-flutter-ui-widgets/id1475231341), and on our [website](https://flutter.syncfusion.com/#/).

If you need a new widget for the Flutter framework or new features in our existing widgets, you can contact us with suggestions through our [support forum](https://www.syncfusion.com/forums), [Direct-Trac](https://www.syncfusion.com/support/directtrac/incidents), or [feedback portal](https://www.syncfusion.com/feedback/flutter). As always, we are happy to assist you!