概要

Flutterアプリにジオフェンシング機能を実装した際の備忘録 iOS編です。
Android・iOSを対象とし、デスクトップやWebは対象外です。細かな実装部分については、各公式サイトの紹介にとどめています。
この記事に記載のジオフェンス作成方法は、2026年現在少々古いです。最新の実装はApple公式を参照ください。

実装ステップ

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

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

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

所感ですが、Androidよりは実装が簡単だったような・・・気がします。各々違う難しさはありますが。

XCodeの設定

  • Capability「Background Modes」>「Location updates」をチェック
  • Info.plitに「Privacy - Location Always and When In Use Usage Description」を追記

delegateの設定

AndroidのReceiverにあたる部分ですね。CLLocationManagerにdelegateを設定します。delegateのオブジェクトをどうするかは悩ましいポイントと思いますが、私の場合、FlutterPluginのクラスをそのまま設定しました。
アプリ側で細かい制御を行いたい場合は、AppDelegate等に設定し、プラグイン側に渡せるようにするのもアリだと思います。

ジオフェンスの作成

CLCircularRegionを使用してジオフェンスを作成します。半径、出入りのタイプなどありますが、ここはAndroid同様にCMSで登録する仕組みとしました。
1つのアプリで登録可能なジオフェンスは20個までです。Androidの5分の1しか登録できないのが厳しいですね。

ジオフェンスの登録

作成したジオフェンスはCLLocationManager::startMonitoringで登録できます。 失敗時、locationManager(_:monitoringDidFailFor:withError:)が呼ばれるので、必要に応じてdelegate登録しておくと良さそうです。
私が実装時は入れなかったのですが、入れておけばよかったなと今は思います。

ジオフェンスの解除

ユーザーが機能をオフにする際は、ジオフェンスの登録もきちんと解除しておきましょう。 Androidと違って登録時に作成したCLCircularRegionが必要ですがCLLocationManager::monitoredRegionsで取得できます。
私はなるべくAndroidと仕様を合わせたかったこともあり、下記のように保持しておいたIDで検索する作りにしました。

func removeGeofence(_ identifier: String) -> Bool {
    for region in locationManager.monitoredRegions {
        if region.identifier == identifier {
            locationManager.stopMonitoring(for: region)
            return true
        }
    }
    return false
}

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

登録中のジオフェンスはCLLocationManager::monitoredRegionsで全て取得できます。

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

バックグラウンドで定期的に位置情報を取得し、近い順に登録し直すのが良いかなと思います。
Androidの場合はWorker、フォアグラウンドサービスと少々ややこしいですが、iOSはシンプルです。 CLLocationManager::startMonitoringSignificantLocationChangesをバックグラウンド移行時やアプリ起動時に呼び出して、didUpdateLocationsで再登録を行いましょう。
Flutterのデバッグビルドだとキル状態からの検証が厳しいので、profileやreleaseでビルドして確認する必要があります。