Flutterアプリケーションでデバイスの位置情報を取得するために、location
ライブラリを活用する方法を解説する。この記事では、開発環境の設定から、AndroidおよびiOSでの位置情報取得の実装手順、さらには発生したエラーの対処法までを詳しく説明する。位置情報を利用したアプリケーション開発において、必要な設定とコーディングのポイントを押さえることができる。
開発環境と検証端末
- 開発環境
- MacOS Sonoma 14.1
- Xcode – develop for iOS and macOS (Xcode 15.0.1)
- Android Studio 17.0.6
- Flutter 3.13.6
- 検証端末
- iPhone8+ iOS16.7.2
- Google Pixel 6a Android13
使用するライブラリ
location 5.0.3: https://pub.dev/packages/location
設定
Android
以下のファイルに追記
android/app/src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
記載場所については、以下の公式ドキュメントを参照。
https://developer.android.com/guide/topics/manifest/uses-permission-element
iOS
以下のファイルに追記
ios/Runner/Info.plist
<key>NSLocationWhenInUseUsageDescription</key>
<string>このアプリがバックグラウンドで位置情報を使用する理由を説明するテキスト</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>アプリが常に位置情報を使用する理由を説明するテキスト</string>
実装
アプリで位置情報を使用できるようにするためには、位置情報サービスの状態と権限状態を確認する処理を実装する必要がある。以下の手順で実装する。
- 位置情報のロジックを別ファイルで定義する。
- main.dartなどのファイルで呼び出す
1. 位置情報のロジックを別ファイルで定義する
location_manager.dart
という新しいファイルを作成し、以下のコードを追加。処理の詳細についてはコメントを参照。
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:location/location.dart';
class LocationManager {
final Location location = Location();
// 位置情報サービスが現在有効かどうか
late bool _serviceEnabled;
// アプリに位置情報へのアクセス権限が与えられているか
late PermissionStatus _permissionGranted;
// 現在の位置情報
LocationData? _currentLocationData;
// LocationManagerのシングルトンインスタンスを作成
static final LocationManager _instance = LocationManager._internal();
factory LocationManager() {
return _instance;
}
// privateなコンストラクタ
LocationManager._internal();
/*
位置情報サービスを初期化する処理
*/
Future<void> initLocationService() async {
try {
// 位置情報サービスが現在有効かどうかを確認
_serviceEnabled = await location.serviceEnabled();
if (!_serviceEnabled) {
// サービスが無効の場合、ユーザーに位置情報サービスを有効にするように要求
_serviceEnabled = await location.requestService();
if (!_serviceEnabled) {
throw Exception('Location services are disabled.');
}
}
// アプリに位置情報へのアクセス権限が与えられているかをチェック
_permissionGranted = await location.hasPermission();
if (_permissionGranted == PermissionStatus.denied) {
// 権限が拒否されている場合、ユーザーに位置情報へのアクセス権限を要求
_permissionGranted = await location.requestPermission();
if (_permissionGranted != PermissionStatus.granted) {
throw Exception('Location permissions are denied');
}
}
// 現在の位置情報を取得
_currentLocationData = await location.getLocation();
} catch (e) {
// 例外をキャッチしてログに記録するか、エラーハンドリングを行う
safePrint('An error occurred while initializing location services: $e');
// 必要に応じてユーザーにエラーを通知
}
}
/*
現在の位置情報を取得
@return _currentLocationData: latitude longitude
*/
Future<LocationData?> getLocation() async {
if (_permissionGranted != PermissionStatus.granted) {
throw Exception('Location permissions are not granted');
}
_currentLocationData = await location.getLocation();
return _currentLocationData;
}
/*
位置情報の変更をリッスンする
*/
Stream<LocationData> get onLocationChanged {
return location.onLocationChanged;
}
/*
バックグラウンドでの位置情報取得を有効にする
@param enable バックグラウンドでの位置情報取得を有効にするかどうか
*/
Future<void> enableBackgroundMode(bool enable) async {
await location.enableBackgroundMode(enable: enable);
}
}
2. main.dartなどのファイルで呼び出す
@override
void initState() {
super.initState();
// 位置情報関連の非同期処理をinitStateで安全に呼び出す
WidgetsBinding.instance.addPostFrameCallback((_) async {
// LocationManagerのインスタンスを取得し初期化
var locationManager = LocationManager();
await locationManager.initLocationService();
// 現在の位置情報を取得
var currentLocation = await locationManager.getLocation();
safePrint(
'Current Location: ${currentLocation?.latitude}, ${currentLocation?.longitude}');
// アプリがバックグラウンドにあるときも位置情報を取得する
await locationManager.enableBackgroundMode(true);
// 位置情報が変わった時の処理を設定
locationManager.onLocationChanged.listen((LocationData currentLocation) {
safePrint(
'New Location: ${currentLocation.latitude}, ${currentLocation.longitude}');
});
});
}
上記の実装により、以下のような位置情報を確認するためのホップアップが表示されるようになる。アプリの使用時のみを選択した場合には、上記の`safePrint(‘Current Location: ${currentLocation?.latitude}, ${currentLocation?.longitude}’);`で現在の位置情報が出力されるようになる。
iPhoneでの表示
Androidでの表示
発生したエラー
locationプラグイン設定後のAndroidビルドエラー
私の環境下でlocationプラグイン設定後に以下のエラーが発生した。
Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 40s
┌─ Flutter Fix ──────────────────────────────────────────────────────────────────────────────┐
│ [!] Your project requires a newer version of the Kotlin Gradle plugin. │
│ Find the latest version on https://kotlinlang.org/docs/releases.html#release-details, then │
│ update /Users/waibandl321/onishi/code/Flutter/reboot/android/build.gradle: │
│ ext.kotlin_version = '<latest-version>' │
└────────────────────────────────────────────────────────────────────────────────────────────┘
Exception: Gradle task assembleDebug failed with exit code 1
Kotlin Gradleプラグインのバージョンが古いことが原因のよう。以下の手順で解消した。
- Kotlinの最新バージョンを確認するために、提供されたリンク Kotlin Releases にアクセス
- プロジェクトの
android/build.gradle
ファイルを開き、ext.kotlin_version
の値を最新バージョンに更新 - 再度ビルドする
まとめ
location
ライブラリを使ってFlutterアプリでデバイスの位置情報を取得する手順を解説した。AndroidとiOSの設定を行い、位置情報サービスの状態と権限を確認し、位置情報の取得とリッスンを実装することで、アプリでリアルタイムな位置情報を扱うことが可能になる。また、発生したビルドエラーの対処法も紹介した。これらの手順を踏むことで、Flutterアプリケーションにおける位置情報の取得をスムーズに実装できるだろう。
この記事は役に立ちましたか?
もし参考になりましたら、下記のボタンで教えてください。
コメント