01 NOTEゼロワンノートは、転職・独立したい人のサービス開発・転職・副業・起業を応援するサイトです。

FlutterでGPSを簡単実装!初心者が知っておくべきポイントと注意点

Flutterアプリ開発

プロダクトを作る中でマップを表示したり、ユーザーの行動をトラッキングしたりする機能を提供することがあります。

この記事では、GPSを使ってユーザーの行動のトラッキングする方法やバックグラウンドで実行する方法を解説していきます。

Flutterで位置情報を取得する方法

今回は、位置情報を取得するために geolocator というFlutterパッケージを使っていきます。

はじめに、アプリ上で位置情報を取得するためには、位置情報にアクセスするためのパーミッションをユーザー許可してもらう必要があります。 この許可をもらう設定は、プラットフォームごとにプロジェクト内ファイルに記述する必要があります。

iOSの設定

iOSでは、info.plistファイルに以下の設定を追加します。

<!-- geolocator Section -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>Required to post location information when posting photos and videos.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Required to post location information when posting photos and videos.</string>
<!-- End of the geolocator Section -->

Androidの設定

Androidでは、AndroidManifest.xmlファイルに以下のいずれかの設定を追加します。それぞれのパーミッションの違いは、位置情報の精度になります。「ACCESS_COARSE_LOCATION」では半径が約3キロ以内の位置情報、「ACCESS_FINE_LOCATION」ではより正確に半径が約 50 メートルで位置情報を取得できます。

<manifest ... >
  <!-- Always include this permission -->
  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

  <!-- Include only if your app benefits from precise location access. -->
  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>

次に、サービスも追加します。

<!-- Recommended for Android 9 (API level 28) and lower. -->
<!-- Required for Android 10 (API level 29) and higher. -->
<service
    android:name="MyNavigationService"
    android:foregroundServiceType="location" ... >
    <!-- Any inner elements would go here. -->
</service>

geolocatorパッケージの追加

以下のコマンドでパッケージをプロジェクトに追加します。

flutter pub add geolocator

位置情報の取得を実装

はじめに、geolocationを使って位置情報を取得する処理を実装していきます。位置情報を取得するためのパーミッションをチェックする機能を実装します。

import 'package:geolocator/geolocator.dart';

Future<Boolean> chckPermission() async {

  /* 位置情報サービスが有効かどうか確認します。 */
  if (!await Geolocator.isLocationServiceEnabled()) {
    /* 位置情報サービスが有効ではない場合、エラーを表示します。 */
    return Future.error('Location services are disabled.');
  }

  /* 位置情報サービスにアクセスして良いか、ユーザーに確認をします。 */
  LocationPermission permission = await Geolocator.checkPermission();
  if (permission == LocationPermission.denied) {

     /* 位置情報サービスのアクセス許可がない場合は、ユーザーにアクセス許可を求めます。 */
    permission = await Geolocator.requestPermission();

    /* 位置情報サービスへのアクセスを拒否された場合、エラーを表示します。 */
    if (permission == LocationPermission.denied) {
        return Future.error('Location permissions are denied');
    }
}
  
  /* 位置情報サービスのアクセスが永久に拒否されている場合、エラーを表示します。 */
  if (permission == LocationPermission.deniedForever) {
    return Future.error(
      'Location permissions are permanently denied, we cannot request permissions.');
  } 

  /* 位置情報サービスへのアクセスに問題がない場合、位置情報を取得します。 */
  return true
}

次に、位置情報サービスが有効になっているか、位置情報へのアクセス許可があるかをチェックし、最終的に位置情報を取得します。

Future<Position> getCurrentPosition() async {
    /* 位置情報サービスのパーミッション確認. */
    Boolean permission = await checkPermission();
    if (!permission) {
        return Future.error('Location permissions are denied');
    }

    return Geolocator.getCurrentPosition();
}

位置情報をトラッキングをする実装

geolocatorを使って継続的に位置情報を取得する処理を実装していきます。例えば、マップを使った機能などで移動中の現在地を表示する場合などに使われます。

Future<StreamSubscription> startTracking() async {
    /* 位置情報サービスのパーミッション確認. */
    Boolean permission = await checkPermission();
    if (!permission) {
        return Future.error('Location permissions are denied');
    }

    /* トラッキングの精度を設定 */
    final LocationSettings locationSettings = LocationSettings(
         accuracy: LocationAccuracy.high,
         distanceFilter: 100,
    );

    /* 位置情報が更新されるたびに位置情報を処理 */
    return Geolocator.getPositionStream(locationSettings: locationSettings)
        .listen((Position? position) {
                /* トラッキングした位置情報を処理する */
         });
}

位置情報のトラッキングを中断するには、以下のように処理することで中断できます。

StreamSubscription subscription = await startTracking();
subscription.cancel();

バックグラウンドモードで実装する

アプリ上でバックグラウンドサービス (background service)にアクセスするために、パーミッションをユーザー許可してもらう必要があります。 この許可をもらう設定は、プラットフォームごとにプロジェクト内ファイルに記述する必要があります。

Androidの設定

Androidのバックグラウンドサービス (background service) を使うためには、マニフェストファイルに以下のパーミッションを追加する必要があります。

<manifest ... >
  <!-- Required only when requesting background location access on
       Android 10 (API level 29) and higher. -->
  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
</manifest>

iOSの設定

iOSのバックグラウンドサービス (background service) を使うためには、プロパティに以下のパーミッションを追加する必要があります。

...
<key>UIBackgroundModes</key>
<array>
  <string>location</string>
</array>

バックグラウンド処理の最適化とトラブルシューティング

iOSでの制約

iOSでは、バックグラウンドの処理をOSが管理しています。そのため、デバイスの状況などを踏まえて処理が安定的に実行されない場合があります。

AndroidのDozeモード

Androidでも同様にデバイスの使用状況に応じて、バッテリー消費のコントロールが行われるDozeという機能があります。これは、ユーザーが一定時間操作を行わなかったり、静止していたりする場合に切り替わります。この間、OSはアプリのネットワークアクセスやバックグラウンド処理を制限することがあります。

さいごに

Flutterにおける位置情報の取得について、コードの解説とともに紹介していきました。パーミッションの設定や位置情報の精度、バッテリーの消費など、ユーザーに配慮する部分について気を遣いつつ実装するのがポイントです。ぜひ参考にしてみてください。

Copylight 01 NOTE