The most popular mapping platform is definately the Google maps. In this tutorial we will look at how to integrate them in a Flutter application.

Use google_maps_flutter package

google_maps_flutter is a Flutter plugin that provides a Google Maps widget.

Step 1: Get API Key

The first step is to get an API key from Google. Follow the following instructions:

  • Get an API key at https://cloud.google.com/maps-platform/.

  • Enable Google Map SDK for each platform.

    • Go to Google Developers Console.
    • Choose the project that you want to enable Google Maps on.
    • Select the navigation menu and then select "Google Maps".
    • Select "APIs" under the Google Maps menu.
    • To enable Google Maps for Android, select "Maps SDK for Android" in the "Additional APIs" section, then select "ENABLE".
    • To enable Google Maps for iOS, select "Maps SDK for iOS" in the "Additional APIs" section, then select "ENABLE".
    • Make sure the APIs you enabled are under the "Enabled APIs" section.

For more details, see Getting started with Google Maps Platform.

Step 2: Install google_maps_flutter

start by installing this package. Add it as a dependency in your pubspec.yaml:

dependencies:
  google_maps_flutter: ^2.0.11

Then sync or flutter pub get.

Alternatively you can also install it from the commandline using the following command:

flutter pub add google_maps_flutter

Step 3: Setup Platform

You need to setup your target platforms as follows:

Android

  1. Set the minSdkVersion in android/app/build.gradle:
android {
    defaultConfig {
        minSdkVersion 20
    }
}

This means that app will only be available for users that run Android SDK 20 or higher.

  1. Specify your API key in the application manifest android/app/src/main/AndroidManifest.xml:
<manifest ...
  <application ...
    <meta-data android:name="com.google.android.geo.API_KEY"
               android:value="YOUR KEY HERE"/>

iOS

This plugin requires iOS 9.0 or higher. To set up, specify your API key in the application delegate ios/Runner/AppDelegate.m:

#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
#import "GoogleMaps/GoogleMaps.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GMSServices provideAPIKey:@"YOUR KEY HERE"];
  [GeneratedPluginRegistrant registerWithRegistry:self];
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}
@end

Or in your swift code, specify your API key in the application delegate ios/Runner/AppDelegate.swift:

import UIKit
import Flutter
import GoogleMaps

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GMSServices.provideAPIKey("YOUR KEY HERE")
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

Step : Write Code

Start by importing the package classes:

import 'package:google_maps_flutter/google_maps_flutter.dart';

Below is a simple example of how to add a google map to your Flutter app:

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Google Maps Demo',
      home: MapSample(),
    );
  }
}

class MapSample extends StatefulWidget {
  @override
  State<MapSample> createState() => MapSampleState();
}

class MapSampleState extends State<MapSample> {
  Completer<GoogleMapController> _controller = Completer();

  static final CameraPosition _kGooglePlex = CameraPosition(
    target: LatLng(37.42796133580664, -122.085749655962),
    zoom: 14.4746,
  );

  static final CameraPosition _kLake = CameraPosition(
      bearing: 192.8334901395799,
      target: LatLng(37.43296265331129, -122.08832357078792),
      tilt: 59.440717697143555,
      zoom: 19.151926040649414);

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: GoogleMap(
        mapType: MapType.hybrid,
        initialCameraPosition: _kGooglePlex,
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: _goToTheLake,
        label: Text('To the lake!'),
        icon: Icon(Icons.directions_boat),
      ),
    );
  }

  Future<void> _goToTheLake() async {
    final GoogleMapController controller = await _controller.future;
    controller.animateCamera(CameraUpdate.newCameraPosition(_kLake));
  }
}

Full Example

Find a full example in the link provided below.

Reference

Below are the reference links:

Number Link
1. Download Example
2. Read more

Example 1: Flutter Google Maps and Directions API

This is a full example to teach you Google Maps usage with Directions API. The example is done in a step by step manner for easy following.

The app has will teach the following concepts:

  • Detect the current location of the user
  • Use Geocoding for converting addresses to coordinates and vice versa
  • Add Markers to the Map View
  • Draw the route between two places using Polylines and Directions API
  • Calculate the actual distance of the route

Step 1: Install Necessary Packages

Three packages have been used:

In your pubspecy.yaml declare them as dependencies:

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^0.1.3
  google_maps_flutter: ^2.0.6
  geolocator: ^7.0.3
  geocoding: ^2.0.0
  flutter_polyline_points: ^1.0.0

Sync or flutter pub get to fetch them.

Step 2: Setup API Key

You need to make a new project in the Google Cloud Platform, and enable the Google Maps API for that project. Also, don't forget to setup the Billing for that project on GCP, otherwise you will receive the following error:

  • Clone the repository.

    git clone https://github.com/sbis04/flutter_maps.git
  • Open the project using your favorite IDE. For opening with VS Code:

    code flutter_maps
  • For the Android part, go to android/app/src/main/AndroidManifest.xml file and add your API key here.

    
    
  • For the iOS part, go to ios/Runner/AppDelegate.swift file and add your API key here.

    GMSServices.provideAPIKey("YOUR KEY HERE")
  • Go to the lib/secrets.dart file and add your API key here.

Step 3: Configure App

NB/= These steps are unnecessary if you are cloning or downloading the app. They've already been done.However if you are creating a project from scratch then follow them

Android

  • Navigate to the file android/app/src/main/AndroidManifest.xml and add the following code snippet inside the application tag:

    <!-- Add your Google Maps API Key here -->
    <meta-data android:name="com.google.android.geo.API_KEY"
                   android:value="YOUR KEY HERE"/>
  • Also, you will need location access in the app. So, add the following permission in the same file inside the manifest tag:

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

iOS

  • Navigate to the file ios/Runner/AppDelegate.swift and replace the whole code with the following:

    import UIKit
    import Flutter
    import GoogleMaps
    
    @UIApplicationMain
    @objc class AppDelegate: FlutterAppDelegate {
      override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        //Add your Google Maps API Key here
        GMSServices.provideAPIKey("YOUR KEY HERE")
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }
    }
  • Also, add the following to ios/Runner/Info.plist file:

    io.flutter.embedded_views_preview
    YES
    
  • For getting location permission, add the following to the same file:

    NSLocationWhenInUseUsageDescription
    This app needs access to location when open.

Step 4: Create API class

This is the class that will contain the API key:

secrets.dart

class Secrets {
  // Add your Google Maps API Key here
  static const API_KEY = 'API KEY HERE';
}

Step 4: main class

Create the main.dart and add imports:

import 'package:flutter/material.dart';
import 'package:flutter_maps/secrets.dart'; // Stores the Google Maps API Key
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

import 'dart:math' show cos, sqrt, asin;

Create main function. We run our MyApp class:

void main() {
  runApp(MyApp());
}

Create the MyApp class as a StatelessWidget:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Maps',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MapView(),
    );
  }
}

Create a MapView as a StatefulWidget:

class MapView extends StatefulWidget {
  @override
  _MapViewState createState() => _MapViewState();
}

Now create the State class for the above MapView:

class _MapViewState extends State<MapView> {

Add the instance fields:

  CameraPosition _initialLocation = CameraPosition(target: LatLng(0.0, 0.0));
  late GoogleMapController mapController;

  late Position _currentPosition;
  String _currentAddress = '';

  final startAddressController = TextEditingController();
  final destinationAddressController = TextEditingController();

  final startAddressFocusNode = FocusNode();
  final desrinationAddressFocusNode = FocusNode();

  String _startAddress = '';
  String _destinationAddress = '';
  String? _placeDistance;

  Set<Marker> markers = {};

  late PolylinePoints polylinePoints;
  Map<PolylineId, Polyline> polylines = {};
  List<LatLng> polylineCoordinates = [];

  final _scaffoldKey = GlobalKey<ScaffoldState>();

Build a textfield widget:

  Widget _textField({
    required TextEditingController controller,
    required FocusNode focusNode,
    required String label,
    required String hint,
    required double width,
    required Icon prefixIcon,
    Widget? suffixIcon,
    required Function(String) locationCallback,
  }) {
    return Container(
      width: width * 0.8,
      child: TextField(
        onChanged: (value) {
          locationCallback(value);
        },
        controller: controller,
        focusNode: focusNode,
        decoration: new InputDecoration(
          prefixIcon: prefixIcon,
          suffixIcon: suffixIcon,
          labelText: label,
          filled: true,
          fillColor: Colors.white,
          enabledBorder: OutlineInputBorder(
            borderRadius: BorderRadius.all(
              Radius.circular(10.0),
            ),
            borderSide: BorderSide(
              color: Colors.grey.shade400,
              width: 2,
            ),
          ),
          focusedBorder: OutlineInputBorder(
            borderRadius: BorderRadius.all(
              Radius.circular(10.0),
            ),
            borderSide: BorderSide(
              color: Colors.blue.shade300,
              width: 2,
            ),
          ),
          contentPadding: EdgeInsets.all(15),
          hintText: hint,
        ),
      ),
    );
  }

The following function shows you how you get the current location:

  _getCurrentLocation() async {
    await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high)
        .then((Position position) async {
      setState(() {
        _currentPosition = position;
        print('CURRENT POS: $_currentPosition');
        mapController.animateCamera(
          CameraUpdate.newCameraPosition(
            CameraPosition(
              target: LatLng(position.latitude, position.longitude),
              zoom: 18.0,
            ),
          ),
        );
      });
      await _getAddress();
    }).catchError((e) {
      print(e);
    });
  }

The following function shows you how to get the address:

  _getAddress() async {
    try {
      List<Placemark> p = await placemarkFromCoordinates(
          _currentPosition.latitude, _currentPosition.longitude);

      Placemark place = p[0];

      setState(() {
        _currentAddress =
            "${place.name}, ${place.locality}, ${place.postalCode}, ${place.country}";
        startAddressController.text = _currentAddress;
        _startAddress = _currentAddress;
      });
    } catch (e) {
      print(e);
    }
  }

The following function shows you hot calculate the distance between two places:

  Future<bool> _calculateDistance() async {
    try {
      // Retrieving placemarks from addresses
      List<Location> startPlacemark = await locationFromAddress(_startAddress);
      List<Location> destinationPlacemark =
          await locationFromAddress(_destinationAddress);

      // Use the retrieved coordinates of the current position,
      // instead of the address if the start position is user's
      // current position, as it results in better accuracy.
      double startLatitude = _startAddress == _currentAddress
          ? _currentPosition.latitude
          : startPlacemark[0].latitude;

      double startLongitude = _startAddress == _currentAddress
          ? _currentPosition.longitude
          : startPlacemark[0].longitude;

      double destinationLatitude = destinationPlacemark[0].latitude;
      double destinationLongitude = destinationPlacemark[0].longitude;

      String startCoordinatesString = '($startLatitude, $startLongitude)';
      String destinationCoordinatesString =
          '($destinationLatitude, $destinationLongitude)';

      // Start Location Marker
      Marker startMarker = Marker(
        markerId: MarkerId(startCoordinatesString),
        position: LatLng(startLatitude, startLongitude),
        infoWindow: InfoWindow(
          title: 'Start $startCoordinatesString',
          snippet: _startAddress,
        ),
        icon: BitmapDescriptor.defaultMarker,
      );

      // Destination Location Marker
      Marker destinationMarker = Marker(
        markerId: MarkerId(destinationCoordinatesString),
        position: LatLng(destinationLatitude, destinationLongitude),
        infoWindow: InfoWindow(
          title: 'Destination $destinationCoordinatesString',
          snippet: _destinationAddress,
        ),
        icon: BitmapDescriptor.defaultMarker,
      );

      // Adding the markers to the list
      markers.add(startMarker);
      markers.add(destinationMarker);

      print(
        'START COORDINATES: ($startLatitude, $startLongitude)',
      );
      print(
        'DESTINATION COORDINATES: ($destinationLatitude, $destinationLongitude)',
      );

      // Calculating to check that the position relative
      // to the frame, and pan & zoom the camera accordingly.
      double miny = (startLatitude <= destinationLatitude)
          ? startLatitude
          : destinationLatitude;
      double minx = (startLongitude <= destinationLongitude)
          ? startLongitude
          : destinationLongitude;
      double maxy = (startLatitude <= destinationLatitude)
          ? destinationLatitude
          : startLatitude;
      double maxx = (startLongitude <= destinationLongitude)
          ? destinationLongitude
          : startLongitude;

      double southWestLatitude = miny;
      double southWestLongitude = minx;

      double northEastLatitude = maxy;
      double northEastLongitude = maxx;

      // Accommodate the two locations within the
      // camera view of the map
      mapController.animateCamera(
        CameraUpdate.newLatLngBounds(
          LatLngBounds(
            northeast: LatLng(northEastLatitude, northEastLongitude),
            southwest: LatLng(southWestLatitude, southWestLongitude),
          ),
          100.0,
        ),
      );

      // Calculating the distance between the start and the end positions
      // with a straight path, without considering any route
      // double distanceInMeters = await Geolocator.bearingBetween(
      //   startLatitude,
      //   startLongitude,
      //   destinationLatitude,
      //   destinationLongitude,
      // );

      await _createPolylines(startLatitude, startLongitude, destinationLatitude,
          destinationLongitude);

      double totalDistance = 0.0;

      // Calculating the total distance by adding the distance
      // between small segments
      for (int i = 0; i < polylineCoordinates.length - 1; i++) {
        totalDistance += _coordinateDistance(
          polylineCoordinates[i].latitude,
          polylineCoordinates[i].longitude,
          polylineCoordinates[i + 1].latitude,
          polylineCoordinates[i + 1].longitude,
        );
      }

      setState(() {
        _placeDistance = totalDistance.toStringAsFixed(2);
        print('DISTANCE: $_placeDistance km');
      });

      return true;
    } catch (e) {
      print(e);
    }
    return false;
  }

Find the full code in the download

Run

  1. Download the code below.
  2. Obtain and add your API Key.
  3. Build and Run

Reference

Find the donwload link below:

Number Link
1. Download Example
2. Follow code author