51
45

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Flutter+Google Maps APIで現在地表示

Last updated at Posted at 2019-05-28

はじめに

FlutterでGoogle Maps APIを用いて現在地を表示するのに結構苦労したのでメモ代わりに残しておこうと思います。現在地取得、現在地表示についてを見たい方はここを押してください。

APIキーの取得

APIキー取得まではGoogle公式Flutter用Google Mapsプラグインを一通り使ってみたを参考にしてください。

Google Mapsを表示

pubspec.yamlにgoogle_maps_flutterを追加する

pubspec.yaml
dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2
  google_maps_flutter: ^0.5.13 // 追加


dev_dependencies:
  flutter_test:
    sdk: flutter

google_maps_flutterを追加し、flutter pub getする。

Android用の設定

android/app/src/main/AndroidManifest.xmlに以下を追記する

android/app/src/main/AndroidManifest.xml
    <application
        android:name="io.flutter.app.FlutterApplication"
        android:label="flutter_maps"
        android:icon="@mipmap/ic_launcher">
        <meta-data android:name="com.google.android.geo.API_KEY" // 追加
            android:value="取得したAPIキー"/>                       // 追加
        <activity
            android:name=".MainActivity"
       ...

iOS用の設定

ios/Runner/Info.plistを開いて以下を追記します

ios/Runner/Info.plist
<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
</array>
	<key>UIViewControllerBasedStatusBarAppearance</key>
	<false/>
<key>io.flutter.embedded_views_preview</key> // 追加
<string>YES</string>                         // 追加

ios/Runner/AppDelegate.mに以下を追記します

ios/Runner/AppDelegate.m
#include "AppDelegate.h"
#include "GeneratedPluginRegistrant.h"
// Add the GoogleMaps import.
#import "GoogleMaps/GoogleMaps.h" // 追加

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  [GMSServices provideAPIKey:@"取得したAPIキー"];                      // 追加
  [GeneratedPluginRegistrant registerWithRegistry:self];
  // Override point for customization after application launch.
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

main.dart, google_maps.dartのコード(コピペでOK)

lib/main.dart
import 'package:flutter/material.dart';
import 'google_maps.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 Maps',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: GoogleMaps(),
    );
  }
}
lib/google_maps.dart
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

class GoogleMaps extends StatefulWidget {
  @override
  _GoogleMapsState createState() => _GoogleMapsState();
}

class _GoogleMapsState extends State<GoogleMaps> {
  Completer<GoogleMapController> _controller = Completer();

  void _onMapCreated(GoogleMapController controller) {
    _controller.complete(controller);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("Flutter Maps"),
        ),
        body: GoogleMap(
          onMapCreated: _onMapCreated,
          initialCameraPosition: CameraPosition(  // 最初のカメラ位置
            target: LatLng(34.643208, 134.997586),
            zoom: 17.0,
          ),
        ),
      ),
    );
  }
}

スクリーンショット

Android

スクリーンショット 2019-05-28 14 53 17 ※実機の関係でこの記事ではスクリーンショットはAndroidだけとします。

現在地表示

pubspec.yamlにlocationを追加します

pubspec.yaml
dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2
  google_maps_flutter: ^0.5.13
  location: ^2.3.5 // 追加

locationを追加し、flutter pub getする。

Android用の設定

android/build.gradleを開いて以下に変更します

android/build.gradle
buildscript {
    repositories {
        google()
        jcenter()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:3.3.0' // 変更
        classpath 'com.google.gms:google-services:4.2.0' // 追加
    }
}

android/gradle.propertiesに以下を追記します

android/gradle.properties
android.enableJetifier=true   // 追加
android.useAndroidX=true      // 追加
org.gradle.jvmargs=-Xmx1536M

android/app/src/main/AndroidManifest.xmlに以下を追記します

android/app/src/main/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.butachin.flutter_maps">

    <uses-permission android:name="android.permission.INTERNET"/>              // 追加
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> // 追加

    <!-- io.flutter.app.FlutterApplication is an android.app.Application that
         calls FlutterMain.startInitialization(this); in its onCreate method.
         In most cases you can leave this as-is, but you if you want to provide
         additional functionality it is fine to subclass or reimplement
         FlutterApplication and put your custom class here. -->
    <application
        android:name="io.flutter.app.FlutterApplication"
        android:label="flutter_maps"

android.permission.ACCESS_FINE_LOCATIONを追加することによって位置情報の権限を付与することができる。android.permission.INTERNETは追加しなくても良いと思う。

iOS用の設定

ios/Runner/Info.plistを開いて以下を追記します

ios/Runner/Info.plist
	</array>
	<key>UIViewControllerBasedStatusBarAppearance</key>
	<false/>
	<key>io.flutter.embedded_views_preview</key>
    <string>YES</string>
    <key>NSLocationAlwaysUsageDescription</key>             // 追加
    <string>Your location is required for this app</string> // 追加
    <key>NSLocationWhenInUseUsageDescription</key>          // 追加
    <string>Your location is required for this app</string> // 追加
</dict>
</plist>

google_maps.dartの変更, 追加

lib/google_maps.dart
class _GoogleMapsState extends State<GoogleMaps> {
  LocationData currentLocation;                                              // 追加
  // StreamSubscription<LocationData> locationSubscription;

  Location _locationService = new Location();                                 // 追加
  String error;                                                               // 追加

  @override                                                                   // 追加
  void initState() {                                                          // 追加
    super.initState();                                                        // 追加

    initPlatformState();                                                      // 追加
    _locationService.onLocationChanged().listen((LocationData result) async { // 追加
      setState(() {                                                           // 追加
        currentLocation = result;                                             // 追加
      });                                                                     // 追加
    });                                                                       // 追加
  }                                                                           // 追加

  Completer<GoogleMapController> _controller = Completer();

  void _onMapCreated(GoogleMapController controller) {
  ...
  initialCameraPosition: CameraPosition(
            target: LatLng(currentLocation.latitude, currentLocation.longitude), // 緯度経度を取得したものに変更
            zoom: 17.0,
 ...
  void initPlatformState() async {
    LocationData myLocation;
    try {
      myLocation = await _locationService.getLocation();
      error = "";
    }on PlatformException catch(e){
      if(e.code == 'PERMISSION_DENITED')
        error = 'Permission denited';
      else if(e.code == 'PERMISSION_DENITED_NEVER_ASK')
        error = 'Permission denited - please ask the user to enable it from the app settings';
      myLocation = null;
    }
    setState(() {
      currentLocation = myLocation;
    });
  }
}

initPlatformState()は全てコピペで追加してください。

スクリーンショット

Android

スクリーンショット 2019-05-28 14 52 54

このままのコードだと、一瞬ですがこの赤い画面が表示されると思います。これは現在地を取得できていないよというエラーなので取得するまで待つようにしたいと思います。

※もしこの画面がずっと出ていたら、AndroidならAndroidmanifest.xmlのandroid.permission.ACCESS_FINE_LOCATIONが、iOSならNSLocationWhenInUseUsageDescription, NSLocationAlwaysUsageDescriptionがうまく反映されていないかもしれないです。再起動したりpubspec.lockを消してpub getし直したりしてみると直るかも。ちなみに私はどうしても権限が付与できなくて、GitHubにあげたコードをCloneしてきたら動きました。

google_maps.dartに追加

lib/google_maps.dart
@override
  Widget build(BuildContext context) {
    if (currentLocation == null) {          // 追加
      return Center(                        // 追加
        child: CircularProgressIndicator(), // 追加
      );                                    // 追加
    } else {                                // 追加
      return MaterialApp(

上記を追加することにより、赤い画面を出すことなく現在地を表示することができます。

まとめ

今回はFlutterの現在地を取得する記事があまりなかったため調べて実装したことをメモ程度に書きました。Flutterを始めて、Google Maps APIを触ってみようかなくらいの人の助けになれば嬉しいです。

ソースコード

参考

Google公式Flutter用Google Mapsプラグインを一通り使ってみた

51
45
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
51
45

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?