mapbox-flutter-patterns

Par mapbox · mapbox-agent-skills

Modèles d'intégration officiels pour le SDK Mapbox Maps Flutter. Couvre l'installation, la configuration des plateformes iOS/Android, la configuration du token d'accès, l'initialisation du MapWidget, le contrôle de la caméra, les annotations avec gestion des taps, la localisation de l'utilisateur et le chargement de GeoJSON. Basé sur la documentation officielle de Mapbox.

npx skills add https://github.com/mapbox/mapbox-agent-skills --skill mapbox-flutter-patterns

Modèles d'intégration Mapbox Flutter

Modèles officiels pour intégrer le SDK Mapbox Maps pour Flutter (mapbox_maps_flutter) sur iOS et Android avec Dart.

Utilisez cette skill quand :

  • Installer et configurer mapbox_maps_flutter dans une app Flutter
  • Définir le token d'accès Mapbox correctement
  • Initialiser un MapWidget avec les options caméra / style
  • Ajouter des annotations (points, cercles, lignes, polygones) et gérer les taps
  • Afficher le puck de localisation de l'utilisateur
  • Charger du GeoJSON depuis les assets de l'app
  • Résoudre les échecs de build iOS après l'ajout de Mapbox

Ressources officielles :

Web et desktop ne sont pas supportés — le SDK Flutter cible iOS et Android uniquement.


Installation et configuration

Prérequis

  • Flutter SDK 3.22.3 / Dart 3.4.4+
  • iOS : cible de déploiement 14.0 ou supérieure
  • Android : minSdk 21 ou supérieur
  • Compte Mapbox gratuit

Étape 1 : Ajouter la dépendance

# pubspec.yaml
dependencies:
  mapbox_maps_flutter: ^2.0.0
flutter pub get

Étape 2 : Relever la cible de déploiement iOS à 14.0 (requis)

C'est la cause la plus courante des échecs de build iOS après l'ajout de Mapbox. Le SDK Flutter nécessite iOS 14.0 et ne compilera pas avec la valeur par défaut de Flutter.

  1. Ouvrez ios/Runner.xcworkspace dans Xcode.

  2. Sélectionnez la cible RunnerGeneral → définissez Minimum Deployments → iOS sur 14.0.

  3. Si ios/Podfile existe, mettez également à jour la ligne platform :

    # ios/Podfile
    platform :ios, '14.0'

Vous n'avez pas besoin de vous préoccuper de CocoaPods vs Swift Package Manager — mapbox_maps_flutter supporte les deux et Flutter choisit celui pour lequel votre app est configurée.

Étape 3 : Permission de localisation iOS

Ajoutez la chaîne de description à ios/Runner/Info.plist :

<key>NSLocationWhenInUseUsageDescription</key>
<string>Show your location on the map</string>

Étape 4 : Permissions Android

Ajoutez à android/app/src/main/AndroidManifest.xml :

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Étape 5 : Configurer le token d'accès

Le modèle recommandé est de passer le token via --dart-define au moment du build/run et de le définir sur MapboxOptions avant de créer un MapWidget.

flutter run --dart-define=ACCESS_TOKEN=pk.your_token_here
// main.dart
import 'package:flutter/material.dart';
import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart';

const accessToken = String.fromEnvironment('ACCESS_TOKEN');

void main() {
  MapboxOptions.setAccessToken(accessToken);
  runApp(const MaterialApp(home: MapScreen()));
}

Ne codez jamais les tokens en dur dans le code source. Pour la CI, passez --dart-define=ACCESS_TOKEN=$MAPBOX_ACCESS_TOKEN.


Initialisation de la map

Map basique

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: MapWidget(
        key: const ValueKey('mapWidget'),
        cameraOptions: CameraOptions(
          center: Point(coordinates: Position(-122.4194, 37.7749)),
          zoom: 12,
        ),
        styleUri: MapboxStyles.STANDARD,
      ),
    );
  }
}

Récupérer le contrôleur MapboxMap

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

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

class _MapScreenState extends State<MapScreen> {
  MapboxMap? mapboxMap;

  void _onMapCreated(MapboxMap controller) {
    mapboxMap = controller;
  }

  @override
  Widget build(BuildContext context) {
    return MapWidget(
      key: const ValueKey('mapWidget'),
      onMapCreated: _onMapCreated,
      cameraOptions: CameraOptions(
        center: Point(coordinates: Position(-122.4194, 37.7749)),
        zoom: 12,
      ),
    );
  }
}

Ajouter des annotations

Utilisez mapboxMap.annotations pour créer des gestionnaires pour les annotations de point, cercle, polyline et polygone. Les gestionnaires sont de longue durée — créez-les une fois et réutilisez-les pour les mises à jour.

Annotations de point avec une image personnalisée

import 'package:flutter/services.dart' show rootBundle;

PointAnnotationManager? pointAnnotationManager;

Future<void> _addMarkers(MapboxMap mapboxMap) async {
  pointAnnotationManager = await mapboxMap.annotations.createPointAnnotationManager();

  final bytes = await rootBundle.load('assets/marker.png');
  final imageBytes = bytes.buffer.asUint8List();

  final options = <PointAnnotationOptions>[
    PointAnnotationOptions(
      geometry: Point(coordinates: Position(-122.4194, 37.7749)),
      image: imageBytes,
      iconSize: 1.2,
    ),
    PointAnnotationOptions(
      geometry: Point(coordinates: Position(-122.4094, 37.7849)),
      image: imageBytes,
    ),
  ];

  await pointAnnotationManager!.createMulti(options);
}

N'oubliez pas de déclarer l'asset dans pubspec.yaml :

flutter:
  assets:
    - assets/marker.png

Gestion des taps

Utilisez manager.tapEvents — c'est l'API actuelle. addOnPointAnnotationClickListener est dépréciée.

tapEvents retourne un Cancelable que vous sauvegardez et sur lequel vous appelez .cancel() quand le listener n'est plus nécessaire :

final Cancelable tapSubscription = pointAnnotationManager!.tapEvents(
  onTap: (annotation) {
    debugPrint('Tapped annotation ${annotation.id}');
  },
);

@override
void dispose() {
  tapSubscription.cancel();
  super.dispose();
}

Le même modèle — retournant un Cancelable — existe sur longPressEvents et dragEvents de chaque gestionnaire, et à travers les autres types d'annotations (CircleAnnotationManager.tapEvents, etc.).

Charger les annotations depuis GeoJSON

import 'dart:convert';
import 'package:flutter/services.dart' show rootBundle;

Future<void> _loadGeoJson(MapboxMap mapboxMap) async {
  final raw = await rootBundle.loadString('assets/coffee_shops.geojson');
  final geo = jsonDecode(raw) as Map<String, dynamic>;
  final features = (geo['features'] as List).cast<Map<String, dynamic>>();

  final manager = await mapboxMap.annotations.createPointAnnotationManager();
  final icon = (await rootBundle.load('assets/coffee.png')).buffer.asUint8List();

  final options = features.map((feature) {
    final coords = feature['geometry']['coordinates'] as List;
    return PointAnnotationOptions(
      geometry: Point(coordinates: Position(coords[0] as double, coords[1] as double)),
      image: icon,
    );
  }).toList();

  await manager.createMulti(options);
}

Pour des milliers de features, utilisez plutôt une couche de style (GeoJsonSource + SymbolLayer) au lieu des annotations.


Afficher la localisation de l'utilisateur

Les permissions doivent déjà être accordées (utilisez permission_handler ou similaire) avant d'activer le puck.

await mapboxMap.location.updateSettings(LocationComponentSettings(
  enabled: true,
  puckBearingEnabled: true,
  locationPuck: LocationPuck(
    locationPuck2D: DefaultLocationPuck2D(),
  ),
));

Contrôle de la caméra

// Saut instantané
await mapboxMap.setCamera(CameraOptions(
  center: Point(coordinates: Position(-80.1263, 25.7845)),
  zoom: 14,
));

// Fly-to animé
await mapboxMap.flyTo(
  CameraOptions(
    center: Point(coordinates: Position(-80.1263, 25.7845)),
    zoom: 17,
    bearing: 180,
    pitch: 30,
  ),
  MapAnimationOptions(duration: 2000),
);

Dépannage

Le build iOS échoue avec « platform is lower than deployment target »

La cible de déploiement iOS par défaut de Flutter est inférieure au minimum de Mapbox (iOS 14). Définissez Minimum Deployments → iOS sur 14.0 sur la cible Runner dans Xcode. Si le projet a un ios/Podfile, définissez également platform :ios, '14.0' et réexécutez pod install.

setAccessToken n'a pas été appelée

Si vous oubliez d'appeler MapboxOptions.setAccessToken avant de créer un MapWidget, la map se chargera avec une grille vide. Appelez-le toujours dans main() avant runApp.

Le handler de tap d'annotation ne se déclenche pas

Assurez-vous que vous utilisez manager.tapEvents(onTap: ...)addOnPointAnnotationClickListener est dépréciée. Confirmez également que le contrôleur MapboxMap est capturé via onMapCreated avant de créer le gestionnaire d'annotations.

Hot reload après un changement de permissions

iOS/Android ne relira pas les manifestes ou Info.plist sur hot reload. Redémarrez complètement l'app après modification des permissions.


Fichiers de référence

  • references/annotations.md — Modèles de cercle, polyline, polygone et recettes de source/couche GeoJSON.
  • references/platform-setup.md — Configuration iOS/Android approfondie, stratégies de token, notes de signature de release.

Ressources supplémentaires

Skills similaires