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 の最新リリースである Ladybug 2024.2.1+ を使用している場合、Flutter アプリを起動しようとするとエラーが発生することがあります。例えば、このチュートリアルを実行しようとすると、次のようなエラーが表示されることがあります。
“Unknown Kotlin JVM target: 21”
同様に、flutter create コマンドを使って新しい Flutter プロジェクトを作成すると、次のような警告が表示されることがあります。
“The configured version of Java detected may conflict with the Gradle version in your new Flutter app."
この問題は、Ladybug にバンドルされている Java のバージョン(JDK 21)が Flutter の要件(JDK 17)と後方互換性がないことと、Flutter が使用している Gradle のバージョンに関連しています。

新しい Flutter アプリを作成し、Android Studio Ladybug でこのチュートリアルを実行するための解決策は、手動で JDK 17 をインストールし、Flutter が JDK 17 を使用するようにリダイレクトすることです。
Android Studio からこの操作を行うためには、
[設定] -> [ビルドツール] -> [Gradle JDK Location] に行き、JDK 17 のインストール パスを設定します。
またはコマンド ラインから次のように実行します。

flutter config --jdk-dir=<your-local-JDK-17-path>

前提条件

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

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

ステップ

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

  1. VS Code を開き、ウェルカム タブで [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 ファイルを編集して、最小要件を更新します。

    build.gradle

    android {
        namespace = "com.example.app.display_a_map"
        compileSdk = flutter.compileSdkVersion
        ndkVersion = "25.2.9519653"  //変更
    
        compileOptions {
            sourceCompatibility = JavaVersion.VERSION_1_8
            targetCompatibility = JavaVersion.VERSION_1_8
        }
    
        kotlinOptions {
            jvmTarget = JavaVersion.VERSION_1_8
        }
    
        defaultConfig {
            // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
            applicationId = "com.example.app.display_a_map"
            // You can update the following values to match your application needs.
            // For more information, see: https://flutter.dev/to/review-gradle-config.
            //
            minSdk = 26 // 変更
            targetSdk = flutter.targetSdkVersion
            versionCode = flutter.versionCode
            versionName = flutter.versionName
        }
    }
    

    `

  2. プロジェクトの android/settings.gradle ファイルを編集して、Kotlin のバージョンを更新します。

    settings.gradle

    plugins {
        id "dev.flutter.flutter-plugin-loader" version "1.0.0"
        id "com.android.application" version "8.1.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 = ''; // Your access token here. //追加
    
        runApp(const MainApp());
    }
    

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

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

    main.dart

    void main() {
    
    const apiKey = ''; // Your access token here.
    
    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 = ''; // Your access token here.
    
        ArcGISEnvironment.apiKey = apiKey;
    
        runApp(
    
            //変更開始
            const MaterialApp(
                home: MainApp(),
            ),
            //変更終了
    
        );
    }
    

マップを追加する

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

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

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

    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 プロパティをマップに設定します。 さらに、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 lib/main.dart
    
  4. アクセス トークンを取得し、ソース コード ファイルに API キーを設定します。

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

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

Web マップを表示する

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

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

    main.dart

    void onMapViewReady() {
    
        //URI を生成します。
        var uri = Uri(
          scheme: "https",
          host: "example.com",
          path: "Portal の Path"
        );
    
        //ArcGIS ポータルを作成します。URI を指定しない場合は "Portal.arcGISOnline()" を使用します。
        final portal = Portal(uri);
    
        //アイテム ID を使用して、Web マップをポータル アイテムとして取得します。
        final portalItem = PortalItem.withPortalAndItemId(portal: portal, itemId: "Web マップの ID");
    
        //ポータル アイテムからマップを作成します。
        final map = ArcGISMap.withItem(portalItem);
    }
    

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