How to Use Google Maps in Flutter: A Step-by-Step Guide

Yawar Osman
6 min readNov 7, 2024

--

Integrating Google Maps into a Flutter application allows users to view and interact with a map interface. In this article, we’ll cover every step, from setting up your project and obtaining an API key to displaying the map, adding markers, and customizing the map appearance.

Prerequisites

  • Flutter SDK
  • A Google Cloud Platform account (for obtaining an API key)
  • Basic knowledge of Dart and Flutter development

Step 1: Create a New Flutter Project

If you haven’t already created a Flutter project, open your terminal and run:

flutter create google_maps_example
cd google_maps_example

Step 2: Add Google Maps Flutter Plugin

To integrate Google Maps, we’ll use the google_maps_flutter package. Open pubspec.yaml and add the following dependency:

dependencies:
flutter:
sdk: flutter
google_maps_flutter: ^2.2.0 # Make sure to check for the latest version on pub.dev

Run the following command to install the dependency:

flutter pub get

Step 3: Set Up Google Maps API Key

  1. Go to the Google Cloud Console.
  2. Create a new project or select an existing one.
  3. Navigate to APIs & Services > Credentials.
  4. Click on Create Credentials > API Key. Copy the generated API key.
  5. In APIs & Services > Library, enable the following APIs:
  • Maps SDK for Android
  • Maps SDK for iOS

Configuring the API Key for Android and iOS

For Android:

  • Open the android/app/src/main/AndroidManifest.xml file and add the following inside the <application> tag:
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_API_KEY" />

Replace YOUR_API_KEY with your actual API key.

For iOS:

  • Open ios/Runner/AppDelegate.swift (for Swift) or AppDelegate.m (for Objective-C) and add the following inside the application method:
import GoogleMaps  // Add this line at the top
GMSServices.provideAPIKey("YOUR_API_KEY")

Step 4: Add Google Maps to Flutter Application

Now, let’s add the Google Maps widget to our app. Create a new Dart file called google_map_screen.dart and add the following code.

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class GoogleMapScreen extends StatefulWidget {
@override
_GoogleMapScreenState createState() => _GoogleMapScreenState();
}
class _GoogleMapScreenState extends State<GoogleMapScreen> {
late GoogleMapController mapController;
// Set the initial camera position
final CameraPosition initialPosition = CameraPosition(
target: LatLng(37.7749, -122.4194), // Coordinates for San Francisco
zoom: 10.0,
);
// Marker setup
final Set<Marker> markers = {};
// Called when the map is created
void _onMapCreated(GoogleMapController controller) {
mapController = controller;
// Example marker
markers.add(
Marker(
markerId: MarkerId('sfMarker'),
position: LatLng(37.7749, -122.4194),
infoWindow: InfoWindow(
title: 'San Francisco',
snippet: 'A beautiful city',
),
),
);
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Google Maps in Flutter'),
),
body: GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: initialPosition,
markers: markers,
mapType: MapType.normal,
myLocationEnabled: true, // Enables user location
zoomControlsEnabled: true,
),
);
}
}

Step 5: Display the Map Screen

In main.dart, update the home property to display GoogleMapScreen:

import 'package:flutter/material.dart';
import 'google_map_screen.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Google Maps Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: GoogleMapScreen(),
);
}
}

Step 6: Customizing Markers

Adding a custom marker icon can improve the user experience. Save your marker icon in the assets folder, and update pubspec.yaml to include it:

flutter:
assets:
- assets/custom_marker.png

Load and use the custom marker in _onMapCreated:

BitmapDescriptor customIcon;
@override
void initState() {
super.initState();
_loadCustomMarker();
}
void _loadCustomMarker() async {
customIcon = await BitmapDescriptor.fromAssetImage(
ImageConfiguration(size: Size(48, 48)),
'assets/custom_marker.png',
);
}
void _onMapCreated(GoogleMapController controller) {
mapController = controller;
markers.add(
Marker(
markerId: MarkerId('customMarker'),
position: LatLng(37.7749, -122.4194),
icon: customIcon, // Use custom icon
infoWindow: InfoWindow(
title: 'Custom Location',
snippet: 'Using a custom marker icon',
),
),
);
setState(() {});
}

Step 7: Adding User Location

To show the user’s current location, ensure that both myLocationEnabled and myLocationButtonEnabled are set to true:

GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: initialPosition,
markers: markers,
myLocationEnabled: true,
myLocationButtonEnabled: true,
)

Permissions (Android)

For Android, add the following permissions in android/app/src/main/AndroidManifest.xml:

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

For Flutter, consider using the permission_handler package to request location permissions.

Step 8: Updating Camera Position

To navigate the map camera to a different location, use the animateCamera method:

void _moveToPosition(LatLng position) {
mapController.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(target: position, zoom: 14),
),
);
}

Step 9: Implementing Routing with Google Maps

To add routing, we’ll integrate the Google Directions API. This API calculates routes and provides detailed turn-by-turn directions.

Step 9.1: Enable the Directions API

  1. Go to Google Cloud Console.
  2. Under APIs & Services > Library, enable the Directions API for your project.

Step 9.2: Request Directions

To get directions between two points, you’ll make an HTTP request to the Directions API. We’ll use the http package to make this request.

Add http to pubspec.yaml:

dependencies:
http: ^0.13.3

Run:

flutter pub get

Step 9.3: Write the Code for Route Calculation

In google_map_screen.dart, import http and define a function that fetches route information:

import 'package:http/http.dart' as http;
import 'dart:convert';
// Function to get directions from Google Directions API
Future<void> _getRoute(LatLng origin, LatLng destination) async {
final String apiKey = 'YOUR_API_KEY';
final String url = 'https://maps.googleapis.com/maps/api/directions/json?origin=${origin.latitude},${origin.longitude}&destination=${destination.latitude},${destination.longitude}&key=$apiKey';
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
final Map<String, dynamic> data = json.decode(response.body);
if (data['routes'].isNotEmpty) {
// Extract polyline
final String encodedPolyline = data['routes'][0]['overview_polyline']['points'];
_decodePolyline(encodedPolyline);
}
} else {
print('Failed to fetch route: ${response.reasonPhrase}');
}
}

The overview_polyline gives the route’s encoded polyline, which represents the path between the origin and destination.

Step 9.4: Decode and Display the Polyline on the Map

The polyline must be decoded to use it on the map. Add this function to decode it:

List<LatLng> _decodePolyline(String polyline) {
List<LatLng> points = [];
int index = 0, len = polyline.length;
int lat = 0, lng = 0;
while (index < len) {
int b, shift = 0, result = 0;
do {
b = polyline.codeUnitAt(index++) - 63;
result |= (b & 0x1F) << shift;
shift += 5;
} while (b >= 0x20);
int dlat = (result & 1) != 0 ? ~(result >> 1) : (result >> 1);
lat += dlat;
shift = 0;
result = 0;
do {
b = polyline.codeUnitAt(index++) - 63;
result |= (b & 0x1F) << shift;
shift += 5;
} while (b >= 0x20);
int dlng = (result & 1) != 0 ? ~(result >> 1) : (result >> 1);
lng += dlng;
points.add(LatLng(lat / 1E5, lng / 1E5));
}
return points;
}
void _showRoute(List<LatLng> points) {
final Polyline routePolyline = Polyline(
polylineId: PolylineId('route'),
color: Colors.blue,
width: 5,
points: points,
);
setState(() {
_polylines.add(routePolyline);
});
}

After decoding, call _showRoute to display the route as a polyline on the map. Call _getRoute when you want to calculate and display the route.

Add the _polylines set in your class:

final Set<Polyline> _polylines = {};

And update GoogleMap widget to use _polylines:

GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: initialPosition,
markers: markers,
polylines: _polylines,
myLocationEnabled: true,
zoomControlsEnabled: true,
)

Step 10: Adding Real-Time Tracking

Tracking shows the user’s real-time location on the map and can automatically update their position.

Step 10.1: Use the geolocator Package

Add the geolocator package for accessing location services:

dependencies:
geolocator: ^9.0.2

Run:

flutter pub get

Step 10.2: Configure Permissions

Configure Android and iOS permissions in android/app/src/main/AndroidManifest.xml and Info.plist for iOS. Refer to the geolocator documentation for details.

Step 10.3: Track User Location

Add the following code to listen to location changes and update the map’s camera:

import 'package:geolocator/geolocator.dart';
void _startTracking() async {
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
await Geolocator.openLocationSettings();
return;
}
LocationPermission permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
return;
}
}
Geolocator.getPositionStream(
locationSettings: const LocationSettings(
accuracy: LocationAccuracy.high,
distanceFilter: 10,
),
).listen((Position position) {
LatLng newPosition = LatLng(position.latitude, position.longitude);
mapController.animateCamera(
CameraUpdate.newLatLng(newPosition),
);
setState(() {
markers.add(
Marker(
markerId: MarkerId('userLocation'),
position: newPosition,
infoWindow: InfoWindow(title: 'You are here'),
),
);
});
});
}

Call _startTracking() in initState to start tracking as soon as the screen loads.

Full Code for google_map_screen.dart

Here’s the complete code for google_map_screen.dart:

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class GoogleMapScreen extends StatefulWidget {
@override
_GoogleMapScreenState createState() => _GoogleMapScreenState();
}
class _GoogleMapScreenState extends State<GoogleMapScreen> {
late GoogleMapController mapController;
final Set<Marker> markers = {};
final Set<Polyline> _polylines = {};
final CameraPosition initialPosition = CameraPosition(
target: LatLng(37.7749, -122.4194),
zoom: 10.0,
);
@override
void initState() {
super.initState();
_startTracking();
}
void _onMapCreated(GoogleMapController controller) {
mapController = controller;
}
Future<void> _getRoute(LatLng origin, LatLng destination) async {
final String apiKey = 'YOUR_API_KEY';
final String url = 'https://maps.googleapis.com/maps/api/directions/json?origin=${origin.latitude},${origin.longitude}&destination=${destination.latitude},${destination.longitude}&key=$apiKey';
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
final data = json.decode(response.body);
if (data['routes'].isNotEmpty) {
final encodedPolyline = data['routes'][0]['overview_polyline']['points'];
final points = _decodePolyline(encodedPolyline);
_showRoute(points);
}
}
}
List<LatLng> _decodePolyline(String polyline) { /*...*/ } void _showRoute(List<LatLng> points) {
final Polyline routePolyline = Polyline(
polylineId: PolylineId('route'),
color: Colors.blue,
width: 5,
points: points,
);
setState(() {
_polylines.add(routePolyline);
});
}
void _startTracking() { /*...*/ } @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Routing & Tracking')),
body: GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: initialPosition,
markers: markers,
polylines: _polylines,
myLocationEnabled: true,
zoomControlsEnabled: true,
),
);
}
}

--

--

Yawar Osman
Yawar Osman

Written by Yawar Osman

Project Manager || Software Developer || Team Leader || Flutter Developer

No responses yet