FlutterのGeoLocationで位置情報を取ってみる

---
# :book: Flutterの記事を整理し本にしました :book:
https://zenn.dev/kazutxt/books/flutter_practice_introduction

* <font color="red"><b>本稿の記事を含む様々な記事を体系的に整理し本にまとめました</b></font>
* 今後はこちらを最新化するため、<font color="red"><b>最新情報はこちらをご確認ください</b></font>
* 20万文字を超える超大作になっています!!

---

## まとめ記事
* [Flutter系の記事のまとめ](https://qiita.com/kazutxt/items/524acb1c134015682ccf)

# はじめに
* Flutterは位置情報も簡単にとれるようです。GoogleMapのAPIと組み合わせるとなお良しらしいですが、今回は位置情報止まり :sweat: 


# 事前準備

## パッケージインストール

```yaml:pubspec.yml
geolocator: ^7.0.3
```

## iOS

```xml:ios/Runner/info.plist
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when open.</string>
```

## Android

位置情報に関する権限には、`ACCESS_FILE_LOCATION`と`ACCESS_COARSE_LOCATION`がありますが、前者が詳細な位置。後者が大まかな位置情報となり、このパッケージでは、後者だと動かない場合があるようなので、詳細な位置情報を取得できる権限を要求しています。

```xml:android/app/src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
```

# 実装
Geolocatorを使って、現在の緯度・経度・高度の取得や2点間の距離、方位を取得することができます。

```dart:main.dart
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
void main() {
  runApp(MyApp());
}
class MyApp extends StatelessWidget {
  @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, this.title}) : super(key: key);
  final String? title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
  String _location = "no data";
  Future<void> getLocation() async {
    // 現在の位置を返す
    Position position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.high);
    // 北緯がプラス。南緯がマイナス
    print("緯度: " + position.latitude.toString());
    // 東経がプラス、西経がマイナス
    print("経度: " + position.longitude.toString());
    // 高度
    print("高度: " + position.altitude.toString());
    // 距離をメートルで返す
    double distanceInMeters =
        Geolocator.distanceBetween(35.68, 139.76, -23.61, -46.40);
    print(distanceInMeters);
    // 方位を返す
    double bearing = Geolocator.bearingBetween(35.68, 139.76, -23.61, -46.40);
    print(bearing);
    setState(() {
      _location = position.toString();
    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title!),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '$_location',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
          onPressed: getLocation, child: Icon(Icons.location_on)),
    );
  }
}
```


`Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high)`で、現在の位置情報を取得しています。

その後positionから情報を取得します
* position.latitude // 緯度
* position.longitude // 軽度
* position.altitude // 高度

2点間の距離や方位を返すこともできます。
2点間の緯度経度をそれぞれ指定します。
* Geolocator.distanceBetween(35.68, 139.76, -23.61, -46.40); // 距離
* Geolocator.bearingBetween(35.68, 139.76, -23.61, -46.40); // 方位


距離はメートル、方位は初期方位を返します。


# 動作確認

初回のみ位置情報のアクセス許可のポップアップが出ることがあります。

## 東京を指定
![pic1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259228/c5c65cc9-54b0-5369-6758-f7cd05690950.png)


```sh:result.sh
I/flutter (13662): 緯度: 35.6803983
I/flutter (13662): 経度: 139.7690167
I/flutter (13662): 高度: 0.036667554410087067
```

## サンパウロを指定
![pic2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/259228/e2333773-0384-08e4-ac2a-036b1f9da7db.png)

```sh:result.sh
I/flutter (13662): 緯度: -23.6104067
I/flutter (13662): 経度: -46.4085333
I/flutter (13662): 高度: 0.05080430969328764
```


## 東京とサンパウロの距離/方位

```sh:result.sh
I/flutter (13662): 18568551.931076292 // メートル
I/flutter (13662): 25.5127264183883 // 初期方位
```