flutterでgeofenceを使ってみた

１８歳学生のHaruです!

この後の話題にも出ますが、最近Restinという**休憩場所を手軽に見つけられるSNSのようなマップアプリ**をリリースしました!
ログイン無しでもご利用いただけるので、是非使ってもらえるととても嬉しいです！

https://apps.apple.com/jp/app/restin/id6470670439

![スクリーンショット 2023-11-06 1.02.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882303/c7016874-8eeb-66a7-bbac-23662f130608.png)

# まずGeofenceとは
:::note info
**Geofence**
仮想的な境界線で囲まれた任意のエリア
[引用](https://www.cariot.jp/blog/2021/09/30/geofence/)
:::


:::note info
**Geofencing**
対象がGeofenceに入ったとき、又は出たときに、アプリやソフトウェアで所定のアクションを実行すること
[引用](https://smartdrive.co.jp/fleet/useful-info/glossary/geofencing/)
:::



# 概要
前々からこのアプリにGeofencingを使って、機能追加をしたいと思っていたので、[flutter_background_geolocation](https://pub.dev/packages/flutter_background_geolocation)パッケージを使ってみました。
私のアプリの場合、休憩場所(ピン)に向かう前に、すでに他の人に使用されているかを判断できる機能を作るために、Geofencingを利用して、休憩場所の使用中かのステータスを見れるようにしました。

### この記事では導入、利用方法などを紹介します！


# 開発環境
- flutter 3.16.0
- google_maps_flutter 2.3.1
- flutter_background_geolocation 4.13.4

:::note alert
flutter_background_geolocationパッケージのAndroid対応について
このパッケージを使用して、Androidのリリースビルドをしたい場合、**ライセンスの購入が必要**になります。
今回はiOSの導入のみご紹介させていただきます、ご了承ください。
（iOSはアプリをリリースしても関係ありません。）
:::

:::note alert
今回google_maps_flutterの導入は紹介しません。
:::
# 導入


### ① packageの追加

```yaml:pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
    flutter_background_geolocation: 4.13.5
```

### ② iOSの設定

```diff_plist:Info.plist
<dict>
+    <key>NSMotionUsageDescription</key>
+    <string>Motion usage description</string>
+    <key>NSLocationWhenInUseUsageDescription</key>
+    <string>When in use description</string>
+    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
+    <string>Always/When in use description</string>

+    <key>UIBackgroundModes</key>
+    <array>
+        <string>fetch</string>
+        <string>location</string>
+    </array>
</dict>
```

<details><summary>Androidの設定</summary>

[こちら](https://qiita.com/drafts/08dc361efd5d50a7d28f/edit#%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83)でも記述した通り、Androidの設定紹介はしません。ご了承ください🙇🏻‍♂️
Androidの設定公式Docは[こちら](https://github.com/transistorsoft/flutter_background_geolocation/blob/master/help/INSTALL-ANDROID.md)
</details>


### ③ 初期化処理

クラスにパッケージをインポートし、
```dart:home_page.dart
import 'package:flutter_background_geolocation/flutter_background_geolocation.dart' as bg;
```

:::note warn
Location, Config, Stateなど他のパッケージでも使われていそうな、クラスとの混同を防ぐため、`as bg`とprefixをします。
:::

初期化処理を記述して

```dart:home_page.dart
  Future<void> initialize() async {
    await bg.BackgroundGeolocation.ready(
      bg.Config(
        desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH,
        distanceFilter: 10.0,
        stopOnTerminate: false,
        startOnBoot: true,
        debug: true,
        logLevel: bg.Config.LOG_LEVEL_VERBOSE,
      ),
    ).then((value) async {
      await bg.BackgroundGeolocation.start().then((value) {
        print('BackgroundGeolocation started');
      });
    });
  }
```

実行します。

```dart:home_page.dart
@override
  void initState() {
    super.initState();
    initialize();
  }
```


#### これで導入完了🎉


# Geofenceをマップに追加する

#### ① まずは追加するリストの変数を用意し、マップに表示したいピンの数だけloop処理をする

```dart
final geofences = <bg.Geofence>[];
for (final marker in markers) {
    geofences.add(
        bg.Geofence(
          identifier: marker.markerId,
          radius: 60.0,
          latitude: marker.latitude,
          longitude: marker.longitude,
          notifyOnEntry: true,
          notifyOnExit: true,
        ),
    );
}
```

```dart
  Future<bool> addGeofences(List<bg.Geofence> geofences) async {
    try {
      await bg.BackgroundGeolocation.addGeofences(geofences);
      debugPrint('addGeofences success');
      return true;
    } on Exception catch (e) {
      debugPrint('addGeofences failed $e');
      return false;
    }
  }
```

#### ② マップにGeofenceを追加しただけでは見えないので、可視化していきましょう
google_maps_flutterパッケージにCircleクラスという便利なものがあるので、使っていきましょう！
```dart
final circles = <Circle>[];
for (final marker in markers) {
    circles.add(
      Circle(
        circleId: CircleId(marker.markerId.value),
        center: marker.position,
        strokeColor: ColorName.amber.withOpacity(0.8),
        fillColor: ColorName.amber.withOpacity(0.2),
        strokeWidth: 2,
        radius: markerCircleRadius,
         ),
    );
}
```


#### ③ 追加
```dart
GoogleMap(
...
circles: circles.toSet(),
...
)
```


ここまででマップ上にGeofenceを追加することができました！
# Geofenceへの出入りのアクションを追加

#### ① Geofenceでのアクションハンドリングをする関数を作成

```dart
Future<void> eventOnGeofence(bg.GeofenceEvent event) async {
  if (event.action == 'ENTER') {
    print('GeofenceEvent: [--ENTER--]$event');
    // Geofenceに入った際に実行したいことを記述
  } else if (event.action == 'EXIT') {
    print('GeofenceEvent: [--EXIT--]$event');
    // Geofenceから出た際に実行したいことを記述
  }
}
```

#### ② 関数を実行する
```diff_dart:home_page.dart
  Future<void> initialize() async {
    await bg.BackgroundGeolocation.ready(
      bg.Config(
        desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH,
        distanceFilter: 10.0,
        stopOnTerminate: false,
        startOnBoot: true,
        debug: true,
        logLevel: bg.Config.LOG_LEVEL_VERBOSE,
      ),
    ).then((value) async {
      await bg.BackgroundGeolocation.start().then((value) {
        print('BackgroundGeolocation started');
      });
    });

+    bg.BackgroundGeolocation.onGeofence((bg.GeofenceEvent event) async {
+      await eventOnGeofence(event);
+    });
  }
```


# 作成できた機能

#### Geofenceに入場時

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882303/d5f1f35d-dba6-7223-8775-6f62e7e5531d.gif" width="400">

#### Geofenceから退場時

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2882303/3e86aed9-f731-5bc9-7e7d-df7aba0e0b33.gif" width="400">

無限に使い道やアイデアを考えられるGeofenceにとても興味をそそられますよね！！！！

::: note warn
退場時の処理がうまく走っていない部分は頑張って修正します😇
:::


# 最後に
初めて、Qiitaに投稿をすると共に、初めてAdventCalendarに投稿しました！
周りの記事がつよつよすぎて、こんな記事あげていいのかと思いましたが、あまりflutterの記事でGeofenceについての話題を見ないので、個人的には満足したと思い込むとします！！

雑な記事でしたが、ご覧いただきありがとうございました！！！！！😭


 # Geofence機能を追加したアプリのリポジトリ
 https://github.com/Haru-Kobayashi073/restin_app

# 参考
https://pub.dev/documentation/flutter_background_geolocation/latest/

# 著者

https://twitter.com/h_aru073

https://github.com/Haru-Kobayashi073

(ちなみに25卒です...)
https://www.wantedly.com/id/haru_kobayashi_dev