Flutter — Location & Permissions
Showing the user's own position on the map takes two objects working together: PermissionManager (requests/checks OS location permission) and the location methods on MapController (actually show/track the puck). Neither works alone — enableLocation() will fail if permission hasn't been granted, and granting permission does nothing to the map by itself.
PermissionManager cannot be used on web.
PermissionManager
abstract interface class PermissionManager {
factory PermissionManager();
bool get backgroundLocationPermissionGranted;
bool get locationPermissionsGranted;
bool get runtimePermissionsRequired;
Future<bool> requestLocationPermissions({required String explanation});
}| Member | Description |
|---|---|
locationPermissionsGranted | true if either coarse or fine location access is currently granted. |
backgroundLocationPermissionGranted | true if background location access is granted. |
runtimePermissionsRequired | true if the OS requires asking for location permission at runtime (i.e. Android 6+/iOS, as opposed to permissions declared only at install time). |
requestLocationPermissions({required String explanation}) | Triggers the OS permission prompt (using explanation where the platform surfaces a rationale string) and resolves to whether it was granted. |
Construct it with the plain factory constructor — no arguments:
final permissionManager = PermissionManager();Platform permission declarations
Android
<!-- android/app/src/main/AndroidManifest.xml -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>iOS
<!-- ios/Runner/Info.plist -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs your location to display your location on the map.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app requires access to your location.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app requires access to your location.</string>Without these declarations the runtime permission prompt will not appear (Android) or the app will crash when requesting location (iOS).
Wiring it together
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';
class UserLocationPage extends StatefulWidget {
const UserLocationPage({super.key});
@override
State<UserLocationPage> createState() => _UserLocationPageState();
}
class _UserLocationPageState extends State<UserLocationPage> {
final _permissionManager = PermissionManager();
MapController? _controller;
Future<void> _showMyLocation() async {
final granted = await _permissionManager.requestLocationPermissions(
explanation: 'Show your location on the map.',
);
if (!granted || _controller == null) return;
await _controller!.enableLocation();
await _controller!.trackLocation(trackBearing: BearingTrackMode.gps);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('User Location')),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(8),
child: OutlinedButton(
onPressed: _showMyLocation,
child: const Text('Show my location'),
),
),
Expanded(
child: MapMetricsView(
options: MapOptions(
initCenter: Position(-74.006, 40.7128), // New York: lng, lat
initZoom: 9,
),
onMapCreated: (controller) => _controller = controller,
),
),
],
),
);
}
}Checking permission state without prompting
Read the getters directly to reflect current state in your UI (e.g. to decide whether to show a "request permission" button at all):
final manager = PermissionManager();
if (!manager.locationPermissionsGranted) {
// show a prompt / explainer before calling requestLocationPermissions
}Related MapController methods
Once permission is granted, these live on MapController (full reference: MapController — User location):
enableLocation({...})— start showing the location pucktrackLocation({trackLocation, trackBearing})— re-center the camera on the user as it movesshowUserLocationPuck({show})— toggle puck visibilitysetLocationDraggable({draggable})— allow the user to drag the puck to a new positionsetNavigationRoute(List<Position>)/clearNavigationRoute()— snap the puck to a route line while navigating
See also
- MapController reference — full method signatures
- Getting Started — platform setup for a first map