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
- Set the
minSdkVersion
inandroid/app/build.gradle
:
android {
defaultConfig {
minSdkVersion 20
}
}
This means that app will only be available for users that run Android SDK 20 or higher.
- 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.<!-- Add your Google Maps 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 theapplication
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
- Download the code below.
- Obtain and add your API Key.
- Build and Run
Reference
Find the donwload link below:
Number | Link |
---|---|
1. | Download Example |
2. | Follow code author |