[Flutter] Geolocatorを使用して現在位置情報を取得する方法

# 概要

Flutterを運用して5ヶ月が経ちました。
3ヶ月前から弊社ではFlutterが普及しだし、エンジニア４人が全てFlutterをかけるようになってきました。現在は自社アプリの新機能追加とアーキテクチャの導入を頑張っているという感じです。

今回は自社アプリで位置情報を取得する必要があったので、何かライブラリないかなと調べてみたら良さげなものがあったのと、導入にちょっと時間がかかったのと、単純に現在位置だけを返すだけのソースコードがあまりなかったのでその共有をします。

# 今回やること
iOS実機で現在位置情報を `緯度(Latitude)` `経度(Longitude)` で取得する（Androidはライブラリ通りでうまくいくので特に記載はしない）

# 環境

## iPhone/iOS
iPhone XR `12.4`

## Flutter
Flutter `1.9.1`
Dart    `2.3.0`

## ライブラリ

[geolocator](https://pub.dev/packages/geolocator) `5.1.3`

## 導入

### １.  `pubspec.yaml` に記載してpub get

お約束ですね

 ```pudspec.yaml
 dependencies:
    geolocator: ^5.1.3
 ```

### ２. `ios/Runner/info.plist` にpermissionを記載する

[iOS doesn't ask for Location permissions](https://github.com/BaseflowIT/flutter-geolocator/issues/172)で記載されているエラーが発生しているので、どうも `info.plist` に記載する必要があるっぽいので以下のように編集します。


```info.plist
...
<dict>
	<key>NSLocationAlwaysUsageDescription</key>
	<string>Your location is required for this app</string>
	<key>NSLocationWhenInUseUsageDescription</key>
	<string>Your location is required for this app</string>
	<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
	<string>Your location is required for this app</string>
...
</dict>
```

### ３. 実装してみる

```location.dart
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';

class LocationSample extends StatefulWidget{
  @override
  _LocationSampleState createState() => _LocationSampleState();
}

class _LocationSampleState extends State<LocationSample> {
  // Location
  Position position; // Geolocator

  @override
  void initState() {
    super.initState();
    _getLocation(context);
  }

  Future<void> _getLocation(context) async {
    Position _currentPosition = await Geolocator()
        .getCurrentPosition(desiredAccuracy: LocationAccuracy.high); // ここで精度を「high」に指定している
    print(_currentPosition);
    setState(() {
      position = _currentPosition;
    });
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<GeolocationStatus>(
      future: Geolocator().checkGeolocationPermissionStatus(),
      builder: 
          (BuildContext context, AsyncSnapshot<GeolocationStatus> snapshot) {
        if (!snapshot.hasData) {
          return const Center(child: CircularProgressIndicator());
        }

        if (snapshot.data == GeolocationStatus.denied) {
          return Text(
            'Access to location denied',
            textAlign: TextAlign.center,
          );
        }

        return Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Text(
                "Location Infomation",
                style: TextStyle(
                  fontSize: 20.0
                ),
              ),
              Text("Your Current Location is :"),
              Text("${position}")
            ],
          ),
        );
      }
    );
  }
}
```

### ４. 結果

- Permission

最初にiOSの位置情報のPermissionの処理が走ります。とりあえず「このAppの使用中のみ許可」を選択しましょう。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228436/11d7762d-e081-3d59-4bb9-5b4201d59743.png" width="320px">

- Loading

許可を選択すると、位置情報の取得に数秒時間がかかります。ここではnull値が入ってきています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228436/92aa48fd-5ffa-1a1e-558b-f81d1983ac81.png" width="320px">

- Current Location

数秒後、無事現在位置が取得し、null値がLat(Latitude)とLong(Longitude)に書き換わりました。（表示されているのはオフィス周辺の情報）
その後、数秒後ごとに現在位置を取得し、返してくれるようになりました。
ライブラリを見ると取得できている緯度経度は `double` 型なので、適宜 String に加工して使えそうです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/228436/4acf1e93-7bc5-a5a9-6a4f-462a536172fb.png" width="320px">




ソースコードは以下にあります。自分の勉強も兼ねて、これから実装するコード反映させるアプリケーションを作りました。
今後はこちらに更新されていく予定です。

https://github.com/cheapthrillandwine/i-am-learning-flutter



# 補足

位置情報を取得できるライブラリはこの他に [location](https://pub.dev/packages/location)というのもあります。
ここでの導入の方法を見ると `info.plist` に Permissionを記載する記述があるので、geolocator同様に位置情報を取得するためには必須の記述のようです。
ネイティブエンジニアの方だったら常識なのかも知れないのですが、自分は初めて知りました。

まだこのライブラリを使いこなしている訳ではないので、位置情報に関してはもっと掘り下げて行きたいと思います。
あと、位置情報の精度に関しても選択ができるので、試してみるのも面白いかと思います。

#### 精度

|  | Android | iOS |
|:--|:--|:--|
| lowest | 500m | 3000m |
| low | 500m | 1000m |
| medium | 100 - 500m | 100m |
| high | 0 - 100m | 10m |
| best | 0 - 100m | ~0m |
| bestForNavigation | 0 - 100m | Optimized for navigation |