mcpField
M
mapbox-flutter-patterns

mapbox-flutter-patterns

github.com/mapbox開発83794 回インストール4 週間前に更新
リポジトリ

mapbox-flutter-patterns について

mapbox-flutter-patternsは、iOSとAndroidでMapbox Maps SDKを使うFlutter開発者向けの統合ガイドです。設定、地図操作、注釈、位置表示、一般的なビルド問題を扱います。

主な機能

  1. 01Mapbox Flutterの導入とトークン設定
  2. 02MapWidgetの初期化とカメラ操作
  3. 03点、円、線、多角形の注釈
  4. 04注釈のタップとジェスチャーイベント処理
  5. 05GeoJSONの読み込みと現在地表示
  6. 06iOSとAndroidの設定トラブルシューティング

活用シーン

  1. 01FlutterアプリへのインタラクティブなMapbox地図の追加
  2. 02マーカーやGeoJSONフィーチャーの表示
  3. 03現在地の表示と注釈タップへの応答
  4. 04Mapbox導入後のiOSビルド失敗の調査

インストール

コマンドをコピーしてターミナルで実行します。

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

インストール後、Claude Code で/mapbox-flutter-patternsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

AGENTS.md
evals/
evals.json
references/
annotations.md
platform-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 のデフォルト設定ではコンパイルできません。

  1. Xcode で ios/Runner.xcworkspace を開きます。

  2. Runner ターゲット → General を選択し、Minimum Deployments → iOS を 14.0 に設定します。

  3. 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 の詳細なセットアップ、トークンの戦略、リリース署名に関する注意事項です。

追加リソース

コメント