mapbox-flutter-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMapbox Flutter Integration Patterns
Mapbox Flutter 集成模式
Official patterns for integrating the Mapbox Maps SDK for Flutter (mapbox_maps_flutter) on iOS and Android with Dart.
Use this skill when:
- Installing and configuring mapbox_maps_flutter in a Flutter app
- Setting the Mapbox access token the right way
- Initializing a with camera / style options
MapWidget - Adding annotations (points, circles, lines, polygons) and handling taps
- Showing the user location puck
- Loading GeoJSON from app assets
- Troubleshooting iOS build failures after adding Mapbox
Official Resources:
Web and desktop are not supported — the Flutter SDK targets iOS and Android only.
Mapbox Maps Flutter SDK(mapbox_maps_flutter)在iOS和Android平台上的官方Dart集成方案。
适用场景:
- 在Flutter应用中安装和配置mapbox_maps_flutter
- 正确设置Mapbox访问令牌
- 结合相机/样式选项初始化
MapWidget - 添加标注(点、圆形、线条、多边形)并处理点击事件
- 显示用户定位图标
- 从应用资源中加载GeoJSON
- 解决添加Mapbox后iOS构建失败的问题
官方资源:
Web和桌面端暂不支持——该Flutter SDK仅面向iOS和Android平台。
Installation & Setup
安装与配置
Requirements
环境要求
- Flutter SDK 3.22.3 / Dart 3.4.4+
- iOS: deployment target 14.0 or higher
- Android: minSdk 21 or higher
- Free Mapbox account
- Flutter SDK 3.22.3 / Dart 3.4.4+
- iOS:部署目标版本14.0或更高
- Android:minSdk 21或更高
- 免费Mapbox账号
Step 1: Add the dependency
步骤1:添加依赖
yaml
undefinedyaml
undefinedpubspec.yaml
pubspec.yaml
dependencies:
mapbox_maps_flutter: ^2.0.0
```bash
flutter pub getdependencies:
mapbox_maps_flutter: ^2.0.0
```bash
flutter pub getStep 2: Bump the iOS deployment target to 14.0 (required)
步骤2:将iOS部署目标版本提升至14.0(必填)
This is the single most common cause of iOS build failures after adding Mapbox. The Flutter SDK requires iOS 14.0 and will not compile on the Flutter default.
-
Openin Xcode.
ios/Runner.xcworkspace -
Select the Runner target → General → set Minimum Deployments → iOS to.
14.0 -
Ifexists, update the platform line too:
ios/Podfileruby# ios/Podfile platform :ios, '14.0'
You do not need to worry about CocoaPods vs Swift Package Manager — supports both and Flutter picks whichever your app is configured for.
mapbox_maps_flutter这是添加Mapbox后iOS构建失败最常见的原因。 Flutter SDK要求最低iOS版本为14.0,无法在Flutter默认版本上编译。
-
在Xcode中打开。
ios/Runner.xcworkspace -
选择Runner目标 → 通用 → 将最低部署版本 → iOS设置为。
14.0 -
如果项目存在,同时更新其中的平台配置行:
ios/Podfileruby# ios/Podfile platform :ios, '14.0'
无需担心CocoaPods与Swift Package Manager的兼容问题——同时支持两者,Flutter会自动适配应用当前的配置。
mapbox_maps_flutterStep 3: iOS location permission
步骤3:iOS定位权限配置
Add the purpose string to :
ios/Runner/Info.plistxml
<key>NSLocationWhenInUseUsageDescription</key>
<string>Show your location on the map</string>在中添加权限说明字符串:
ios/Runner/Info.plistxml
<key>NSLocationWhenInUseUsageDescription</key>
<string>在地图上显示您的位置</string>Step 4: Android permissions
步骤4:Android权限配置
Add to :
android/app/src/main/AndroidManifest.xmlxml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />在中添加:
android/app/src/main/AndroidManifest.xmlxml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />Step 5: Configure the access token
步骤5:配置访问令牌
The recommended pattern is to pass the token via at build/run time and set it on before creating any .
--dart-defineMapboxOptionsMapWidgetbash
flutter run --dart-define=ACCESS_TOKEN=pk.your_token_heredart
// 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()));
}Never hard-code tokens in source. For CI, pass .
--dart-define=ACCESS_TOKEN=$MAPBOX_ACCESS_TOKEN推荐的方式是在构建/运行时通过传递令牌,并在创建任何前将其设置到中。
--dart-defineMapWidgetMapboxOptionsbash
flutter run --dart-define=ACCESS_TOKEN=pk.your_token_heredart
// 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()));
}切勿在源代码中硬编码令牌。对于CI环境,使用传递令牌。
--dart-define=ACCESS_TOKEN=$MAPBOX_ACCESS_TOKENMap Initialization
地图初始化
Basic map
基础地图
dart
import 'package:flutter/material.dart';
import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart';
class MapScreen extends StatelessWidget {
const MapScreen({super.key});
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,
),
);
}
}dart
import 'package:flutter/material.dart';
import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart';
class MapScreen extends StatelessWidget {
const MapScreen({super.key});
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,
),
);
}
}Grab the MapboxMap
controller
MapboxMap获取MapboxMap
控制器
MapboxMapdart
class MapScreen extends StatefulWidget {
const MapScreen({super.key});
State<MapScreen> createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
MapboxMap? mapboxMap;
void _onMapCreated(MapboxMap controller) {
mapboxMap = controller;
}
Widget build(BuildContext context) {
return MapWidget(
key: const ValueKey('mapWidget'),
onMapCreated: _onMapCreated,
cameraOptions: CameraOptions(
center: Point(coordinates: Position(-122.4194, 37.7749)),
zoom: 12,
),
);
}
}dart
class MapScreen extends StatefulWidget {
const MapScreen({super.key});
State<MapScreen> createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
MapboxMap? mapboxMap;
void _onMapCreated(MapboxMap controller) {
mapboxMap = controller;
}
Widget build(BuildContext context) {
return MapWidget(
key: const ValueKey('mapWidget'),
onMapCreated: _onMapCreated,
cameraOptions: CameraOptions(
center: Point(coordinates: Position(-122.4194, 37.7749)),
zoom: 12,
),
);
}
}Add Annotations
添加标注
Use to create managers for point, circle, polyline, and polygon annotations. Managers are long-lived — create them once and reuse for updates.
mapboxMap.annotations使用创建点、圆形、折线和多边形标注的管理器。管理器为长生命周期对象——创建一次即可重复用于更新操作。
mapboxMap.annotationsPoint annotations with a custom image
自定义图片的点标注
dart
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);
}Remember to register the asset in :
pubspec.yamlyaml
flutter:
assets:
- assets/marker.pngdart
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);
}记得在中注册资源:
pubspec.yamlyaml
flutter:
assets:
- assets/marker.pngTap handling
点击事件处理
Use — this is the current API. is deprecated.
manager.tapEventsaddOnPointAnnotationClickListenertapEventsCancelable.cancel()dart
final Cancelable tapSubscription = pointAnnotationManager!.tapEvents(
onTap: (annotation) {
debugPrint('Tapped annotation ${annotation.id}');
},
);
void dispose() {
tapSubscription.cancel();
super.dispose();
}The same pattern — returning a — exists on every manager's and , and across the other annotation types (, etc.).
CancelablelongPressEventsdragEventsCircleAnnotationManager.tapEvents使用——这是当前的标准API。已被弃用。
manager.tapEventsaddOnPointAnnotationClickListenertapEventsCancelable.cancel()dart
final Cancelable tapSubscription = pointAnnotationManager!.tapEvents(
onTap: (annotation) {
debugPrint('点击了标注 ${annotation.id}');
},
);
void dispose() {
tapSubscription.cancel();
super.dispose();
}相同的模式——返回对象——适用于所有管理器的和,以及其他标注类型(如等)。
CancelablelongPressEventsdragEventsCircleAnnotationManager.tapEventsLoad annotations from GeoJSON
从GeoJSON加载标注
dart
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);
}For thousands of features use a style layer ( + ) instead of annotations.
GeoJsonSourceSymbolLayerdart
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);
}如果有成千上万个要素,建议使用样式图层( + )替代标注。
GeoJsonSourceSymbolLayerShow User Location
显示用户定位
Permissions must already be granted (use or similar) before enabling the puck.
permission_handlerdart
await mapboxMap.location.updateSettings(LocationComponentSettings(
enabled: true,
puckBearingEnabled: true,
locationPuck: LocationPuck(
locationPuck2D: DefaultLocationPuck2D(),
),
));在启用定位图标前,必须已获取权限(可使用等库)。
permission_handlerdart
await mapboxMap.location.updateSettings(LocationComponentSettings(
enabled: true,
puckBearingEnabled: true,
locationPuck: LocationPuck(
locationPuck2D: DefaultLocationPuck2D(),
),
));Camera Control
相机控制
dart
// Instant jump
await mapboxMap.setCamera(CameraOptions(
center: Point(coordinates: Position(-80.1263, 25.7845)),
zoom: 14,
));
// Animated fly-to
await mapboxMap.flyTo(
CameraOptions(
center: Point(coordinates: Position(-80.1263, 25.7845)),
zoom: 17,
bearing: 180,
pitch: 30,
),
MapAnimationOptions(duration: 2000),
);dart
// 瞬间跳转
await mapboxMap.setCamera(CameraOptions(
center: Point(coordinates: Position(-80.1263, 25.7845)),
zoom: 14,
));
// 动画式飞行跳转
await mapboxMap.flyTo(
CameraOptions(
center: Point(coordinates: Position(-80.1263, 25.7845)),
zoom: 17,
bearing: 180,
pitch: 30,
),
MapAnimationOptions(duration: 2000),
);Troubleshooting
故障排查
iOS build fails with "platform is lower than deployment target"
iOS构建失败,提示“platform is lower than deployment target”
The Flutter default iOS deployment target is lower than Mapbox's minimum (iOS 14). Set Minimum Deployments → iOS to on the Runner target in Xcode. If the project has an , also set there and re-run .
14.0ios/Podfileplatform :ios, '14.0'pod installFlutter默认的iOS部署目标版本低于Mapbox的最低要求(iOS 14)。在Xcode的Runner目标中将最低部署版本 → iOS设置为。如果项目存在,同时设置并重新运行。
14.0ios/Podfileplatform :ios, '14.0'pod installsetAccessToken
not called
setAccessToken未调用setAccessToken
setAccessTokenIf you forget to call before creating a , the map will load with a blank grid. Always call it in before .
MapboxOptions.setAccessTokenMapWidgetmain()runApp如果在创建前忘记调用,地图会加载为空白网格。务必在中之前调用该方法。
MapWidgetMapboxOptions.setAccessTokenmain()runAppAnnotation tap handler not firing
标注点击事件未触发
Make sure you're using — is deprecated. Also confirm the controller is captured via before you create the annotation manager.
manager.tapEvents(onTap: ...)addOnPointAnnotationClickListenerMapboxMaponMapCreated确保使用——已被弃用。同时确认在创建标注管理器前,已通过获取到控制器。
manager.tapEvents(onTap: ...)addOnPointAnnotationClickListeneronMapCreatedMapboxMapHot reload after permissions change
修改权限后热重载
iOS/Android will not re-read manifests or Info.plist on hot reload. Fully restart the app after editing permissions.
iOS/Android不会在热重载时重新读取清单文件或Info.plist。修改权限后需完全重启应用。
Reference Files
参考文件
- — Circle, Polyline, Polygon patterns and GeoJSON source/layer recipes.
references/annotations.md - — Deeper iOS/Android setup, token strategies, release signing notes.
references/platform-setup.md
- —— 圆形、折线、多边形标注模式以及GeoJSON源/图层实现方案。
references/annotations.md - —— 更深入的iOS/Android配置、令牌策略、发布签名说明。
references/platform-setup.md