【flutter(location)】位置情報の取得・距離計算


表題の件、やってみた。

### テスト環境の整備

1. 基本は公式を見て設定すればOK
2. 公式の設定だけではエラーが出たので追加（見逃しただけかも）
    Android の場合
　　　kotlin_version が最新じゃないといけないっぽい
　　　Kotlin_version : 1.9.0


### コード

エミュレーターを起動して、"距離を計算する！"をクリックすればデバッグコンソールに計算結果が出てくる。

#### main
``` dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:location_sample/location.dart';



void main() {
	runApp(
		const ProviderScope(
      child: MaterialApp(home: MyApp(),)
		),
	);
}



class MyApp extends ConsumerStatefulWidget {
	const MyApp({super.key});

	@override
	ConsumerState<ConsumerStatefulWidget> createState() => _MyAppState();
}

class _MyAppState extends ConsumerState<MyApp> {

	@override
	Widget build(BuildContext context) {

    bool isGetLocate = ref.watch( isGetLocateProvider );

    if ( isGetLocate ) {
      return Center(
        child: TextButton(
          child     : const Text( "距離を計算する！！" ),
          onPressed : () {
            final myLocateData = ref.watch( isLocateProvider )!;
            double  lon1 = myLocateData.longitude!;
            double  lat1 = myLocateData.latitude!;
            double  lon2 = 130.0;
            double  lat2 = 45.0;
            double  dist = calcDistance( lon1, lat1, lon2, lat2 );
            debugPrint( "x1 : $lon1    y2 : $lat1" );
            debugPrint( "x2 : $lon2    y2 : $lat2" );
            debugPrint( "dist : $dist" );
          },
        )
      );
    } else { return const Placeholder(); }

	}
}

```

#### location.dart
```dart

// flutter pub run build_runner build --delete-conflicting-outputs

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

import 'package:location/location.dart';

part 'location.freezed.dart';



// 
// State
// 
@freezed
class LocateState with _$LocateState {
	factory LocateState({
		
		required				Location			location,
		@Default(null)  LocationData? locateData,
		@Default(false)	bool					isGetLocation

	}) = _LocateState;

}


// 
// Notifier
// 
class LocationCnrl extends AsyncNotifier<LocateState> {

// 初期化
	@override
	Future<LocateState> build() async {

		Location			location		= Location();
		location.enableBackgroundMode( enable: true );
	
		bool							serviceEnabled;
		PermissionStatus	permissionGranted;

		// 位置情報使える？
		serviceEnabled = await location.serviceEnabled();
		if ( !serviceEnabled ) {
			serviceEnabled = await location.requestService();
			if ( !serviceEnabled ) {
				debugPrint( "位置情報が利用できません。。。" );
				return LocateState(
					location			: location,
					locateData		: null,
					isGetLocation	: false
				);
			}
		}

		// アプリに許可してる？
		permissionGranted = await location.hasPermission();
		if ( permissionGranted == PermissionStatus.denied ) {
			permissionGranted = await location.requestPermission();
			if ( permissionGranted != PermissionStatus.granted ) {
				debugPrint( "このアプリに対して位置情報の利用許可がおりていません。。。" );
				return LocateState(
					location		: location,
					locateData	: null,
					isGetLocation	: false
				);
			}
		}
		
		debugPrint( "正常に位置情報を取得しました！" );
		return LocateState(
			location			: location,
			locateData		: await location.getLocation(),
			isGetLocation	: true
		);

	}

// =============================================================================
// ログイン関係
// =============================================================================

// 変数の更新
	void updateState() async
	{

		state.when(
			error   : (e,s) => state = AsyncValue.error(e,s),
			loading : ()    => state = const AsyncValue.loading(),
			data    : (tmp) {
				tmp.location.onLocationChanged.listen( ( LocationData currentLocation ) {
					tmp	= tmp.copyWith( locateData: currentLocation );
				});
			}
		);
	}

}


// 
// Provider
// 
final userProvider = AsyncNotifierProvider<LocationCnrl, LocateState>(() {
	return LocationCnrl();
});

// 位置情報データ
final isLocateProvider = Provider<LocationData?>( ( ref ) =>
	ref.watch( userProvider ).when(
		error   : (e,s)   => null,
		loading : ()      => null,
		data    : (data)  => data.locateData
	)
);

// 位置情報はとれてる？
final isGetLocateProvider = Provider<bool>( ( ref ) =>
	ref.watch( userProvider ).when(
		error   : (e,s)   => false,
		loading : ()      => false,
		data    : (data)  => true
	)
);



// 
// function
// 

double calcDistance( double lon1, double lat1, double lon2, double lat2 ) {

	double x1	= lon1 / 180 * 3.14;
	double y1	= lat1 / 180 * 3.14;
	double x2	= lon2 / 180 * 3.14;
	double y2	= lat2 / 180 * 3.14;


	return 6378.137 * acos(
		( sin( y1 ) * sin( y2 ) ) +	( cos( y1 ) * cos( y2 ) * cos( x2 - x1 ) )
	);
}


```