FlutterアプリでiBeaconを検出したり、発信したりしてみたので、ざっくりまとめておく。
iBeaconとは
iBeaconそのものについては、下記の記事を参照。主にiOS等で使われるbeacon技術。
iBeacon - ウィキペディア
iBeaconとは - ケータイ Watch Watch
発信
発信側はpszklarska/beacon_broadcastを使って発信する。
BeaconBroadcast beaconBroadcast = BeaconBroadcast();
bool isAdvertising = await beaconBroadcast.isAdvertising();
BeaconStatus transmissionSupportStatus = await beaconBroadcast.checkTransmissionSupported();
if (!isAdvertising && transmissionSupportStatus == BeaconStatus.SUPPORTED) {
final String iBeaconFormat = 'm:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24';
await beaconBroadcast
.setUUID(Uuid().v5(Uuid.NAMESPACE_URL, 'sample.beacon.com'))
.setMajorId(1)
.setMinorId(100)
.setIdentifier('com.beacon.sample')
.setLayout(iBeaconFormat) // Android Only
.start();
Timer(
Duration(seconds: 10),
() {
beaconBroadcast.stop();
}
);
}
BeaconBroadcastの方はisAdvertising
で発信中かどうか確認して、checkTransmissionSupported
で動作する端末かどうか確認して、発信している。
ポイントはsetLayout(iBeaconFormat)
の部分で、iBeaconのフォーマットを指定している点。
iOSだと基本的にiBeaconのフォーマットにしか対応していないみたいで、setLayoutに何も指定せずにAndroid端末からbeaconを発信しても、iOS端末でbeaconを検知できない。
ちなみにBeaconBroadcastはデフォルトではAltBeaconのフォーマットになる。
検出
beaconを検出する側はalann-maulana/flutter_beaconを使う。
await flutterBeacon.initializeScanning;
AuthorizationStatus status = await flutterBeacon.authorizationStatus;
if (! (status == AuthorizationStatus.allowed
|| status == AuthorizationStatus.always
|| status == AuthorizationStatus.whenInUse)) {
Scaffold.of(context).showSnackBar(
SnackBar(content: Text("位置情報サービスをオンにする必要があります"))
);
return;
}
final regions = <Region>[
Region(
identifier: 'com.beacon.sample',
proximityUUID: Uuid().v5(Uuid.NAMESPACE_URL, 'sample.beacon.com'),
),
];
StreamSubscription streamRanging = flutterBeacon.ranging(regions).listen((RangingResult result) {
if (result != null && result.beacons.isNotEmpty) {
result.beacons.forEach((beacon) {
if (beacon.proximityUUID.toLowerCase() == uuid.toLowerCase()) {
print('beaconを検出したよ!');
}
});
}
});
StreamSubscription streamMonitoring = flutterBeacon.monitoring(regions).listen((MonitoringResult result) {
if (result != null && result.region != null) {
if (result.region.proximityUUID.toLowerCase() == BEACON_UUID.toLowerCase() && result.monitoringState == MonitoringState.inside) {
print('beacon圏内に入ったよ!');
}
}
});
flutterBeaconはrangingやmonitoringのstreamをlistenした時点で各プラットフォームのbeacon検出をスタートさせるようになっていて、止める場合はstreamRanging.cancel()
とすると止めることができる。streamRanging.close
しちゃうとそれ以降リスタートできないので注意。
rangingはアプリが起動中、常に監視してRangingResult.beacons
に現在圏内にいるbeaconを配列で受け取ることができる。
monitoringはbeaconの圏内に入った/出たを検出できて、バックグラウンドでも動作する。ただ、iOSの場合は位置情報が常に許可になっていないとバックグラウンドで動作しない。
バックグラウンドでの動作を期待する場合は、AuthorizationStatus.always
がfalse
だったらダイアログを出して設定に誘導する等した方が良いかもしれない。