Google Maps with Current Location in Flutter: Complete Tutorial (2026)
Last Updated: | Author: Deep Singh
If you're building an app that needs to show maps — like a delivery tracker, a store locator, or a ride-sharing service — you'll almost certainly need to display the user's current location on a Google Map. In this tutorial, I'll show you exactly how to do that in Flutter.
We'll cover setting up the plugin, handling permissions, showing live location updates, adding markers, and switching between map types. By the end, you'll have a fully working map that follows the user as they move.
Before You Start
Make sure you have the following ready:
- Flutter SDK installed (use the latest stable version for best compatibility)
- Android Studio or VS Code with the Flutter plugin
- A Google Cloud account with the Maps SDK for Android and Maps SDK for iOS enabled
- An API key from the Google Cloud Console
- A physical device or emulator with location services enabled
Important: You must add your Google Maps API key to your Android and iOS project files, or the map will show up blank. If you're not sure how to do that, check Google's official documentation for Android and iOS.
Setting Up Google Maps in Your Flutter Project
Before writing any Dart code, you need to configure the native side of your app. Here's a quick checklist:
- Android: Add your API key to
android/app/src/main/AndroidManifest.xmlinside the<application>tag. - Android: Make sure your
minSdkVersionis at least 21 inandroid/app/build.gradle. - iOS: Add your API key to
ios/Runner/AppDelegate.swiftand set the deployment target to at least iOS 13.0. - Both platforms: Add location permissions to your manifest and Info.plist.
Adding the Plugins
We need two plugins: one for the map itself, and one for accessing the device's location. Run these commands in your project folder:
flutter pub add google_maps_flutter
flutter pub add location
Or add them manually to your pubspec.yaml file:
dependencies:
google_maps_flutter: ^2.9.0
location: ^6.0.2
Then run flutter pub get to fetch the packages.
Note on plugin versions: The versions shown above are the current stable releases. Older tutorials may reference google_maps_flutter: ^2.0.3 and location: ^4.1.1, but those are outdated. The location plugin especially has had breaking changes — the API is different in version 6.x, so make sure you're following current documentation.
The Full Code
Here's a complete, working example. It loads Google Maps, requests location permission, and follows the user as they move. It also includes buttons to switch between normal, satellite, terrain, and hybrid map types.
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.dart';
void main() {
runApp(const MaterialApp(
home: MyGoogleMap(),
title: 'Google Map Tutorial',
));
}
class MyGoogleMap extends StatefulWidget {
const MyGoogleMap({super.key});
@override
State<MyGoogleMap> createState() => _MyGoogleMapState();
}
class _MyGoogleMapState extends State<MyGoogleMap> {
MapType _mapType = MapType.normal;
final Set<Marker> _markers = {};
final Location _location = Location();
GoogleMapController? _mapController;
LocationData? _currentLocation;
@override
void initState() {
super.initState();
_requestLocationPermission();
}
Future<void> _requestLocationPermission() async {
bool serviceEnabled = await _location.serviceEnabled();
if (!serviceEnabled) {
serviceEnabled = await _location.requestService();
if (!serviceEnabled) return;
}
PermissionStatus permissionGranted = await _location.hasPermission();
if (permissionGranted == PermissionStatus.denied) {
permissionGranted = await _location.requestPermission();
if (permissionGranted != PermissionStatus.granted) return;
}
_currentLocation = await _location.getLocation();
_startLocationUpdates();
}
void _startLocationUpdates() {
_location.onLocationChanged.listen((LocationData newLocation) {
if (_mapController == null) return;
_mapController!.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: LatLng(newLocation.latitude!, newLocation.longitude!),
zoom: 16,
),
),
);
setState(() {
_markers.clear();
_markers.add(
Marker(
markerId: const MarkerId('current_location'),
position: LatLng(newLocation.latitude!, newLocation.longitude!),
infoWindow: const InfoWindow(
title: 'You are here',
snippet: 'Your current location',
),
),
);
});
});
}
void _onMapCreated(GoogleMapController controller) {
_mapController = controller;
if (_currentLocation != null) {
_mapController!.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(
target: LatLng(
_currentLocation!.latitude!,
_currentLocation!.longitude!,
),
zoom: 16,
),
),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Google Map Tutorial'),
),
body: Stack(
children: [
GoogleMap(
initialCameraPosition: const CameraPosition(
target: LatLng(28.7041, 77.1025),
zoom: 18,
),
mapType: _mapType,
markers: _markers,
myLocationEnabled: true,
myLocationButtonEnabled: true,
onMapCreated: _onMapCreated,
onTap: (LatLng tappedPoint) {
debugPrint(
'Tapped: ${tappedPoint.latitude}, ${tappedPoint.longitude}',
);
},
),
Align(
alignment: Alignment.topRight,
child: Card(
margin: const EdgeInsets.all(8),
elevation: 10,
color: Colors.black45,
child: ButtonBar(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
tooltip: 'Normal',
onPressed: () => setState(() => _mapType = MapType.normal),
icon: const Icon(Icons.map, color: Colors.white),
),
IconButton(
tooltip: 'Satellite',
onPressed: () =>
setState(() => _mapType = MapType.satellite),
icon: const Icon(Icons.satellite_alt, color: Colors.white),
),
IconButton(
tooltip: 'Terrain',
onPressed: () => setState(() => _mapType = MapType.terrain),
icon: const Icon(Icons.terrain, color: Colors.white),
),
IconButton(
tooltip: 'Hybrid',
onPressed: () => setState(() => _mapType = MapType.hybrid),
icon: const Icon(Icons.layers, color: Colors.white),
),
],
),
),
),
],
),
);
}
@override
void dispose() {
_mapController?.dispose();
super.dispose();
}
}
How the Code Works
Let's break down the important parts so you understand what's happening:
1. Requesting Location Permission
Before we can get the user's location, we need to ask for permission. The _requestLocationPermission() method checks whether location services are enabled and whether the user has granted permission. If not, it asks. This is required on both Android and iOS.
2. Listening to Location Updates
The location.onLocationChanged stream fires every time the device's location changes. Inside the listener, we move the camera to the new coordinates and update the marker. This is what makes the map "follow" the user.
3. Using myLocationEnabled
Setting myLocationEnabled: true on the GoogleMap widget shows the familiar blue dot that represents the user's location. Combined with the marker we add manually, users get both a visual indicator and a pin they can tap for details.
4. Disposing the Controller
In dispose(), we clean up the GoogleMapController. This is a small but important step that prevents memory leaks when the user leaves the screen.
5. Switching Map Types
The buttons in the top-right corner let the user switch between normal, satellite, terrain, and hybrid views. Each button simply calls setState() to update the _mapType variable, and the map rebuilds with the new style.
Wrapping Up
You now have a working Google Map in your Flutter app that shows the user's current location and follows them as they move. This is the foundation for all kinds of location-based features — ride tracking, delivery updates, nearby search, and more.
A few things to keep in mind as you build on this:
- Battery life: Continuous location tracking drains the battery. Consider using a lower accuracy setting or stopping updates when the app is in the background.
- Permissions: Always handle the case where the user denies permission gracefully — don't just crash or show a blank screen.
- API costs: Google Maps API calls are billed. Check the pricing page to understand your usage limits.
1 comment:
marker not working
Post a Comment