自宅Wi-Fiお知らせアプリ開発【第二回】 Beacon 探索機能編

開発部のなーさんです。
普段はWEB系の開発をしている私が「家庭で使える」をテーマに突如はじめた、Beaconを使ったスマホアプリ作成チャレンジブログ、第2回は、自宅Wi-Fiお知らせアプリのベースとなるiOSのCoreLocationを使ったiBeacon探索機能の作成を行っていきます。

下記は2018年10月現在の情報で執筆しています。
文中、画像中で使用されている商標等はそれぞれの企業、団体に帰属します。
コンセプト実証用のソースコードのため簡略化等された箇所があります。

前回のまとめ

前回は作成のための準備や情報の整理をしました。
自宅Wi-Fiお知らせアプリ開発【第一回】 準備編
つくるアプリ: 自宅Wi-Fiお知らせアプリ
アプリの機能: 帰宅したらBeacon(BLEAD-B)に反応して、スマホを自宅Wi-Fiに接続するかを聞いてくれるアプリ

今回開発に使用した環境を記載します。
●ハードウェア
iMac2017(macOS 10.14)
iPad Air2 (iOS12.0.1)SIMなし
BLEAD-B 1台
Wi-Fiルータ 1台
●ソフトウェア
Xcode 10.0 + Swift4.2
Apple developer Programアカウント ※HotSpotの許可をONにするために必須です。

CoreLocation.framework

作成にあたって、iBeacon探索の機能について整理したいと思います。
このアプリではiOSでiBeaconの探索や検知を手軽に行えるCoreLocation.frameworkを利用します。しかし、GPSなどの屋外位置測位も扱うフレームワークなので機能がたくさんあります。そこで今回使うクラスやメソッドなどをリスト化しました。
おおよその処理の流れです。

  1. 探索したいiBeaconの情報を設定したRegionを生成します。
  2. 生成したRegionの探索(Monitoring)を開始します。
  3. Regionの探索条件に合ったiBeaconが最初に検知されたとき、Regionの検知が発生します。
  4. レンジング(Ranging)を開始します。
    見つかったiBeaconの情報が連続的に通知されるようになります。Regionに合ったiBeaconが追加で見つかっても、新たにRegionの検知は発生しません。
  5. Regionの探索条件に合ったiBeaconが全て検知されなくなったら、レンジングを終了します。
  6. 無駄な探索(Monitoring)を防ぐために、必要に応じて探索を終了してください。

インポート

import CoreLocation

クラス

名前機能
CLLocationManageriBeaconを含めた位置情報の探索・検知をまとめて制御
CLLocationManagerDelegateCLLocationManagerのデリゲート
CLBeaconRegion探索したいiBeaconの情報を設定したRegion
親クラスはCLRegionクラス
CLBeacon検知されたBeaconの情報を格納
取得できる情報は下記の通り

  • ProximityUUID
  • Major
  • Minor
  • RSSI
  • Proximity
  • Accuracy
CLRegionState検出中のRegionの現在の状態(3種類)を格納

  • Inside
  • Outside
  • Unknown
CLBeaconMajorValueMajor値
CLBeaconMinorValueMinor値

なおUUIDはNSUUID?型、Region名はString型で定義します。

メソッド – CLLocationManager

名前機能
[クラスメソッド]
authorizationStatus()
取得:アプリに位置情報利用の許可があるか
[クラスメソッド]
isMonitoringAvailable()
取得:デバイスの探索に対応しているか
[クラスメソッド]
locationServicesEnabled()
取得:OS設定画面の位置情報がオンであるか
[クラスメソッド]
isRangingAvailable()
取得:デバイスがレンジングに対応しているか
requestAlwaysAuthorization()アプリが位置情報を使うことの許可を求めるダイアログを出すリクエスト(authorizationStatus()が.notDeterminedのとき、つまり初回起動時のみ有効)
この他にrequestWhenInUseAuthorization()というリクエストもある
requestState()didDetermineStateデリゲートを明示的に呼び出す
startMonitoring()Regionの探索を開始
stopMonitoring()Regionの探索を停止
startRangingBeacons()検知したRegion内のiBeaconのレンジングを開始
stopRangingBeacons()検知したRegion内のiBeaconのレンジングを停止
rangedRegions.contains()引数に指定したRegionが今レンジングされているか

デリゲート – CLLocationManagerDelegate

名前機能
didChangeAuthorization契機:アプリへの位置情報の許可状況が変化したとき
使い方:許可がある場合はRegion探索開始
didStartMonitoringFor契機:Regionの探索が開始されたとき
使い方:既にinsideしているRegionがないかを確認するために、CLLocationManager#requestState()を実行する
didEnterRegion※今回は使わないことにしました
契機:Regionの探索条件に合ったiBeaconが最初に検知されたとき
使い方:検知したRegion内のiBeaconのレンジング処理を開始する契機にできる
didExitRegion※今回は使わないことにしました
契機:Regionの探索条件に合ったiBeaconが全て検知されなくなったとき使い方:検知したRegion内のiBeaconのレンジング処理を終了する契機にできる
didDetermineState契機:didEnterRegion、didExitRegionが発生したとき、CLLocationManager#requestState()が実行されたとき
使い方:Regionの状態(inside/outside/unknown)で処理をわけたいときに使う
検知したRegion内のiBeaconのレンジングを開始・停止する契機にできる
didRangeBeacons契機:レンジング中にiBeacon情報が到着したとき
使い方:iBeaconの情報を取得して、内容に応じた処理をする
rangingBeaconsDidFailFor契機:レンジング中にエラーが発生したとき
使い方:エラー内容に応じた処理をする

プロパティ – CLLocationManager

名前機能
desiredAccuracyBeacon情報の通知頻度の指定
delegateデリゲート先の指定
allowsBackgroundLocationUpdatesバックグラウンド状態でも位置情報を更新
showsBackgroundLocationIndicator位置情報がAlways Useかつバックグラウンド状態のときにユーザーに位置情報の使用を明示

プロパティ – CLBeaconRegion

名前機能
notifyEntryStateOnDisplay画面が点灯したときやデバイスが常にRegion内にあるときに通知する
notifyOnEntryRegionのEnterをデリゲートする
notifyOnExitRegionのExitをデリゲートする
CoreLocation.frameworkなどの設定

iBeacon探索に関係する部分のプロジェクトの設定を再掲します。

使用するCapabilities

オンにする項目用途
Background Modes – Location updatesアプリがバックグラウンド状態でもBeaconを検知できるようにする許可

Info.plistの追加項目

CoreLocationを使う際の許可ダイアログに表示する文言を追加します。文言は適当に書いたものなので、ちゃんとしたものに変更してください。

追加する項目設定値
Privacy – Location Always and When In Use Usage DescriptionApp needs this permission.
Privacy – Location When In Use Usage DescriptionApp needs this permission.
アプリの状態の違いによるiBeaconの挙動

アプリの状態にはおおよそ下記の3つがあります。今回のアプリは、普段はフォアグラウンドにいるような使い方はしないので、1日の多くはバックグラウンド状態か終了状態でしょう。そこでバックグラウンド時の挙動を見てみました。

  • フォアグラウンド状態
  • バックグラウンド状態
  • 終了(キル)された状態

iBeaconの検知は、フォアグラウンド状態であれば、Regionに含まれる複数台のBeaconそれぞれについてEnter/Exitが発生するのに対して、バックグラウンド状態ではRegionごとに1度の発生となるようです(キル状態では試していません)。複数台のBeaconを使うときは注意してください。
バックグラウンド時の挙動について試してみたところ、なーさんの環境では下記のようになりました。

  • Region中の最初のBeacon 1台がEnterした瞬間から約10秒間didRangeBeaconsで検知
  • この時間内に他のBeaconがEnterすれば、そのBeaconもdidRangeBeaconsで検知
  • 追加でBeaconが検知されても、10秒間から延長されない
  • 10秒以降は、新規Beaconを検知してもdidRangeBeaconsが発行されない(内部的に検知はしていると思われます)

例えば、Beaconの電波を止めたのになかなかRegionがExitしないと思ったら、他のBeaconがいた、などの状況確認がフォアグラウンド状態よりもやりづらいように思いました。

次回の予定

なんと今回、CoreLocationの説明のみでコーディングに辿りつきませんでした。
次回こそはBeacon探索・検知機能のコーディングをはじめていきたいと思います。
以上、ご質問・ご指摘等ありましたら、弊社までお気軽にお問い合わせください。

自宅Wi-Fiお知らせアプリ開発【第三回】 Beacon 探索機能編 その2
自宅Wi-Fiお知らせアプリ開発【第四回】 Wi-Fiお知らせ機能編

関連記事

  1. Elastic Stack を使った予兆検知結果の可視化 〜概要と環境…

  2. 【2019年度版】BLEの基礎技術と活用例コンテンツ 12 選

  3. アジャイル ~壁を乗り越える~【第2回 改善のフレームワーク】

  4. Web Bluetooth を使ってみよう!その1

  5. 知識ゼロで Unity をはじめてみた【その5 -Android 端末…

  6. ねぇClova、開発したい 【対話モデル作成編】