mapbox-flutter-patterns について
mapbox-flutter-patternsは、iOSとAndroidでMapbox Maps SDKを使うFlutter開発者向けの統合ガイドです。設定、地図操作、注釈、位置表示、一般的なビルド問題を扱います。
主な機能
- 01Mapbox Flutterの導入とトークン設定
- 02MapWidgetの初期化とカメラ操作
- 03点、円、線、多角形の注釈
- 04注釈のタップとジェスチャーイベント処理
- 05GeoJSONの読み込みと現在地表示
- 06iOSとAndroidの設定トラブルシューティング
活用シーン
- 01FlutterアプリへのインタラクティブなMapbox地図の追加
- 02マーカーやGeoJSONフィーチャーの表示
- 03現在地の表示と注釈タップへの応答
- 04Mapbox導入後の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 統合パターン
Dart を使用して、iOS と Android で 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
タップの処理
現在の API である manager.tapEvents を使用します。addOnPointAnnotationClickListener は非推奨です。
tapEvents は Cancelable を返します。これを保存し、リスナーが不要になったときに .cancel() を呼び出します。
final Cancelable tapSubscription = pointAnnotationManager!.tapEvents(
onTap: (annotation) {
debugPrint('Tapped annotation ${annotation.id}');
},
);
@override
void dispose() {
tapSubscription.cancel();
super.dispose();
}
同じく Cancelable を返すパターンは、すべてのマネージャーの longPressEvents と dragEvents、および他のアノテーションタイプ(CircleAnnotationManager.tapEvents など)にもあります。
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),
);
トラブルシューティング
「platform is lower than deployment target」で iOS のビルドが失敗する
Flutter の iOS デプロイメントターゲットのデフォルト値は、Mapbox の最小要件(iOS 14)より低くなっています。Xcode で Runner ターゲットの Minimum Deployments → iOS を 14.0 に設定します。プロジェクトに ios/Podfile がある場合は、そこでも platform :ios, '14.0' を設定し、pod install を再実行します。
setAccessToken が呼び出されていない
MapWidget を作成する前に MapboxOptions.setAccessToken を呼び出し忘れると、マップは空白のグリッドで読み込まれます。必ず runApp の前に main() で呼び出してください。
アノテーションのタップハンドラーが呼び出されない
manager.tapEvents(onTap: ...) を使用していることを確認してください。addOnPointAnnotationClickListener は非推奨です。また、アノテーションマネージャーを作成する前に、onMapCreated 経由で MapboxMap コントローラーを取得していることも確認してください。
権限変更後のホットリロード
iOS/Android はホットリロード時にマニフェストや Info.plist を再読み込みしません。権限を編集した後は、アプリを完全に再起動してください。
参考ファイル
references/annotations.md— Circle、Polyline、Polygon のパターンと GeoJSON のソース/レイヤーのレシピです。references/platform-setup.md— iOS/Android の詳細なセットアップ、トークンの戦略、リリース署名に関する注意事項です。