iOSでジオフェンスに触れる①

こんにちは増島です!

ポケモンGoがリリースされてしばらく経ちました。 最近ではゲームやO2Oサービスなど色々な領域で位置情報の重要性が増しているような気がします!!

先日iOSでジオフェンスについて触れる機会が有りました。その時学んだことを2回に渡って書きたいと思います。

ジオフェンスとは

仮想的な地理的境界線のことを言います。 ある特定の領域をジオフェンスとして設定し、移動体の侵入、退出をトリガーとしてイベントを発生させることができます。

例えばジオフェンスを使用すると下記のような機能を実現することが出来ます。

1.ある店舗を中心に半径500mで領域を作成する
2.ユーザがエリア内に入った時に店舗のクーポン券を配布する

ジオフェンスを使っているサービス

ジオフェンスを使っているサービスとしては下記のようなものが挙げられます。

iOSにおけるジオフェンス機能の特徴

iOSでジオフェンス機能を使用する際に気になる特徴についてまとめました。

同時に観測出来るフェンス数の上限

  • 最大20個まで同時に登録出来ます。

必要なパーミッション

  • 位置情報の取得について「常に許可(AuthorizedAlways)」の取得が必要なようです。

バックグラウンドでの動作

  • 上記の通り「常に許可」の状態を取っているので可能なようです。アプリがタスクから切られている時でも 通知イベントによって裏側でアプリが再起動されるようです。

iOSでのジオフェンスの実装

開発環境

  • iOS10
  • Swift3.0

通常の位置情報の取得にも使用する「CoreLocation」フレームワークを使用します。 CLLocationManagerに領域観測を実施する為の各種メソッドが用意されているので、そちらを使用します。

下記が今回実装する内容の全体です。

import UIKit  
import CoreLocation

class ViewController: UIViewController {  
  private let manager = CLLocationManager()
  private var monitoredRegion: CLCircularRegion?

  override func viewDidLoad() {
    super.viewDidLoad()
    self.requestPrivasyAccess()
    self.startMonitoring()
  }

  private func requestPrivasyAccess() {
    self.manager.requestAlwaysAuthorization()
  }

  private func startMonitoring() {
    let status = CLLocationManager.authorizationStatus()
    if status == .denied || status == .restricted {
      return
    }
    self.manager.delegate = self
    let center = CLLocationCoordinate2DMake(35.681391, 139.766103)
    self.monitoredRegion = CLCircularRegion(center: center, radius: 200, identifier: "region1")
    self.manager.startMonitoring(for: self.monitoredRegion!)
  }

  private func stopMonitoring() {
    if let monitoredRegion = self.monitoredRegion {
      self.manager.stopMonitoring(for: monitoredRegion)
    }
  }
}

extension ViewController: CLLocationManagerDelegate {  
  func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) {
    print("観測を開始しました!")
  }

  func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) {
    print("観測の開始に失敗しました!")
  }

  func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
    print("領域に入りました!")
  }

  func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
    print("領域から出ました!")
  }
}

それでは各処理を見ていきましょう。

パーミッション許可のリクエスト

パーミション許可を取得しないと、観測を開始しても位置情報を取ることが出来ません。 あらかじめリクエスト処理を入れて許可してもらうようにしましょう。

self.manager.requestAlwaysAuthorization()  

補足ですが、iOS10ではユーザにパーミッションの利用目的を明示することが必須となりました。10に対応する場合はプロジェクトのplistに「Privacy - Location Always Usage Description」を設定をしないとパーミッション許可のダイアログが表示されません。

観測の開始と終了

領域観測の開始

「startMonitoringForRegion」メソッドを使用します。 下記のようなコードで観測を開始出来ます。

self.manager.delegate = self  
let center = CLLocationCoordinate2DMake(35.681391, 139.766103)  
self.monitoredRegion = CLCircularRegion(center: center, radius: 200, identifier: "region1")  
self.manager.startMonitoring(for: self.monitoredRegion!)  

上記の例だと新橋駅を中心に半径200mで領域を作成して観測を開始しています。

領域観測の終了

止める場合は先ほど指定したregionを渡してstopメソッドを呼んであげるだけです。

if let monitoredRegion = self.monitoredRegion {  
self.manager.stopMonitoring(for: monitoredRegion)  
}

通知系処理

通知を受けるにはCLLocationManagerのdelegateを実装する必要が有ります。 それではDelegateメソッドを見てみましょう。

領域に入ったとき

func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {  
print("エリアに入りました");  
}

領域から出たとき

func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {  
print("エリアから出ました");  
}

観測開始エラー時

観測の開始時にエラーが発生した場合は下記の処理が呼ばれます。

func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) {  
    print("観測の開始に失敗しました!")
}

このようにDelegateメソッドで任意の処理を実装することで、 通知されたタイミングで色々な機能を実現出来ます。


位置情報を使用する機能は非常に動作確認がしづらいです。 最終的にはフィールドテストをすべきかと思いますが、ちょっとした動作確認のために外に出るのは非常に大変ですよね。
次回はXcodeを使って簡単な動作確認をする方法を実装例とともにご紹介します。

comments powered by Disqus