Google Flutter コラム- 第2 回 GoogleMapとmapboxの地図表示を比較してみた

Google Flutterのコラム第2回は、Flutterを使った自作の地図アプリケーション開発を行いたいと思います。 

今回は、地図機能を実現するにあたってGoogle Mapとmapboxの2種類を使用します。 

Google Mapは、90 日間 $300 分の無料トライアルがありますが、これが終了すると有料アカウントが必要になります。

Google Cloud の無料プログラム

一方mapboxは、機能は制限されますがフリーアカウントを作成することで利用することができます。

事前準備 

アプリケーション開発環境は、前回コラムを元にFlutter 2.2.0を構築しています。

環境構築をしていない場合は、前回コラムの「Google Flutter を 導入してみた」の章を参照してください。 

■開発環境

OS:Windows 10 64bit
CPU: Intel® Core™ i7 Processor
メモリ:32GB
Flutterバージョン:2.2.0
AndroidStudio:4.2.1

googleアカウントは事前に作成済みとなります。

Google Mapを使用したアプリケーション開発

Google FlutterでGoogle Mapを使用した、Androidアプリケーションを開発について説明します。

Google MapのAPIキー取得

地図表示や検索、ルートを引くといったGoogle Mapの機能はGoogle Cloudが提供しており、利用するにはAPIキーが必要となります。 APIキー取得までの流れを、簡単に説明します。

1.Google Cloudにログイン

まず、以下URLからGoogle Cloudのmaps platformにアクセスし、「使ってみる」のリンクをクリックしGoogleアカウントでログインします。

https://cloud.google.com/maps-platform/

2.APIキーの発行

Google Cloudのコンソール画面が表示されたら、画面左の「認証情報」をクリックし、「認証情報を作成」から「APIキー」をクリックします。
その後、以下ポップアップが表示されAPIキーが作成されます。

注意点として、この状態のAPIキーは制限がなく、すべてのAPIがすべてのアプリケーションから使用可能です。

詳細な説明は割愛しますがAPIキーには適切な利用制限を設定の上、ソースコードを公開する際には、APIキーを含んだ状態で公開してしまうといったことがないようにしてください。
https://developers.google.com/maps/api-key-best-practices

Google Map アプリ作成

1.Flutterアプリケーションを作成

まず、ベースとなるFlutterAppプロジェクト作成します。

前回コラムの「Google Flutter を 導入してみた」の章の「サンプルアプリケーションの実行」を参照してください。

2.pubspec.yamlの修正

次に、サンプルアプリのソースコードを修正していきます。

今回はGoogle Mapを使った地図表示を行うにあたり、google_maps_flutterパッケージを使用します。
google_maps_flutter | Flutter Package (pub.dev)

そのため、まずはこのgoogle_maps_flutterパッケージを使用するためにpubspec.yamlファイルを修正します。 具体的には、dependenciesタグが以下のようになるよう「google_maps_flutter: ^2.0.6」を追加します。
pubspec.yaml

dependencies:																																																							
  flutter:																																																							
    sdk: flutter																																																							
																																																							
  google_maps_flutter: ^2.0.6																																																							

pubspec.yamlファイルは、左のプロジェクトビューのプロジェクト直下にあります。

修正後、右上の「Pub get」をクリックし追加した依存パッケージの取得を実施します。
正常に終了すると、画面下に画像のようなメッセージが表示されます。

ここで少しpubspec.yamlについて触れます。
すべてのFlutterプロジェクトにはpubspec.yamlというファイルが含まれています。 このファイルはYAMLという言語で記述されており、Flutterプロジェクトの環境情報が記載されています。

環境情報には、本Flutterプロジェクトが使用するdart-SDKのバージョンや依存(使用)するパッケージ、リソース情報などがあります。

パッケージとはFlutterプロジェクトの形式の一種で、flutterアプリを開発するのに便利な機能をパッケージ化したものになります。

pubspec.yamlにパッケージ名とバージョンを記載することで、「pub.dev」というパッケージ公開サイトで公開されているパッケージを使用することができます。

Dart packages (pub.dev)

上記で行った変更は、本Flutterプロジェクトで「google_maps_flutter」という外部パッケージを使用するという意味になります。

より詳細な情報は以下を参照してください。

https://flutter.dev/docs/development/tools/pubspec

3.dartコード修正

次に、「google_maps_flutter」パッケージを使ったサンプルコードを作成します。

ソースコードは、左のプロジェクトビューのlibフォルダ内のmain.dartにあります。

ファイルを開いたら、以下のソースコードで上書きします。

このソースコードは、以下のpub.dev内のサンプルを元にしています。

https://pub.dev/packages/google_maps_flutter#sample-usage

主な変更点は、以下の2点です。 

1.デフォルトのカメラ位置を「Google本社」から「日本システム開発名古屋本社」に変更
2.右下のボタンタップ時の移動先を「アメリカ合衆国 カリフォルニア州 マウンテンビュー ショアライン湖」から「名古屋城」に変更

lib/main.dart
import 'dart:async';																																																							
																																																							
import 'package:flutter/material.dart';																																																							
import 'package:google_maps_flutter/google_maps_flutter.dart';																																																							
																																																							
void main() => runApp(MyApp());																																																							
																																																							
class MyApp extends StatelessWidget {																																																							
  @override																																																							
  Widget build(BuildContext context) {																																																							
    return MaterialApp(																																																							
      title: 'Flutter Google Maps Demo',																																																							
      home: MapSample(),																																																							
    );																																																							
  }																																																							
}																																																							
																																																							
class MapSample extends StatefulWidget {																																																							
  @override																																																							
  State createState() => MapSampleState();																																																							
}																																																							
																																																							
class MapSampleState extends State {																																																							
  Completer _controller = Completer();																																																							
																																																							
  static final CameraPosition _kNSK = CameraPosition(																																																							
    target: LatLng(35.17176088096857, 136.88817886263607),																																																							
    zoom: 14.4746,																																																							
  );																																																							
																																																							
  static final CameraPosition _kNagoyajo = CameraPosition(																																																							
      bearing: 192.8334901395799,																																																							
      target: LatLng(35.184910766826086, 136.8996468623372),																																																							
      tilt: 59.440717697143555,																																																							
      zoom: 19.151926040649414);																																																							
																																																							
  @override																																																							
  Widget build(BuildContext context) {																																																							
    return new Scaffold(																																																							
      body: GoogleMap(																																																							
        mapType: MapType.hybrid,																																																							
        initialCameraPosition: _kNSK,																																																							
        onMapCreated: (GoogleMapController controller) {																																																							
          _controller.complete(controller);																																																							
        },																																																							
      ),																																																							
      floatingActionButton: FloatingActionButton.extended(																																																							
        onPressed: _goToTheNagoyajo,																																																							
        label: Text('To the 名古屋城!'),																																																							
        icon: Icon(Icons.directions_bike),																																																							
      ),																																																							
    );																																																							
  }																																																							
																																																							
  Future _goToTheNagoyajo() async {																																																							
    final GoogleMapController controller = await _controller.future;																																																							
    controller.animateCamera(CameraUpdate.newCameraPosition(_kNagoyajo));																																																							
  }																																																							
}																																																							

4.APIキーを追記

次に、GoogleMap表示に必要なAPIキーを入力します。

APIキーは「AndroidManifest.xml」の「application」タグ内に記載します。
「YOUR KEY HERE」を自分で取得したAPIキーに置き換えてください。

android\app\src\main\AndroidManifest.xml
<application android:value="YOUR KEY HERE"></application>																																																							
																																																							
AndroidManifest.xmlは、左のプロジェクトビューのandroidフォルダから以下のようにたどった場所にあります。

5.SDKバージョン修正

Flutterアプリケーションのデフォルトのプロジェクトは、サポートするAndroid SDKの最低バージョンが16となっており、

「google_map_flutter」パッケージでの最低バージョン20と一致しません。
そのため、build.gradleファイルの「minSdkVersion」を以下のように20に修正します。

android\app\src\main\AndroidManifest.xml

android {
    compileSdkVersion 29

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "jp.co.nskint.flutter_example.googlemap_flutter"
        minSdkVersion 20
        targetSdkVersion 29
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
}
build.gradleは、左のプロジェクトビューのandroidフォルダから以下のようにたどった場所にあります。

6.アプリ起動

以下はAndroid10.0(Google APIs) x86_64のAndroid Emulatorでの起動例です。
衛星地図上に道路や施設のアイコンが表示されたGoogleMapと、右下にボタンが表示されます。
右下のアイコンをタップすると、アニメーションとともに視点が名古屋城へと移動します。 

7.サンプルコードの修正

Flutterの機能の一つであるHot Reloadを使いつつ、アプリの表示内容を修正してみます。

今回は以下の2点を修正します。
・左下のボタンがGoogleMapの拡縮ボタン「+/-」と重複しているので、場所を変える
・GoogleMapの地図スタイルを通常に変更する

google_maps_flutterの主な機能

「google_maps_flutter」パッケージは、Flutter公式が開発して公開しているパッケージです。

ローカライズも進んでおり、日本語での地図表示や路線図の表示まで簡単に行えます。
日本語のドキュメントも豊富です。

「google_maps_flutter」パッケージの機能としては、今回の視点移動のほかにも主な機能としては以下が利用できます。

・地図スタイルの切り替え(通常、衛星画像、ハイブリッド、地形)
・渋滞情報の表示
・地図上の位置から緯度経度の取得
・緯度経度から画面上の座標を取得
・マーカーの表示
・円や線分の描画
・カスタマイズした地図スタイルを表示
スタイル付き地図を追加する  |  Maps SDK for Android  |  Google Developers

mapboxを使用したアプリケーション開発

次は、Flutterでmapboxを使用した、Androidアプリケーションを開発について説明します。

mapboxは、2010年頃登場した地図開発プラットフォームで、近年様々な企業やアプリケーションに導入され始めています。
https://www.mapbox.jp/

mapboxアカウントの作成

mapboxは、GoogleMapと同様にAPIキーが必要となります。

APIキーを取得するために、mapboxアカウントを作成します。

1.mapboxのwebページにアクセスし、サインアップ

以下URLからアクセスし、サインアップをクリックします。

すでにアカウントをお持ちの方はログインをクリックしてください。
https://www.mapbox.jp/

2.アカウント情報入力

ユーザー名などのアカウント情報を入力してアカウントを作成します。

3.アクセストークンコピー

ログインすると、最初からDefault public tokenが作成されているため、このアクセストークンをコピーしてください。

mapbox_glパッケージで地図のwidgetを使用する際に必要になります。

4.シークレットトークン作成

mapbox_glの最新バージョンを使う場合、上記とは別にシークレットトークンを作る必要があります。

Create a tokenボタンをクリック

Nameに任意の名前を入力
DOWNLOADS:READにチェック

Create tokenボタンをクリック

作成後は一度しか表示されないため、必ずテキストファイル等にコピーしてください。

mapbox_glを利用して地図表示

1.pubspec.yamlを修正

mapbox_glパッケージを利用するために、pubspec.yamlを修正します。

※インデントに注意してください。

例)
dependencies:																																																							
  flutter:																																																							
    sdk: flutter																																																							
  mapbox_gl: ^0.12.0																																																							
また、2021/06/24現在、0.12.0にはFlutter2.X.X系で対応されたnull Safety対応が入っていないため、以下を追記してください。
dependency_overrides:																																																							
  mapbox_gl:																																																							
    git:																																																							
      url: https://github.com/tobrun/flutter-mapbox-gl.git																																																							
  mapbox_gl_platform_interface:																																																							
    git:																																																							
      url: https://github.com/tobrun/flutter-mapbox-gl.git																																																							
      path: mapbox_gl_platform_interface																																																							
  mapbox_gl_web:																																																							
    git:																																																							
      url: https://github.com/tobrun/flutter-mapbox-gl.git																																																							
      path: mapbox_gl_web																																																							

2.main.dartを修正

mapboxを使って地図表示するwidget、MapboxMapを記述します。
例)
import 'package:flutter/material.dart';																																																							
import 'package:mapbox_gl/mapbox_gl.dart';																																																							
																																																							
void main() {																																																							
  runApp(MyApp());																																																							
}																																																							
																																																							
class MyApp extends StatelessWidget {																																																							
  // This widget is the root of your application.																																																							
  @override																																																							
  Widget build(BuildContext context) {																																																							
    return MaterialApp(																																																							
      title: 'Flutter Demo',																																																							
      theme: ThemeData(																																																							
        primarySwatch: Colors.blue,																																																							
      ),																																																							
      home: MyHomePage(title: 'Flutter Demo Home Page'),																																																							
    );																																																							
  }																																																							
}																																																							
																																																							
class MyHomePage extends StatefulWidget {																																																							
  MyHomePage({Key? key, required this.title}) : super(key: key);																																																							
  final String title;																																																							
																																																							
  @override																																																							
  _MyHomePageState createState() => _MyHomePageState();																																																							
}																																																							
																																																							
class _MyHomePageState extends State {																																																							
  Widget build(BuildContext context) {																																																							
    return Scaffold(																																																							
      body: MapboxMap(																																																							
        initialCameraPosition: const CameraPosition(																																																							
            target: LatLng(35.17176088096857, 136.88817886263607),																																																							
            zoom: 13.4746),																																																							
      ),																																																							
    );																																																							
  }																																																							
}																																																							
																																																							

3.AndroidManifest.xmlを修正

mapboxアカウントページより、アクセストークンをコピーして以下に設定してください。

例)
<Application ・・・>																																																							
																																																							
<meta-data android:name="com.mapbox.token" android:value="★ここにアクセストークンを追加★" />																																																							
																																																							
</Application>																																																						

4.シークレットトークンを設定

システム環境変数を設定します。設定後はAndroid Studioを再起動してください。

※変数値にダブルクォーテーション等は不要です

変数名:SDK_REGISTRY_TOKEN

変数値:作成したシークレットトークン

5.実行結果

mapboxを用いて地図を表示することができました。

6.トラブルシューティング

筆者がつまずいたエラーについて紹介します。
・SDKのバージョンが低い mapboxを利用するには最低バージョンが20である必要があります。 build.gradleの「minSdkVersion」を以下のように修正してください。 例)
defaultConfig {																																																							
    applicationId "com.example.プロジェクト名"																																																							
    minSdkVersion 20																																																							

・エミュレータのストレージ容量が足りない

地図を読み込む際にストレージ容量が足りず、エラーが発生しました。
その際は、以下のようにエミュレータの設定を修正してください。

1. AVDマネージャーから、使用するデバイスの詳細設定を開きます

  画面右上の以下アイコンをクリック

以下のアイコンをクリック
Show Advanced Settingsをクリック

2.Internal Storageを増やします

※筆者は4GBを設定し、問題なく動いています。

サンプルアプリケーションの実行

「mapbox_gl」パッケージは、mapboxのコミュニティが非公式に開発し、公開しているパッケージです。

基本的な地図表示機能はGoogleMapとほぼ同じです。

GoogleMapとmapboxの比較

ローカライズ

名古屋市を表示した例です。

GoogleMapは変更しておらず、デフォルトの地図となります。

mapboxは、デフォルトの言語が英語のため、カスタマイズしたスタイルを使用して日本語表記にしています。
また、デフォルトでは電車の路線図等もありません。

mapbox_glの最新リリースは2021/06/24時点で0.12.0ですが、0.11.0からバージョンを上げただけでは日本語が表示できませんでした。

日本語化する例として、mapbox_glのバージョンが0.11.0のものを挙げています。

○GoogleMap
○mapbox(mapbox_gl:0.11.0)
○GoogleMap
○mapbox(mapbox_gl:0.11.0)

地図タイプの切り替え

衛星地図に切り替えた例です。

地図生成時に指定するパラメータを変えることで、切り替えができます。

○GoogleMap
○mapbox(mapbox_gl:0.12.0)
○GoogleMap
○mapbox(mapbox_gl:0.12.0)
GoogleMap
body: GoogleMap(																																																							
  mapType: MapType.satellite,																																																							
  initialCameraPosition: _kNSK,																																																							
  onMapCreated: (GoogleMapController controller) {																																																							
    _controller.complete(controller);																																																							
  },																																																							
),																																																							
																																																							
mapbox
body: MapboxMap(																																																							
  styleString: MapboxStyles.SATELLITE_STREETS,																																																							
  initialCameraPosition: const CameraPosition(																																																							
      target: LatLng(35.17176088096857, 136.88817886263607),																																																							
      zoom: 13.4746),																																																							
),																																																							

渋滞表示

渋滞情報を地図に重畳表示した例です。

地図タイプ切り替えと同様、地図生成時のパラメータで有効にできます。

○GoogleMap
○mapbox(mapbox_gl:0.12.0)
○GoogleMap
○mapbox(mapbox_gl:0.12.0)
GoogleMap
body: GoogleMap(																																																							
  mapType: MapType.normal,																																																							
  initialCameraPosition: _kNSK,																																																							
  onMapCreated: (GoogleMapController controller) {																																																							
    _controller.complete(controller);																																																							
  },																																																							
  trafficEnabled:true ,																																																							
),																																																							
mapbox
body: MapboxMap(																																																							
  styleString: MapboxStyles.SATELLITE_STREETS,																																																							
  initialCameraPosition: const CameraPosition(																																																							
      target: LatLng(35.17176088096857, 136.88817886263607),																																																							
      zoom: 13.4746),																																																							
),																																																							
																																																							

画面から緯度経度取得

タップした位置の緯度経度を取得する例です。

地図生成時に設定したメソッドに、緯度経度を引数にコールバックされます。

○GoogleMap
○mapbox(mapbox_gl:0.12.0)
○GoogleMap
○mapbox(mapbox_gl:0.12.0)
GoogleMap
body: GoogleMap(																																																							
  mapType: MapType.normal,																																																							
  initialCameraPosition: _kNSK,																																																							
  onMapCreated: (GoogleMapController controller) {																																																							
    _controller.complete(controller);																																																							
  },																																																							
  trafficEnabled:true ,																																																							
  onTap: (LatLng latlng){																																																							
    showDialog(																																																							
      context: context,																																																							
      builder: (BuildContext context) {																																																							
        return AlertDialog(																																																							
          title:  Text("onTapイベント"),																																																							
          content:  Text("${latlng.toString()} "),																																																							
          actions: [																																																							
            FlatButton(																																																							
              child: Text("OK"),																																																							
              onPressed: () => Navigator.pop(context),																																																							
            ),																																																							
          ],																																																							
      );																																																							
    },																																																							
    );																																																							
  },																																																							
),																																																							
 

mapbox

body: MapboxMap(																																																							
  styleString: MapboxStyles.TRAFFIC_DAY,																																																							
  initialCameraPosition: const CameraPosition(																																																							
      target: LatLng(35.17176088096857, 136.88817886263607),																																																							
      zoom: 13.4746),																																																							
  onMapClick: (point, coordinates) {																																																							
    showDialog(																																																							
        context: context,																																																							
        builder: (context) {																																																							
          return AlertDialog(																																																							
            title: Text("onMapClickイベント"),																																																							
            content: Text(coordinates.toString()),																																																							
            actions: [																																																							
              FlatButton(																																																							
                  onPressed: () => Navigator.pop(context),																																																							
                  child: Text("OK"))																																																							
            ],																																																							
          );																																																							
        });																																																							
  },																																																							
),																																																							

マーカー表示

任意地点にマーカーを追加した例です。

GoogleMapは地図生成時のコンストラクタで指定可能です。
mapboxでは地図生成後のコントローラークラス「MapboxMapController」からメソッドをコールして追加します。
また、マーカーは任意の画像に差し替えることが可能です。

○GoogleMap
○mapbox(mapbox_gl:0.12.0)
GoogleMap
body: GoogleMap(																																																							
  mapType: MapType.normal,																																																							
  initialCameraPosition: _kNSK,																																																							
  onMapCreated: (GoogleMapController controller) {																																																							
																																																							
  },																																																							
  trafficEnabled:true ,																																																							
  onTap: (LatLng latlng){																																																							
  },																																																							
  markers: {																																																							
    Marker(markerId: MarkerId("nagoya") ,position: LatLng(35.184910766826086, 136.8996468623372)),																																																							
    Marker(markerId: MarkerId("nsk") ,position: LatLng(35.17176088096857, 136.88817886263607)),																																																							
  },																																																							
),																																																							
mapbox
MapboxMapController? mapController;																																																							
																																																							
void _onMapCreated(MapboxMapController controller) {																																																							
  mapController = controller;																																																							
}																																																							
																																																							
Widget build(BuildContext context) {																																																							
  return Scaffold(																																																							
    body: MapboxMap(																																																							
      onMapCreated: _onMapCreated,																																																							
      styleString: MapboxStyles.MAPBOX_STREETS,																																																							
      initialCameraPosition: const CameraPosition(																																																							
          target: LatLng(35.17176088096857, 136.88817886263607),																																																							
          zoom: 13.4746),																																																							
      onMapClick: (point, coordinates) {																																																							
        mapController?.addSymbol(SymbolOptions(																																																							
          geometry: coordinates,																																																							
          iconImage: "marker-15",																																																							
          iconSize: 5,																																																							
        ));																																																							
      },																																																							
    ),																																																							
  );																																																							
}																																																							

図形描画

地図上に、円や線分、矩形を描画した例です。

追加はマーカーとほぼ同じ方法です。
パラメータとして、色や太さなどを指定できます。

○GoogleMap
○mapbox(mapbox_gl:0.12.0)
○GoogleMap
○mapbox(mapbox_gl:0.12.0)
GoogleMap
body: GoogleMap(																																																							
  mapType: MapType.normal,																																																							
  initialCameraPosition: _kNSK,																																																							
  onMapCreated: (GoogleMapController controller) {																																																							
  },																																																							
  trafficEnabled:true ,																																																							
  onTap: (LatLng latlng){																																																							
  },																																																							
  markers: {																																																							
    Marker(markerId: MarkerId("nagoya") ,position: LatLng(35.184910766826086, 136.8996468623372)),																																																							
    Marker(markerId: MarkerId("nsk") ,position: LatLng(35.17176088096857, 136.88817886263607)),																																																							
  },																																																							
  polylines: {																																																							
    Polyline(																																																							
        polylineId: PolylineId("nagoya-nsk") ,																																																							
        points: [LatLng(35.184910766826086, 136.8996468623372),LatLng(35.17176088096857, 136.88817886263607)] ,																																																							
        color: Color(0xFF0000FF),																																																							
    ),																																																							
  },																																																							
  polygons: {																																																							
    Polygon(																																																							
        polygonId: PolygonId("nagoya-nsk"),																																																							
        points: [																																																							
          LatLng(35.184910766826086, 136.8996468623372),																																																							
          LatLng(35.184910766826086, 136.88817886263607),																																																							
          LatLng(35.17176088096857, 136.88817886263607),																																																							
          LatLng(35.17176088096857, 136.8996468623372),																																																							
        ],																																																							
        fillColor: Color(0x00000000),																																																							
        strokeColor: Color(0xFF00FF00,)																																																							
    ),																																																							
  },																																																							
  circles: {																																																							
    Circle( circleId: CircleId("nagoya") ,center: LatLng(35.184910766826086, 136.8996468623372) , radius: 1000, strokeColor: Color(0xFFFF0000)),																																																							
    Circle( circleId: CircleId("nsk"), center:LatLng(35.17176088096857, 136.88817886263607) , radius: 500, strokeColor: Color(0xFFFF0000)),																																																							
  },																																																							
),																																																							
mapbox
MapboxMapController? mapController;																																																							
																																																							
void _onMapCreated(MapboxMapController controller) {																																																							
  mapController = controller;																																																							
}																																																							
																																																							
Widget build(BuildContext context) {																																																							
  return Scaffold(																																																							
    body: MapboxMap(																																																							
        onMapCreated: _onMapCreated,																																																							
        styleString: MapboxStyles.MAPBOX_STREETS,																																																							
        initialCameraPosition: const CameraPosition(																																																							
            target: LatLng(35.17176088096857, 136.88817886263607),																																																							
            zoom: 13.4746),																																																							
        onMapClick: (point, coordinates) {																																																							
          mapController?.addCircle(CircleOptions(																																																							
            circleRadius: 170,																																																							
            circleStrokeColor: "#ff0000",																																																							
            circleStrokeWidth: 7,																																																							
            circleOpacity: 0,																																																							
            geometry: LatLng(35.184910766826086, 136.8996468623372),																																																							
          ));																																																							
          mapController?.addCircle(CircleOptions(																																																							
            circleRadius: 90,																																																							
            circleStrokeColor: "#ff0000",																																																							
            circleStrokeWidth: 7,																																																							
            circleOpacity: 0,																																																							
            geometry: LatLng(35.17176088096857, 136.88817886263607),																																																							
          ));																																																							
          mapController?.addLine(LineOptions(																																																							
            geometry: [																																																							
              LatLng(35.184910766826086, 136.8996468623372),																																																							
              LatLng(35.17176088096857, 136.8996468623372),																																																							
              LatLng(35.17176088096857, 136.88817886263607),																																																							
              LatLng(35.184910766826086, 136.88817886263607),																																																							
              LatLng(35.184910766826086, 136.8996468623372),																																																							
            ],																																																							
            lineColor: "#00ff00",																																																							
            lineWidth: 7,																																																							
          ));																																																							
          mapController?.addLine(LineOptions(																																																							
            geometry: [																																																							
              LatLng(35.184910766826086, 136.8996468623372),																																																							
              LatLng(35.17176088096857, 136.88817886263607),																																																							
            ],																																																							
            lineColor: "#0000ff",																																																							
            lineWidth: 7,																																																							
          ));																																																							
        }),																																																							
  );																																																							
}																																																							

カスタムスタイル

地図のスタイルをカスタマイズした例です。

GoogleMapでは、Styling WizardというWebサービスがあり、ブラウザ上でスタイルをカスタマイズしてjsonとして出力し、Flutterアプリケーションで使用することができます。

https://mapstyle.withgoogle.com/

以下の5種類の基本テーマを選択可能です。

また、これらをベースに対象物のレイヤーごとに細かく色を変えるといった設定も可能です。
・Standard
・Silver
・Retro
・Dark
・Night
・Aubergine

mapboxでは、Mapbox StudioというWebサービスがあり、ブラウザ上でスタイルをカスタマイズしてStyle URLとして出力し、Flutterアプリケーションで使用することができます。

https://studio.mapbox.com/

また、MapboxStylesクラスに以下パラメータが用意されており、地図生成時のコードに指定することで切り替えが可能です。 
・DARK
・LIGHT
・MAPBOX_STREETS
・OUTDOORS
・SATELLITE
・SATELLITE_STREETS
・TRAFFIC_DAY
・TRAFFIC_NIGHT

○GoogleMap(Night Theme)
○mapbox(mapbox_gl:0.12.0、DARK)
○GoogleMap(Night Theme)
○mapbox(mapbox_gl:0.12.0、DARK)
GoogleMap<main.dart>
import 'package:flutter/services.dart' show rootBundle;																																																							
																																																							
body: GoogleMap(																																																							
  mapType: MapType.normal,																																																							
  initialCameraPosition: _kNSK,																																																							
  onMapCreated: (GoogleMapController controller) {																																																							
    _controller.complete(controller);																																																							
    var read = rootBundle.loadString('assets/mystyle.json');																																																							
    read.then((value) => controller.setMapStyle(value));																																																							
  },																																																							
GoogleMap<pubspec.yaml>
flutter:																																																							
  assets:																																																							
    - assets/mystyle.json																																																							
																																																							
GoogleMap<assets/mystyle.json>
[																																																							
  {																																																							
    "elementType": "geometry",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#242f3e"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "elementType": "labels.text.fill",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#746855"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "elementType": "labels.text.stroke",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#242f3e"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "featureType": "administrative.locality",																																																							
    "elementType": "labels.text.fill",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#d59563"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "featureType": "poi",																																																							
    "elementType": "labels.text.fill",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#d59563"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "featureType": "poi.park",																																																							
    "elementType": "geometry",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#263c3f"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "featureType": "poi.park",																																																							
    "elementType": "labels.text.fill",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#6b9a76"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "featureType": "road",																																																							
    "elementType": "geometry",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#38414e"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "featureType": "road",																																																							
    "elementType": "geometry.stroke",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#212a37"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "featureType": "road",																																																							
    "elementType": "labels.text.fill",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#9ca5b3"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "featureType": "road.highway",																																																							
    "elementType": "geometry",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#746855"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "featureType": "road.highway",																																																							
    "elementType": "geometry.stroke",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#1f2835"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "featureType": "road.highway",																																																							
    "elementType": "labels.text.fill",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#f3d19c"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "featureType": "transit",																																																							
    "elementType": "geometry",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#2f3948"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "featureType": "transit.station",																																																							
    "elementType": "labels.text.fill",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#d59563"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "featureType": "water",																																																							
    "elementType": "geometry",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#17263c"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "featureType": "water",																																																							
    "elementType": "labels.text.fill",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#515c6d"																																																							
      }																																																							
    ]																																																							
  },																																																							
  {																																																							
    "featureType": "water",																																																							
    "elementType": "labels.text.stroke",																																																							
    "stylers": [																																																							
      {																																																							
        "color": "#17263c"																																																							
      }																																																							
    ]																																																							
  }																																																							
]																																																							
																																																							
mapbox
body: MapboxMap(																																																							
  styleString: MapboxStyles.DARK,																																																							
  initialCameraPosition: const CameraPosition(																																																							
      target: LatLng(35.17176088096857, 136.88817886263607),																																																							
      zoom: 13.4746),																																																							
),																																																							

GoogleMapでは、上記よりもより細かい対象物の単位でカスタマイズが可能なクラウドベースのスタイル作成機能も存在しますが、現状の「google_map_flutter」では未対応となっています。
https://console.cloud.google.com/google/maps-apis/client-styles

一方で、スタイルのカスタマイズについてはmapboxの方が自由度があります。
mapboxでは、「Mapbox Studio」というカスタマイズマップを作成するための、アプリケーションが用意されています。
https://docs.mapbox.com/studio-manual/guides/

フォントや文字の大きさなどの細かい調整や、新たに独自のレイヤを追加するなど様々なことが可能です。
自身の用途に合わせて地図をカスタマイズしやすいという点では、mapboxにメリットがあります。
https://docs.mapbox.com/help/tutorials/?product=Mapbox+Studio

まとめ

GoogleMapとmapboxを比較すると、基本的なAPIはほとんど差異がなく、似たコードで同様のことが行えます。
地図を使った簡単な表示であれば、GoogleMapがお手軽でした。
一方、見た目や表示内容をカスタマイズする場合は、カスタマイズの幅が大きいmapboxがよいと感じました。

次回のコラムでは、
今回表示した地図と、GoogleFlutterで作成した画面を重ね合わせて、実際のカーナビのような画面を作成していきます。
作成した画面同士の切り替えや、配置した釦による地図の操作を紹介する予定です。

お問い合わせ

名古屋本社

東京本社

【受付時間】9:00~18:00

pagetop

お客様のお悩み承ります。