AndroidのGPSから現在地を取得しGoogle Map上で表示するFlutterアプリを作る

2021-05-23

AndroidのGPSから現在地を取得しGoogle Map上で表示するFlutterアプリ

モチベーションとしては今いる場所や、近所にある飲食店(特にカレー屋やラーメン屋)を探したいと考えています。

Google検索で探すと範囲が広すぎて近くの店を探すのが大変です。 Google Mapのアプリから探すにしても検索結果には、その店の評価やコメントが嫌でも入ってきます。

私はかねてより、自分がこれから金を払って食べる料理を決める際に余計な先入観を持ちたくないと考えています。 ふらっと出掛けて店の外見も関係なく、どんな料理が食べられるのか、美味しそうな料理かどうかが大切だと思います。

人気店やコメントが多い店だけが美味い料理を食べることができるでしょうか。 駅から近くて人がたくさん来る機会が多ければ、人気が出たりコメントも増えるでしょう。 (当然、美味しい店に人が集まるのも理解しているつもりです)

しかし、オープンしたての店はどうですか?本当に美味しい料理を出すかもしれないのに、コメントや評価が少ないからと避けていませんか?

そうです。店の場所と、何を出す店かが分かるだけで良いと考えています。 究極、店の場所と名前、料理の写真があれば良いのです。

コーディング

FlutterでGoogle Mapを表示するアプリを作っています。 今回は、上のような野望を叶えるアプリ開発の第一歩です。 GPSから現在値を取得していきます。

AndroidManifest.xml

Androidの端末でGPSを使用する場合、Permissionの設定が必要となります。

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

ここで設定したPermissionがGoogle Playで公開する際に「使用許可を求める機能」として表示されます。

location パッケージをプロジェクトに追加する。

location FlutterでAndroidやiOS等のGPSから現在値を取得するのを助けてくれるライブラリです。 ライセンスがMITなのもありがたい。

flutter pub add location

main.dart

現在地を取得する関数を書いていきます。

現在地を取得するのはこう書きます。 取得に失敗することもあるので失敗したときはNullを返します。

var location = new Location();
try {
  currentLocation = await location.getLocation();
} on Exception {
  currentLocation = Null as LocationData;
}

取得した現在地にGoogle Mapのカメラを移動させるコードを書きます。 target:に座標を渡しています。

double currentlat = currentLocation.latitude!;
double currentlong = currentLocation.longitude!;

controller.animateCamera(CameraUpdate.newCameraPosition(
  CameraPosition(
    bearing: 0,
    target: LatLng(currentlat, currentlong),
    zoom: 17.0,
  ),
));

上のコード絵は、Location.latitudeとLocation.longitudeがNull safetyで作られており LatLngに入れるときの方と一致しない(double?とdouble)です。

せっかくnullを許可しない型で定義してくれていますが、末尾に!を付けてNullableとして許可しています。 この手の場合、どう処理をするのが良いんでしょうね。

これらの機能を_currentLocation()として定義します。 画面右下にFloatingButtonを追加し先程定義した関数を呼び出しましょう。

build関数等から呼び出してあげれば、Buttonを押したら指定したGPS座標の位置に移動できます。

floatingActionButton: FloatingActionButton.extended(
  onPressed: _currentLocation,
  label: Text('CurrentLocation'),
  icon: Icon(Icons.directions_boat),
),

全文

main.dartを書き換えるならこのようにすれば良いです。

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.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<MapSample> createState() => MapSampleState();
}

class MapSampleState extends State<MapSample> {
  Completer<GoogleMapController> _controller = Completer();

  static final CameraPosition _kGooglePlex = CameraPosition(
    target: LatLng(34.652499, 135.506306),
    zoom: 13.0000,
    bearing: 0.0,
    tilt: 0.0,
  );

  static final LatLng _kMapCenter1 = LatLng(34.652499, 135.506306);
  static final LatLng _kMapCenter2 = LatLng(34.64000, 135.49000);

  Set<Marker> _createMarker() {
    return {
      Marker(
          markerId: MarkerId("marker_1"),
          position: _kMapCenter1,
          icon: BitmapDescriptor.defaultMarkerWithHue(5.4),
          infoWindow: InfoWindow(title: "腐ったみかん", snippet: '俺は腐ったみかんじゃない')),
      Marker(
        markerId: MarkerId("marker_2"),
        position: _kMapCenter2,
      ),
    };
  }

  void _currentLocation() async {
    final GoogleMapController controller = await _controller.future;
    LocationData currentLocation;
    var location = new Location();
    try {
      currentLocation = await location.getLocation();
    } on Exception {
      currentLocation = Null as LocationData;
    }

    double currentlat = currentLocation.latitude!;
    double currentlong = currentLocation.longitude!;

    controller.animateCamera(CameraUpdate.newCameraPosition(
      CameraPosition(
        bearing: 0,
        target: LatLng(currentlat, currentlong),
        zoom: 17.0,
      ),
    ));
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: GoogleMap(
        mapType: MapType.normal,
        markers: _createMarker(),
        initialCameraPosition: _kGooglePlex,
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },
        myLocationEnabled: true,
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: _currentLocation,
        label: Text('CurrentLocation'),
        icon: Icon(Icons.directions_boat),
      ),
    );
  }

}

実行結果

Android エミュレータでGPSを動かしてみます。 実機でやっても良いのですが、どの辺に住んでいるのかバレちゃうのであまり良くないです。

Androidエミュレータと一緒に下のようなメニューがあると思います。

「・・・」ボタンを押すと、Extended controlsが開きます。

Locationからエミュレータ上でGPSを試すことができます。

大阪に居た頃通っていたラーメン荘の住所を表示しています。 油が美味い二郎インスパイアの店なのです。

設定したい地点を設定することができたら、SET LOCATIONをクリックして確定します。

これで準備はOKです。

CurrentLocationボタンを押すとアプリ上でも同じ座標に移動します。