Flutter

出典:ArcGIS Maps SDK for Flutter - Tutorials - Display a map

マップを表示する

このチュートリアルでは ArcGIS Maps SDK for Flutter を使用して、マップとベースマップ レイヤーを表示する方法を紹介します。

マップには、地理データのレイヤーが含まれています。マップには、ベースマップ レイヤーと、オプションで 1 つ以上のデータ レイヤーを追加できます。

このチュートリアルでは、地形図ベースマップ レイヤーを使用して、富士山付近を表示する地図を作成します。

このマップとコードは、他の 2D チュートリアルの出発点として使用されます。

このチュートリアルのトピックの背景情報については、Mapping API and location services guide の Maps (2D)ベースマップ を参照してください。

Android Studio の最新リリースである Meerkat 2024.3.1 以降を使用している場合、pub.dev で arcgis_maps パッケージを使用すると、SDK の依存関係の管理で問題が発生する可能性があります。 これを解決するには、Flutter のデフォルト JDK として JDK 17 を設定する必要があります。

  • macOS の場合:Homebrew を使用して macOS に JDK 17 をインストールします。

    brew install openjdk@17
    sudo ln -sfn /opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-17.jdk
    flutter config --jdk-dir=/opt/homebrew/Cellar/openjdk@17/17.0.14/libexec/openjdk.jdk/Contents/Home
    
  • Windowsの場合:Microsoft の OpenJDK ページから OpenJDK 17 をダウンロードして、zip ファイルを任意のフォルダに解凍した後、PowerShell を使用して設定します。

    flutter config --jdk-dir PATH-TO-JDK
    

前提条件

このチュートリアルを実施するには、以下が必要です。

  1. API キーにアクセスするための ArcGIS 開発者アカウント。アカウントをお持ちでない場合は、サインアップ(無料)してください。アカウントの作成方法は「開発者アカウントの作成」をご覧ください。
  2. 開発環境がシステム要件を満たしており、Flutter の開発環境 が整っていることを確認します。
  3. Flutter 用の IDE。VS Code を推奨しています。

ステップ

新しい Flutter アプリを作成する

  1. VS Code を開き、Welcome タブで [Open Folder…] を選択します。プロジェクトの場所を選んでください。

  2. [View] > [Terminal] に進みます。

  3. ターミナル ウィンドウで以下のコマンドを使い、display_a_map という新しい Flutter アプリを作成します。 必要なターゲット プラットフォームと 組織名 com.example.app を設定します。

    flutter create -e display_a_map --platforms ios,android --org com.example.app
    

ArcGIS Maps SDK for Flutter を追加する

arcgis_maps パッケージに依存関係を追加します。

  1. VS Code のターミナルで、ディレクトリーを新しいプロジェクトに変更します。
    cd display_a_map
    
  2. 以下のコマンドを実行します。
    dart pub add arcgis_maps
    
  3. 以下のコマンドを実行します。
    flutter pub upgrade
    
  4. 最後に、以下のコマンドを実行します。
    dart run arcgis_maps install
    

プラットフォーム固有の構成

Android

  1. プロジェクトの android/app/build.gradle.kts ファイルを編集して、最小要件を更新します。

    build.gradle.kts

    android {
        namespace = "com.example.app.display_a_map"
        compileSdk = flutter.compileSdkVersion
        ndkVersion = "27.0.12077973" //変更
    
        compileOptions {
            sourceCompatibility = JavaVersion.VERSION_11
            targetCompatibility = JavaVersion.VERSION_11
        }
    
        kotlinOptions {
            jvmTarget = JavaVersion.VERSION_11.toString()
        }
    
        defaultConfig {
            // TODO: 任意のアプリケーション ID を指定します (https://developer.android.com/studio/build/application-id.html).
            applicationId = "com.example.app.display_a_map"
            // アプリケーションの要件に合わせて次の値を更新します。
            // 詳細については https://flutter.dev/to/review-gradle-config を参照してください。
            minSdk = 26 //変更
            targetSdk = flutter.targetSdkVersion
            versionCode = flutter.versionCode
            versionName = flutter.versionName
        }
    
  2. プロジェクトの android/settings.gradle.kts ファイルを編集して、Kotlin のバージョンを更新します。

    settings.gradle.kts

    plugins {
        id "dev.flutter.flutter-plugin-loader" version "1.0.0"
        id "com.android.application" version "8.7.0" apply false
        id "org.jetbrains.kotlin.android" version "1.9.0" apply false //変更
    }
    
  3. android/app/src/main/AndroidManifest.xml に、オンライン リソースにアクセスするためのパーミッションを追加します。

    AndroidManifest.xml

    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
        <uses-permission android:name="android.permission.INTERNET" /> <!-- 追加 -->
        <application
            android:label="display_a_map"
            android:name="${applicationName}"
            android:icon="@mipmap/ic_launcher">
    

iOS

  1. ios/Podfile ファイルを編集して iOS 16.0 を最小に設定します。 行のコメントを解除し、バージョン番号を更新します。

    Podfile

    # Uncomment this line to define a global platform for your project
    platform :ios, '16.0'  #変更
    
  2. Runtimecore pod と arcgis_maps_ffi pod を Runner ターゲット セクションに追加します。

    Podfile

    target 'Runner' do
        use_frameworks!
        use_modular_headers!
    
        #変更開始
        pod 'Runtimecore', :podspec => '../arcgis_maps_core/ios/Runtimecore.podspec'
        pod 'arcgis_maps_ffi', :podspec => '../arcgis_maps_core/ios/arcgis_maps_ffi.podspec'
        #変更終了
    
        flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
        target 'RunnerTests' do
            inherit! :search_paths
        end
    end
    
  3. pod update を使用して Pods を設定します。

    cd ios && pod update && cd ..
    

アクセス トークンを取得する

このチュートリアルで使用するロケーション サービスを使用するには、アクセス トークンが必要です。

  1. アクセス トークンを取得するには、API キーの取得 チュートリアルに進んでください。
  2. 次の権限が有効になっていることを確認してください。[ロケーション サービス] > [ベースマップ] > [ベースマップ スタイル サービス]
  3. アクセス トークンをコピーします。

アクセス トークンを取得する他の方法については、Types of authentication を参照してください。

API キーを設定する

  1. VS Codeで、lib/main.dart を開きます。

  2. arcgis_maps パッケージをインポートします。

    main.dart

    import 'package:flutter/material.dart';
    
    import 'package:arcgis_maps/arcgis_maps.dart'; //追加
    
  3. main() 関数で、const apiKey を定義し、その値にアクセス トークンを設定します。

    void main() {
    
        const apiKey = ''; // アクセス トークンをここに記入します。 //追加
    
        runApp(const MainApp());
    }
    

    このチュートリアルでは便宜上、アクセス トークンをコードに直接格納しています。アクセス トークンをソース コードに格納することはベスト プラクティスではありません。

  4. ArcGISEnvironment.apiKeyapiKey 定数に設定します。

    main.dart

    void main() {
    
    const apiKey = ''; // アクセス トークンをここに記入します。
    
    ArcGISEnvironment.apiKey = apiKey; //追加
    
    runApp(const MainApp());
    }
    

    API キーが必要なのにアクセス トークンが設定されていない(または無効な値が設定されている)場合、チュートリアルのコードを実行すると次のようなエラーが表示されることがあります。
    Unhandled Loadable ArcGISMap load error: ArcGISException: code=22; HttpException: Failed to parse header value
    このエラーが発生した場合は、有効なアクセス トークンが ArcGISEnvironment.apiKey プロパティに設定されていることを確認してください。Flutter のコア HTTP スタックに既知の問題があるため、ArcGIS Maps SDK for Flutter は現時点でより明確なエラーを確実に提供することができません。

  5. runApp() 内で MaterialApp をインスタンス化し、名前付き引数の homeMainApp のインスタンスを設定します。

    main.dart

    void main() {
    
        const apiKey = ''; // アクセス トークンをここに記入します。
    
        ArcGISEnvironment.apiKey = apiKey;
    
        runApp(
    
            //変更開始
            const MaterialApp(
                home: MainApp(),
            ),
            //変更終了
    
        );
    }
    

マップを追加する

地形図ベースマップ レイヤーを含む地図を作成します。 地図は富士山の付近とします。

  1. テンプレート MainApp クラス定義をリファクタリングして、StatefulWidget を拡張します。 StatelessWidget キーワードにマウス カーソルを合わせて右クリックし、[Refactor…] から、[Convert to StatefulWidget] を選択してコードをリファクタリングします。

    ArcGIS Maps SDK for Flutter で作業していると、データの変更に応じて UI を更新するなど、アプリケーションの状態の更新が必要になることがよくあります。 ステートフル ウィジェットを実装することで、アプリはこのような状況に対応できます。 ステートレス ウィジェットの実装を使用して、単に地図を表示することも可能です。Display map サンプルをご確認ください。

    main.dart

    class MainApp extends StatefulWidget { //変更
    
        const MainApp({super.key});
    
        // 変更開始
        @override
        State<MainApp> createState() => _MainAppState();
        // 変更終了
    
    }
    
    //追加開始
    class _MainAppState extends State<MainApp> {
        @override
        Widget build(BuildContext context) {
    
            return const MaterialApp(
                home: Scaffold(
                    body: Center(
                        child: Text('Hello World!'),
                    ),
                ),
            );
    
        }
    }
    //追加終了
    
  2. build メソッド内で返される MaterialApp ウィジェットを削除します。 このコードは Flutter create テンプレートによって生成されたもので、次項でマップを含むウィジェットを返すコードに置き換えられます。

    main.dart

    class MainApp extends StatefulWidget {
    
        const MainApp({super.key});
    
        @override
        State<MainApp> createState() => _MainAppState();
    
    }
    
    class _MainAppState extends State<MainApp> {
            @override
            Widget build(BuildContext context) {
    
                // 削除開始
                return const MaterialApp(
                    home: Scaffold(
                        body: Center(
                            child: Text('Hello World!'),
                        ),
                    ),
                );
                // 削除終了
    
            }
    }
    
  3. _MainAppState クラスの内部で、最後のクラス メンバー変数 _mapViewController を定義し、ArcGISMapView クラスの createController() を呼び出して ArcGISMapViewController で初期化します。

    ArcGIS マップ ビュー コントローラーは、ArcGISMap で定義された 2 次元 (2D) 地理コンテンツを表示するユーザー インタフェース コントロールです。

    main.dart

    class _MainAppState extends State<MainApp> {
    
        final _mapViewController = ArcGISMapView.createController(); //追加
    
        @override
        Widget build(BuildContext context) {
    
        }
    
    }
    
  4. build メソッド内で ScaffoldColumnExpanded からなるウィジェット ツリーに ArcGISMapView ウィジェットを追加します。 引数名 controllerProvider をクラス メンバー変数 _mapViewController に設定し、onMapViewReady 引数を次に定義する引数と同じ名前の新しいメソッドに設定します。

    Scaffold ウィジェットは基本的なマテリアル デザインのビジュアル レイアウト構造を提供し、Column ウィジェットは子ウィジェットを垂直配列で表示します。ArcGISMapView ウィジェットは、サイズが制限されたウィジェット内でのみ使用できます。 サイズが制限されていない状態で使用すると、アプリケーションは例外をスローします。 たとえば、ArcGISMapViewColumn ウィジェット内で使用すると、サイズが制限されないため、このような例外が発生します。 代わりに、チュートリアルのこのステップで説明するように、ArcGISMapViewExpanded ウィジェットでラップして、適切な境界を提供することができます。

    main.dart

    class _MainAppState extends State<MainApp> {
    
        final _mapViewController = ArcGISMapView.createController();
    
        @override
        Widget build(BuildContext context) {
    
            //追加開始
            return Scaffold(
              body: Column(
                children: [
                  Expanded(
                    child: ArcGISMapView(
                      controllerProvider: () => _mapViewController,
                      onMapViewReady: onMapViewReady,
                    ),
                  ),
                ],
              ),
            );
            //追加終了
    
        }
    
    }
    
  5. MainAppState 内で、何も返さない新しいメソッド onMapViewReady() を定義します。

    main.dart

    class _MainAppState extends State<MainApp> {
    
        final _mapViewController = ArcGISMapView.createController();
    
        @override
        Widget build(BuildContext context) {
    
            return Scaffold(
                body: Column(
                    children: [
                        Expanded(
                            child: ArcGISMapView(
                                controllerProvider: () => _mapViewController,
                                onMapViewReady: onMapViewReady,
                            ),
                        ),
                    ],
                ),
            );
    
        }
    
        //追加開始
        void onMapViewReady() {
    
        }
        //追加終了
    
    }
    
  6. 新しいメソッド内で final 変数 basemapStyleParamsbasemapmap を定義します。それぞれの定義は以下の通りです。

    • basemapStyleParams: BasemapStyleParameters をインスタンス化し、specificLanguage を日本語に変更します。
    • basemap: ArcGIS Topographic ベースマップ スタイルと 生成した basemapStyleParamsBasemap をインスタンス化します。
    • map: basemapArcGISMap をインスタンス化します。

    main.dart

    class _MainAppState extends State<MainApp> {
    
        final _mapViewController = ArcGISMapView.createController();
    
        @override
        Widget build(BuildContext context) {
    
            return Scaffold(
                body: Column(
                    children: [
                        Expanded(
                            child: ArcGISMapView(
                                controllerProvider: () => _mapViewController,
                                onMapViewReady: onMapViewReady,
                            ),
                        ),
                    ],
                ),
            );
    
        }
    
        void onMapViewReady() {
    
            //追加開始
            final basemapStyleParams = BasemapStyleParameters();
            basemapStyleParams.specificLanguage = "ja"; //ベースマップの言語を日本語に設定
    
            final basemap = Basemap.withStyle(BasemapStyle.arcGISTopographic, parameters: basemapStyleParams); //ベースマップに設定を適用
            final map = ArcGISMap.withBasemap(basemap); //設定したベースマップでマップを生成
            //追加終了
    
        }
    
    }
    
  7. ArcGIS マップ ビュー コントローラーの arcGISMap プロパティーを map に設定します。 さらに、setViewpoint() を呼び出して、富士山にズームします。

    main.dart

    class _MainAppState extends State<MainApp> {
    
        final _mapViewController = ArcGISMapView.createController();
    
        @override
        Widget build(BuildContext context) {
    
            return Scaffold(
                body: Column(
                    children: [
                        Expanded(
                            child: ArcGISMapView(
                                controllerProvider: () => _mapViewController,
                                onMapViewReady: onMapViewReady,
                            ),
                        ),
                    ],
                ),
            );
    
        }
    
        void onMapViewReady() {
    
            final basemapStyleParams = BasemapStyleParameters();
            basemapStyleParams.specificLanguage = "ja"; //ベースマップの言語を日本語に設定
    
            final basemap = Basemap.withStyle(BasemapStyle.arcGISTopographic, parameters: basemapStyleParams); //ベースマップに設定を適用
            final map = ArcGISMap.withBasemap(basemap); //設定したベースマップでマップを生成
    
            //追加開始
            _mapViewController.arcGISMap = map;
            _mapViewController.setViewpoint(
                Viewpoint.withLatLongScale(
                    latitude: 35.360626,
                    longitude: 138.727363,
                    scale: 200000.0,
                ),
            );
            //追加終了
    
        }
    
    }
    

アプリを実行する

  1. Android エミュレーター、iOS シミュレーター、または物理的なデバイスが設定され、実行されていることを確認します。
  2. VS Codeで、[Run] > [Run Without Debugging] を選択します。

完成版のプロジェクトはこちらからダウンロードできます(マップの表示場所は本チュートリアルで設定した場所とは異なります)。

ダウンロードしたソリューションを実行する

プロジェクト ソリューションをダウンロードした場合は、以下の手順に従ってアプリケーションを実行します。

  1. VS Code で展開したプロジェクトを開きます。

  2. VS Code のターミナルで、以下のコマンドを実行します。

    flutter pub upgrade
    
  3. 以下のコマンドを実行します。

    dart run arcgis_maps install
    
  4. アクセス トークンを取得し、ソース コード ファイルに API キーを設定します。

  5. Android エミュレーター、iOS シミュレーター、または物理デバイスが設定され、実行されていることを確認します。

  6. VS Code で、[Run] > [Run Without Debugging] を選択します。

Web マップを表示する

Web マップの作成」のガイドで Web マップを作成している場合は、作成した Web マップも基本的に同じステップで表示できます。

  1. マップを表示するのステップで作成したプロジェクトの main.dart を開き、onMapViewReady() を下記のように書き換えます。

    main.dart

    void onMapViewReady() {
    
        //アイテム ID を使用して、Web マップをポータル アイテムとして取得します。
        final portalItem = PortalItem.withPortalAndItemId(
            portal: Portal.arcGISOnline(),
            itemId: "Web マップの ID",
        );
    
        //ポータル アイテムからマップを作成します。
        final map = ArcGISMap.withItem(portalItem);
    
        _mapViewController.arcGISMap = map;
    
    }
    

アプリの動作が確認できたら ArcGIS の セキュリティーと認証について学びましょう!