Maps, Location & Device Features

Introduction to google_maps_flutter

15 min Lesson 1 of 12

Introduction to google_maps_flutter

The google_maps_flutter package is the official Flutter plugin for embedding Google Maps into Android and iOS applications. It provides a GoogleMap widget that wraps the native Google Maps SDK on each platform, giving you full access to markers, polylines, polygons, camera controls, and map type switching — all through a declarative Flutter API.

In this lesson you will add the package to a project, configure the required API keys for both platforms, and render your first interactive map with a fixed initial camera position.

Note: google_maps_flutter requires a valid Google Maps API key with the Maps SDK for Android and Maps SDK for iOS APIs enabled in the Google Cloud Console. Without a key the map will render as a grey grid.

Step 1 — Adding the Package

Open your project's pubspec.yaml and add the dependency under dependencies:

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  google_maps_flutter: ^2.9.0

After saving, run flutter pub get to fetch the package. The plugin automatically links the native Google Maps SDK on both Android and iOS through Flutter's plugin system — no manual Gradle or CocoaPods edits are needed for the plugin itself, only the API-key configuration below.

Step 2 — Configuring the Android API Key

Open android/app/src/main/AndroidManifest.xml and add a <meta-data> element inside the <application> tag:

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <application
      android:label="my_app"
      android:icon="@mipmap/ic_launcher">

    <!-- Google Maps API key -->
    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="YOUR_ANDROID_API_KEY"/>

    <activity ... />
  </application>
</manifest>
Warning: Never hard-code your production API key directly in version-controlled source files. Use a local.properties file (already in .gitignore) or environment injection via a CI/CD pipeline. The placeholder above is fine for development but must be secured before shipping.

Also ensure the minimum SDK version in android/app/build.gradle is at least 21:

android/app/build.gradle

android {
    defaultConfig {
        minSdkVersion 21   // google_maps_flutter requires API 21+
        targetSdkVersion 34
    }
}

Step 3 — Configuring the iOS API Key

Open ios/Runner/AppDelegate.swift and call GMSServices.provideAPIKey before the Flutter engine starts:

ios/Runner/AppDelegate.swift

import UIKit
import Flutter
import GoogleMaps   // 1. Import the SDK

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    // 2. Provide the API key before GeneratedPluginRegistrant
    GMSServices.provideAPIKey("YOUR_IOS_API_KEY")

    GeneratedPluginRegistrant.register(with: self)
    return super.application(application,
                             didFinishLaunchingWithOptions: launchOptions)
  }
}
Tip: If your project uses Objective-C instead of Swift, call [GMSServices provideAPIKey:@"YOUR_IOS_API_KEY"] in AppDelegate.m before [GeneratedPluginRegistrant registerWithRegistry:self].

Then run cd ios && pod install (or flutter pub get which triggers pod install automatically on first run) so that CocoaPods links the GoogleMaps framework.

Step 4 — Rendering a Basic GoogleMap Widget

With the package added and keys configured, you can now embed a map anywhere in your widget tree. The GoogleMap widget requires one mandatory parameter: initialCameraPosition. A CameraPosition needs at minimum a LatLng target and a zoom level.

Basic GoogleMap widget

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

class MapScreen extends StatefulWidget {
  const MapScreen({super.key});

  @override
  State<MapScreen> createState() => _MapScreenState();
}

class _MapScreenState extends State<MapScreen> {
  // Optional: keep a reference to animate the camera later
  GoogleMapController? _controller;

  static const CameraPosition _initialPosition = CameraPosition(
    target: LatLng(24.7136, 46.6753), // Riyadh, Saudi Arabia
    zoom: 12.0,
  );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Map')),
      body: GoogleMap(
        initialCameraPosition: _initialPosition,
        onMapCreated: (GoogleMapController controller) {
          _controller = controller;
        },
        myLocationButtonEnabled: false,
        zoomControlsEnabled: true,
      ),
    );
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }
}

Key points from the code above:

  • initialCameraPosition — mandatory; sets where the camera is aimed when the map first loads.
  • onMapCreated — callback that fires once the underlying native map is ready; use it to store the GoogleMapController for later camera animations.
  • GoogleMapController.dispose() — must be called in dispose() to free the native map resources and avoid memory leaks.
  • myLocationButtonEnabled: false — disables the blue dot and button until you request the location permission (covered in a later lesson).

Zoom Levels Reference

The zoom property of CameraPosition follows Google Maps' standard scale:

  • 1 — World view
  • 5 — Continent / large country
  • 10 — City
  • 15 — Streets
  • 20 — Buildings / individual blocks
Tip: You can also specify a bearing (rotation in degrees, 0 = North) and tilt (0–90 degrees) in CameraPosition for a perspective view. For most use-cases the defaults (bearing: 0, tilt: 0) are fine.

Summary

In this lesson you learned how to:

  • Add google_maps_flutter to pubspec.yaml and run flutter pub get.
  • Register the Maps API key in AndroidManifest.xml for Android.
  • Call GMSServices.provideAPIKey in AppDelegate.swift for iOS.
  • Render a GoogleMap widget with a fixed CameraPosition.
  • Store a GoogleMapController and dispose it correctly to avoid memory leaks.
Next up: In the following lessons you will add markers, handle user taps on the map, and animate the camera programmatically to build richer location-aware experiences.