概要

Flutterアプリにジオフェンシング機能を実装した際の備忘録 Android編です。
Android・iOSを対象とし、デスクトップやWebは対象外です。細かな実装部分については、各公式サイトの紹介にとどめています。

実装ステップ

  1. Androidにジオフェンシング機能を実装する
  2. iOSにジオフェンシング機能を実装する
  3. Dartからジオフェンシング機能を開始/終了する
  4. AndroidからDartにジオフェンシングin/outを通知する
  5. iOSからDartにジオフェンシングin/outを通知する
  6. 位置情報使用の説明画面を作成する
  7. ストアリリースの準備をする

Androidにジオフェンシング機能を実装する

まずはAndroid公式の情報を確認します。

権限の設定

位置情報に関する権限をAndroidManifest.xmlに追記します。

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>

ジオフェンシング出入り検知Receiverの作成

ジオフェンシングの出入りを受信するReceiverを作成します。実装自体はAndroid公式の実装例がそのまま参考になります。

Flutter連携用Workerの作成

Receiverで受信した情報をFlutter側に送りたい場合、ListenableWorkerを使用します。
Workerの中でFlutterEngineMethodChannelを使用して事前にFlutter側で登録しておいた処理を呼び出します。
あまり参考になる記事を見つけることができなかったのですが、今ならAIに聞けば参考になる情報を教えてくれるかもしれません。
ここは実装当時、とても苦労しました。実アプリ上ではデバッグも手間だったため、プラグインとして切り出し、exampleアプリを作成して進めました。
今から作るなら、アプリ本体に組み込むより最初からプラグインとして作るのがおすすめです。

Workerの呼び出し

私の場合はOneTimeWorkRequestBuilderを使って、以下のように呼び出す作りにしました。

 WorkManager.getInstance(context).enqueueUniqueWork("[work名称]", ExistingWorkPolicy.KEEP, request)

ジオフェンスの作成

Geofence.Builderを使用してジオフェンスを作成します。このとき、ジオフェンスの半径、有効期限、出入りのタイプなどを設定する必要があります。値の作成方法はアプリの種類によってさまざまだと思いますが、私の場合はCMSで登録する仕組みを準備しました。
1つのアプリで登録可能なジオフェンスは100個までです。半径や有効期限に上限はないと思いますが、半径は数m〜数kmまでさまざまに設定可能です。公式では100mが推奨されているようです。

精度や頻度についてはバッテリー駆動時間についてを参照しながら、最適な設定を探るのが良いと思います。バッテリー消費が多いとアンインストールの筆頭候補になるので、この辺りは重要ですね。

ジオフェンスの登録

作成したジオフェンスは、GeofencingRequestで登録できます。
このとき、success/failureのリスナーを設定できるので、failure時はFirebaseCrashlyticsなどにログ出力するようにしておくと、後の調査が楽になると思います。ただ、実運用でfailureに入ることは、そうそうないような気もしますが……。
また、登録先のGeofencingClientはアプリ起動時などにインスタンスを作成し、メンバー変数で保持しておくと良いでしょう。

ジオフェンスの解除

ユーザーが機能をオフにする際は、ジオフェンスの登録もきちんと解除しておきましょう。
ジオフェンスを作成する際にセットしたIDをGeofencingClient::removeGeofencesに渡すだけなので簡単です。

デバイス再起動時のジオフェンス再登録

デバイスが再起動した時、そのままだとジオフェンスは消えてしまいますので、一手間必要です。
Androidではandroid.intent.action.BOOT_COMPLETEDを受け取るReceiverを作ることでデバイス再起動を検知できるので、そこでジオフェンスを再登録しましょう。

ジオフェンスが作成されているかチェックしたい場合

公式から提供されているAPIはないようなので、自分でロジックを書く必要があります。私は登録時にセットしたIDを保存しておいて、その有無で判断するようにしました。

ジオフェンスを100件より多く登録したい場合

私の場合は100件で足りましたが、それでは足りない場合もあると思います。
そのような場合は、バックグラウンドで定期的に位置情報を取得し、近い順に100件を登録し直す実装を入れるのが良いと思います。
Flutter連携用Workerと異なり、定期実行のWorkerでは安定性に不安があるようなので、フォアグラウンドサービスを利用するのが良さそうです。
もしくは、アプリ起動時に登録し直す仕組みでもいけそうですね。この辺りはアプリの用途も込みで考える必要がありそうです。