Adding Google Maps to a Flutter app
1. Introduction
Flutter is Google's mobile app SDK for crafting high-quality native experiences on iOS and Android in record time.
With theGoogle Maps Flutter plugin, you can add maps based on Google maps data to your application. The plugin automatically handles access to the Google Maps servers, map display, and response to user gestures such as clicks and drags. You can also add markers to your map. These objects provide additional information for map locations, and allow the user to interact with the map.
What you'll build
In this codelab, you'll build a mobile app featuring a Google Map using the Flutter SDK. Your app will:
|
|
What is Flutter?
Flutter has three core capabilities.
- Fast to develop: Build your Android and iOS applications in milliseconds with Stateful Hot Reload.
- Expressive and flexible: Quickly ship features with a focus on native end-user experiences.
- Native performance on both iOS and Android: Flutter's widgets incorporate all critical platform differences — such as scrolling, navigation, icons, and fonts — to provide full native performance.
Google Maps has:
- 99% coverage of the world: Build with reliable, comprehensive data for over 200 countries and territories.
- 25 million updates daily: Count on accurate, real-time location information.
- 1 billion monthly active users: Scale confidently, backed by Google Maps' infrastructure.
This codelab walks you through creating a Google Maps experience in a Flutter app for both iOS and Android.
What you'll learn
- How to create a new Flutter application.
- How to configure a Google Maps Flutter plugin.
- How to add Markers to a map, using location data from a web service.
This codelab focuses on adding a Google map to a Flutter app. Non-relevant concepts and code blocks are glossed over and are provided for you to simply copy and paste.
What would you like to learn from this codelab?
2. Set up your Flutter environment
You need two pieces of software to complete this lab: theFlutter SDK, andan editor. This codelab assumes Android Studio, but you can use your preferred editor.
You can run this codelab using any of the following devices:
- A physical device (Android or iOS) connected to your computer and set to developer mode.
- The iOS simulator. (Requiresinstalling Xcode tools.)
- The Android emulator. (Requires setup inAndroid Studio.)
3. Getting started
Getting started with Flutter
The easiest way to get started with Flutter is to use the flutter command line tool to create all the required code for a simple getting started experience.
$ flutter create google_maps_in_flutter --platforms android,ios,webCreating project google_maps_in_flutter...Resolving dependencies in `google_maps_in_flutter`... Downloading packages... Got dependencies in `google_maps_in_flutter`.Wrote 81 files.All done!You can find general documentation for Flutter at: https://docs.flutter.dev/Detailed API documentation is available at: https://api.flutter.dev/If you prefer video documentation, consider: https://www.youtube.com/c/flutterdevIn order to run your application, type: $ cd google_maps_in_flutter $ flutter runYour application code is in google_maps_in_flutter/lib/main.dart.
Adding Google Maps Flutter plugin as a dependency
Adding additional capability to a Flutter app is easy usingPub packages. In this codelab you introduce theGoogle Maps Flutter plugin by running the following command from the project directory.
$ cd google_maps_in_flutter$ flutter pub add google_maps_flutterResolving dependencies... Downloading packages... + csslib 1.0.0+ flutter_plugin_android_lifecycle 2.0.19+ flutter_web_plugins 0.0.0 from sdk flutter+ google_maps 7.1.0+ google_maps_flutter 2.6.1+ google_maps_flutter_android 2.8.0+ google_maps_flutter_ios 2.6.0+ google_maps_flutter_platform_interface 2.6.0+ google_maps_flutter_web 0.5.7+ html 0.15.4+ js 0.6.7 (0.7.1 available)+ js_wrapping 0.7.4 leak_tracker 10.0.4 (10.0.5 available) leak_tracker_flutter_testing 3.0.3 (3.0.5 available) material_color_utilities 0.8.0 (0.11.1 available) meta 1.12.0 (1.14.0 available)+ plugin_platform_interface 2.1.8+ sanitize_html 2.1.0+ stream_transform 2.1.0 test_api 0.7.0 (0.7.1 available)+ web 0.5.1Changed 16 dependencies!6 packages have newer versions incompatible with dependency constraints.Try `flutter pub outdated` for more information.
Configuring iOSplatform
To get the latest version of the Google Maps SDK on iOSrequires a platform minimum version of iOS 14. Modify the top of theios/Podfile configuration file as follows.
ios/Podfile
#GoogleMapsSDKrequiresplatformversion14#https://developers.google.com/maps/flutter-package/config#iosplatform:ios,'14.0'#CocoaPodsanalyticssendsnetworkstatssynchronouslyaffectingflutterbuildlatency.ENV['COCOAPODS_DISABLE_STATS']='true'Configuring AndroidminSDK
To use Google Maps SDK onAndroid requires setting theminSdk to 21. Modify theandroid/app/build.gradle configuration file as follows.
android/app/build.gradle
android{defaultConfig{// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).applicationId="com.example.google_maps_in_flutter"// Minimum Android version for Google Maps SDK// https://developers.google.com/maps/flutter-package/config#androidminSdk=21targetSdk=flutter.targetSdkVersionversionCode=flutterVersionCode.toInteger()versionName=flutterVersionName}}4. Adding Google Maps to the app
It's all about the API keys
To use Google Maps in your Flutter app, you need to configure an API project with theGoogle Maps Platform, following theMaps SDK for Android's Using API key,Maps SDK for iOS' Using API key, andMaps JavaScript API's Using API key. With API keys in hand, carry out the following steps to configure both Android and iOS applications.
Adding an API key for an Android app
To add an API key to the Android app, edit theAndroidManifest.xml file inandroid/app/src/main. Add a singlemeta-data entry containing the API key created in the previous step inside theapplication node.
android/app/src/main/AndroidManifest.xml
<manifestxmlns:android="http://schemas.android.com/apk/res/android"><applicationandroid:label="google_maps_in_flutter"android:name="${applicationName}"android:icon="@mipmap/ic_launcher"><!--TODO:AddyourGoogleMapsAPIkeyhere--><meta-dataandroid:name="com.google.android.geo.API_KEY"android:value="YOUR-KEY-HERE"/><activityandroid:name=".MainActivity"android:exported="true"android:launchMode="singleTop"android:taskAffinity=""android:theme="@style/LaunchTheme"android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"android:hardwareAccelerated="true"android:windowSoftInputMode="adjustResize"><!--SpecifiesanAndroidthemetoapplytothisActivityassoonastheAndroidprocesshasstarted.ThisthemeisvisibletotheuserwhiletheFlutterUIinitializes.Afterthat,thisthemecontinuestodeterminetheWindowbackgroundbehindtheFlutterUI.--><meta-dataandroid:name="io.flutter.embedding.android.NormalTheme"android:resource="@style/NormalTheme"/><intent-filter><actionandroid:name="android.intent.action.MAIN"/><categoryandroid:name="android.intent.category.LAUNCHER"/></intent-filter></activity><!--Don't delete the meta-data below.ThisisusedbytheFluttertooltogenerateGeneratedPluginRegistrant.java--><meta-dataandroid:name="flutterEmbedding"android:value="2"/></application><!--Requiredtoqueryactivitiesthatcanprocesstext,see:https://developer.android.com/training/package-visibilityandhttps://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.Inparticular,thisisusedbytheFlutterengineinio.flutter.plugin.text.ProcessTextPlugin.--><queries><intent><actionandroid:name="android.intent.action.PROCESS_TEXT"/><dataandroid:mimeType="text/plain"/></intent></queries></manifest>Adding an API key for an iOS app
To add an API key to the iOS app, edit theAppDelegate.swift file inios/Runner. Unlike Android, adding an API key on iOS requires changes to the source code of the Runner app. The AppDelegate is the core singleton that is part of the app initialization process.
Make two changes to this file. First, add an#import statement to pull in the Google Maps headers, and then call theprovideAPIKey() method of theGMSServices singleton. This API key enables Google Maps to correctly serve map tiles.
ios/Runner/AppDelegate.swift
importFlutterimportUIKitimportGoogleMaps//Addthisimport@UIApplicationMain@objcclassAppDelegate:FlutterAppDelegate{overridefuncapplication(_application:UIApplication,didFinishLaunchingWithOptionslaunchOptions:[UIApplication.LaunchOptionsKey:Any]?)->Bool{GeneratedPluginRegistrant.register(with:self)//TODO:AddyourGoogleMapsAPIkeyGMSServices.provideAPIKey("YOUR-API-KEY")//Addthislinereturnsuper.application(application,didFinishLaunchingWithOptions:launchOptions)}}Adding an API key for a Web app
To add an API key to the Web app, edit theindex.html file inweb. Add a reference to the Maps JavaScript script in the head section, with your API key.
web/index.html
<!DOCTYPE html><html><head><!--Ifyouareservingyourwebappinapathotherthantheroot,changethehrefvaluebelowtoreflectthebasepathyouareservingfrom.Thepathprovidedbelowhastostartandendwithaslash"/"inorderforittoworkcorrectly.Formoredetails:*https://developer.mozilla.org/en-US/docs/Web/HTML/Element/baseThisisaplaceholderforbasehrefthatwillbereplacedbythevalueofthe`--base-href`argumentprovidedto`flutterbuild`.--><basehref="$FLUTTER_BASE_HREF"><metacharset="UTF-8"><metacontent="IE=Edge"http-equiv="X-UA-Compatible"><metaname="description"content="A new Flutter project."><!--iOSmetatags &icons--><metaname="apple-mobile-web-app-capable"content="yes"><metaname="apple-mobile-web-app-status-bar-style"content="black"><metaname="apple-mobile-web-app-title"content="google_maps_in_flutter"><linkrel="apple-touch-icon"href="icons/Icon-192.png"><!--Favicon--><linkrel="icon"type="image/png"href="favicon.png"/><!--AddyourGoogleMapsAPIkeyhere--><scriptsrc="https://maps.googleapis.com/maps/api/js?key=YOUR-KEY-HERE"></script><title>google_maps_in_flutter</title><linkrel="manifest"href="manifest.json"></head><body><scriptsrc="flutter_bootstrap.js"async></script></body></html>Putting a map on the screen
Now it's time to get a map on the screen. Replace the contents oflib/main.dart with the following.
lib/main.dart
import'package:flutter/material.dart';import'package:google_maps_flutter/google_maps_flutter.dart';voidmain(){runApp(constMyApp());}classMyAppextendsStatefulWidget{constMyApp({super.key});@overrideState<MyApp>createState()=>_MyAppState();}class_MyAppStateextendsState<MyApp>{lateGoogleMapControllermapController;finalLatLng_center=constLatLng(45.521563,-122.677433);void_onMapCreated(GoogleMapControllercontroller){mapController=controller;}@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(theme:ThemeData(useMaterial3:true,colorSchemeSeed:Colors.green[700],),home:Scaffold(appBar:AppBar(title:constText('Maps Sample App'),elevation:2,),body:GoogleMap(onMapCreated:_onMapCreated,initialCameraPosition:CameraPosition(target:_center,zoom:11.0,),),),);}}Running the app
Run the Flutter app in either iOS or Android to see a single map view, centered on Portland. Alternatively, run up either an Android emulator or an iOS simulator. Feel free to modify the map center to represent your hometown, or somewhere that is important to you.
$ flutter run
|
|
5. Put Google on the Map
Google has many offices around the world, fromNorth America,Latin America,Europe,Asia Pacific, toAfrica & Middle East. The nice thing about these maps, if you investigate them, is that they have an easily usableAPI endpoint for supplying the office location information in JSON format. In this step, you put these office locations on the map. In this step, you will use code generation to parse JSON.
Add three new Flutter dependencies to the project as follows. Add thehttp package for making HTTP requests easily, thejson_serializable andjson_annotation for declaring object structure for representing JSON documents, addbuild_runner for code generation support.
$ flutter pub add http json_annotation json_serializable dev:build_runnerResolving dependencies... Downloading packages... + _fe_analyzer_shared 67.0.0 (68.0.0 available)+ analyzer 6.4.1 (6.5.0 available)+ args 2.5.0+ build 2.4.1+ build_config 1.1.1+ build_daemon 4.0.1+ build_resolvers 2.4.2+ build_runner 2.4.9+ build_runner_core 7.3.0+ built_collection 5.1.1+ built_value 8.9.2+ checked_yaml 2.0.3+ code_builder 4.10.0+ convert 3.1.1+ crypto 3.0.3+ dart_style 2.3.6+ file 7.0.0+ fixnum 1.1.0+ frontend_server_client 4.0.0+ glob 2.1.2+ graphs 2.3.1+ http 1.2.1+ http_multi_server 3.2.1+ http_parser 4.0.2+ io 1.0.4 js 0.6.7 (0.7.1 available)+ json_annotation 4.9.0+ json_serializable 6.8.0 leak_tracker 10.0.4 (10.0.5 available) leak_tracker_flutter_testing 3.0.3 (3.0.5 available)+ logging 1.2.0 material_color_utilities 0.8.0 (0.11.1 available) meta 1.12.0 (1.14.0 available)+ mime 1.0.5+ package_config 2.1.0+ pool 1.5.1+ pub_semver 2.1.4+ pubspec_parse 1.2.3+ shelf 1.4.1+ shelf_web_socket 1.0.4+ source_gen 1.5.0+ source_helper 1.3.4 test_api 0.7.0 (0.7.1 available)+ timing 1.0.1+ typed_data 1.3.2+ watcher 1.1.0+ web_socket_channel 2.4.5+ yaml 3.1.2Changed 42 dependencies!8 packages have newer versions incompatible with dependency constraints.Try `flutter pub outdated` for more information.
Parsing JSON with code generation
You might have noticed that the JSON data returned from the API endpoint has a regular structure. It would be handy to generate the code to marshal that data into objects that you can use in code.
In thelib/src directory, create alocations.dart file and describe the structure of the returned JSON data as follows:
lib/src/locations.dart
import'dart:convert';import'package:flutter/foundation.dart';import'package:flutter/services.dart'showrootBundle;import'package:http/http.dart'ashttp;import'package:json_annotation/json_annotation.dart';part'locations.g.dart';@JsonSerializable()classLatLng{LatLng({requiredthis.lat,requiredthis.lng,});factoryLatLng.fromJson(Map<String,dynamic>json)=>_$LatLngFromJson(json);Map<String,dynamic>toJson()=>_$LatLngToJson(this);finaldoublelat;finaldoublelng;}@JsonSerializable()classRegion{Region({requiredthis.coords,requiredthis.id,requiredthis.name,requiredthis.zoom,});factoryRegion.fromJson(Map<String,dynamic>json)=>_$RegionFromJson(json);Map<String,dynamic>toJson()=>_$RegionToJson(this);finalLatLngcoords;finalStringid;finalStringname;finaldoublezoom;}@JsonSerializable()classOffice{Office({requiredthis.address,requiredthis.id,requiredthis.image,requiredthis.lat,requiredthis.lng,requiredthis.name,requiredthis.phone,requiredthis.region,});factoryOffice.fromJson(Map<String,dynamic>json)=>_$OfficeFromJson(json);Map<String,dynamic>toJson()=>_$OfficeToJson(this);finalStringaddress;finalStringid;finalStringimage;finaldoublelat;finaldoublelng;finalStringname;finalStringphone;finalStringregion;}@JsonSerializable()classLocations{Locations({requiredthis.offices,requiredthis.regions,});factoryLocations.fromJson(Map<String,dynamic>json)=>_$LocationsFromJson(json);Map<String,dynamic>toJson()=>_$LocationsToJson(this);finalList<Office>offices;finalList<Region>regions;}Future<Locations>getGoogleOffices()async{constgoogleLocationsURL='https://about.google/static/data/locations.json';//RetrievethelocationsofGoogleofficestry{finalresponse=awaithttp.get(Uri.parse(googleLocationsURL));if(response.statusCode==200){returnLocations.fromJson(json.decode(response.body)asMap<String,dynamic>);}}catch(e){if(kDebugMode){print(e);}}//FallbackforwhentheaboveHTTPrequestfails.returnLocations.fromJson(json.decode(awaitrootBundle.loadString('assets/locations.json'),)asMap<String,dynamic>,);}Once you've added this code, your IDE (if you are using one) should display some red squiggles, as it references a nonexistent sibling file,locations.g.dart. This generated file converts between untyped JSON structures and named objects. Create it by runningbuild_runner as follows:
$ dart run build_runner build --delete-conflicting-outputs[INFO] Generating build script...[INFO] Generating build script completed, took 357ms[INFO] Creating build script snapshot......[INFO] Creating build script snapshot... completed, took 10.5s[INFO] There was output on stdout while compiling the build script snapshot, run with `--verbose` to see it (you will need to run a `clean` first to re-snapshot).[INFO] Initializing inputs[INFO] Building new asset graph...[INFO] Building new asset graph completed, took 646ms[INFO] Checking for unexpected pre-existing outputs....[INFO] Deleting 1 declared outputs which already existed on disk.[INFO] Checking for unexpected pre-existing outputs. completed, took 3ms[INFO] Running build...[INFO] Generating SDK summary...[INFO] 3.4s elapsed, 0/3 actions completed.[INFO] Generating SDK summary completed, took 3.4s[INFO] 4.7s elapsed, 2/3 actions completed.[INFO] Running build completed, took 4.7s[INFO] Caching finalized dependency graph...[INFO] Caching finalized dependency graph completed, took 36ms[INFO] Succeeded after 4.8s with 2 outputs (7 actions)
Your code should now analyze cleanly again. Next, we should add in the fallback locations.json file used in thegetGoogleOffices function. One of the reasons for including this fallback is that the static data being loaded in this function is served without CORS headers, and thus will fail to load in a web browser. The Android and iOS Flutter apps don't need CORS headers, but mobile data access can be finicky at the best of times.
Navigate tohttps://about.google/static/data/locations.json in your browser, and save the contents into the asset directory. Alternatively, you can use the command line as follows.
$ mkdir assets$ cd assets$ curl -o locations.json https://about.google/static/data/locations.json % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed100 30348 100 30348 0 0 75492 0 --:--:-- --:--:-- --:--:-- 75492
Now that you have the asset file downloaded, add it to the flutter section of yourpubspec.yaml file.
pubspec.yaml
flutter:uses-material-design:trueassets:-assets/locations.jsonModify themain.dart file to request the map data, and then use the returned info to add offices to the map:
lib/main.dart
import'package:flutter/material.dart';import'package:google_maps_flutter/google_maps_flutter.dart';import'src/locations.dart'aslocations;voidmain(){runApp(constMyApp());}classMyAppextendsStatefulWidget{constMyApp({super.key});@overrideState<MyApp>createState()=>_MyAppState();}class_MyAppStateextendsState<MyApp>{finalMap<String,Marker>_markers={};Future<void>_onMapCreated(GoogleMapControllercontroller)async{finalgoogleOffices=awaitlocations.getGoogleOffices();setState((){_markers.clear();for(finalofficeingoogleOffices.offices){finalmarker=Marker(markerId:MarkerId(office.name),position:LatLng(office.lat,office.lng),infoWindow:InfoWindow(title:office.name,snippet:office.address,),);_markers[office.name]=marker;}});}@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(theme:ThemeData(useMaterial3:true,colorSchemeSeed:Colors.green[700],),home:Scaffold(appBar:AppBar(title:constText('Google Office Locations'),elevation:2,),body:GoogleMap(onMapCreated:_onMapCreated,initialCameraPosition:constCameraPosition(target:LatLng(0,0),zoom:2,),markers:_markers.values.toSet(),),),);}}This code performs several operations:
- In
_onMapCreated, it uses the JSON parsing code from the previous step,awaiting until it's loaded. It then uses the returned data to createMarkers inside asetState()callback. Once the app receives new markers, setState flags Flutter to repaint the screen, causing the office locations to display. - The markers are stored in a
Mapthat is associated with theGoogleMapwidget. This links the markers to the correct map. You could, of course, have multiple maps and display different markers in each.

Here's a screenshot of what you have accomplished. There are many interesting additions that can be made at this point. For example, you could add a list view of the offices that moves and zooms the map when the user clicks an office but, as they say, this exercise is left to the reader!
6. Next steps
Congratulations!
You have completed the codelab and have built a Flutter app with a Google Map! You've also interacted with a JSON Web Service.
Other next steps
This codelab has built an experience to visualise a number of points on a map. There are a number of mobile apps that build on this capability to serve a lot of different user needs. There are other resources that can help you take this further:
- Build Mobile Apps With Flutter and Google Maps (a talk given at Cloud Next ‘19)
- Hadrien Lejard's
google_maps_webservicepackage which makes the Google Maps Web Services, likeDirections API,Distance Matrix API, andPlaces API really easy to use. - If you want to look at different options for using an API via JSON REST, seeAndrew Brogdon's Medium post for a range of options for working with JSON REST APIs.
Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

