关于 mapbox-flutter-patterns
mapbox-flutter-patterns 是面向 Flutter 开发者的 Mapbox Maps SDK 集成指南,适用于 iOS 和 Android。内容涵盖配置、地图控制、注记、位置显示和常见构建问题。
主要功能
- 01Mapbox Flutter 安装与令牌配置
- 02MapWidget 初始化和相机控制
- 03点、圆、线和多边形注记
- 04注记点击与手势事件处理
- 05加载 GeoJSON 并显示用户位置
- 06iOS 和 Android 配置故障排查
适用场景
- 01在 Flutter 应用中加入交互式 Mapbox 地图
- 02显示标记或 GeoJSON 要素
- 03显示用户位置并响应注记点击
- 04排查集成 Mapbox 后的 iOS 构建失败
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mapbox/ mapbox-agent-skills --skill mapbox-flutter-patterns安装后在 Claude Code 中输入/mapbox-flutter-patterns确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
AGENTS.mdevals/evals.jsonreferences/annotations.mdplatform-setup.md详细介绍
Mapbox Flutter 集成模式
在 iOS 和 Android 上使用 Dart 集成 Mapbox Maps SDK for Flutter(mapbox_maps_flutter)的官方模式。
在以下情况下使用此技能:
- 在 Flutter 应用中安装和配置 mapbox_maps_flutter
- 正确设置 Mapbox 访问令牌
- 使用相机/样式选项初始化
MapWidget - 添加注释(点、圆、线、多边形)并处理点击
- 显示用户位置图标
- 从应用资源加载 GeoJSON
- 添加 Mapbox 后排查 iOS 构建失败问题
官方资源:
不支持 Web 和桌面端 — Flutter SDK 仅面向 iOS 和 Android。
安装与设置
要求
- Flutter SDK 3.22.3 / Dart 3.4.4+
- iOS:部署目标为 14.0 或更高版本
- Android:minSdk 为 21 或更高版本
- 免费 Mapbox 账户
步骤 1:添加依赖项
# pubspec.yaml
dependencies:
mapbox_maps_flutter: ^2.0.0
flutter pub get
步骤 2:将 iOS 部署目标提升到 14.0(必需)
这是添加 Mapbox 后导致 iOS 构建失败的最常见原因。 Flutter SDK 要求 iOS 14.0,使用 Flutter 默认值将无法编译。
-
在 Xcode 中打开
ios/Runner.xcworkspace。 -
选择 Runner 目标 → General → 将 Minimum Deployments → iOS 设置为
14.0。 -
如果存在
ios/Podfile,也要更新其中的平台行:# ios/Podfile platform :ios, '14.0'
无需担心使用 CocoaPods 还是 Swift Package Manager — mapbox_maps_flutter 同时支持两者,Flutter 会根据应用的配置选择相应方式。
步骤 3:iOS 位置权限
将用途说明字符串添加到 ios/Runner/Info.plist:
<key>NSLocationWhenInUseUsageDescription</key>
<string>Show your location on the map</string>
步骤 4:Android 权限
添加到 android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
步骤 5:配置访问令牌
推荐的做法是在构建/运行时通过 --dart-define 传递令牌,并在创建任何 MapWidget 之前将其设置到 MapboxOptions 上。
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()));
}
切勿在源代码中硬编码令牌。在 CI 中,传入 --dart-define=ACCESS_TOKEN=$MAPBOX_ACCESS_TOKEN。
地图初始化
基础地图
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,
),
);
}
}
获取 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,
),
);
}
}
添加注释
使用 mapboxMap.annotations 为点、圆、折线和多边形注释创建管理器。管理器会长期存在 — 创建一次并重复使用,以便更新。
使用自定义图像的点注释
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.yaml 中注册资源:
flutter:
assets:
- assets/marker.png
点击处理
使用 manager.tapEvents — 这是当前 API。addOnPointAnnotationClickListener 已弃用。
tapEvents 会返回一个 Cancelable,请保存该对象,并在不再需要监听器时调用 .cancel():
final Cancelable tapSubscription = pointAnnotationManager!.tapEvents(
onTap: (annotation) {
debugPrint('Tapped annotation ${annotation.id}');
},
);
@override
void dispose() {
tapSubscription.cancel();
super.dispose();
}
每个管理器的 longPressEvents 和 dragEvents,以及其他注释类型(CircleAnnotationManager.tapEvents 等)都采用相同模式 — 返回一个 Cancelable。
从 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);
}
对于数千个要素,请使用样式图层(GeoJsonSource + SymbolLayer),而不是注释。
显示用户位置
启用位置图标之前,必须已授予权限(使用 permission_handler 或类似工具)。
await mapboxMap.location.updateSettings(LocationComponentSettings(
enabled: true,
puckBearingEnabled: true,
locationPuck: LocationPuck(
locationPuck2D: DefaultLocationPuck2D(),
),
));
相机控制
// 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),
);
故障排查
iOS 构建失败,提示“platform is lower than deployment target”
Flutter 默认的 iOS 部署目标低于 Mapbox 的最低要求(iOS 14)。在 Xcode 的 Runner 目标中,将 Minimum Deployments → iOS 设置为 14.0。如果项目中存在 ios/Podfile,也要将其中的平台设置为 platform :ios, '14.0',然后重新运行 pod install。
未调用 setAccessToken
如果忘记在创建 MapWidget 之前调用 MapboxOptions.setAccessToken,地图会显示空白网格。务必在 main() 中、runApp 之前调用它。
注释点击处理器未触发
确保使用的是 manager.tapEvents(onTap: ...)——addOnPointAnnotationClickListener 已弃用。另外,请确认在创建注释管理器之前,已通过 onMapCreated 获取 MapboxMap 控制器。
更改权限后热重载
iOS/Android 不会在热重载时重新读取清单或 Info.plist。编辑权限后,请完全重启应用。
参考文件
references/annotations.md— 圆形、折线、多边形模式,以及 GeoJSON 源/图层配置示例。references/platform-setup.md— 更深入的 iOS/Android 配置、令牌策略和发布签名说明。