酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

iOSでジオフェンス機能を実装する

「目的地に近づいたよー」的なことができるのがジオフェンス機能です。アプリを閉じていても反応するのでとても便利と聞いたので実装してみました。

LocationManagerで位置情報を取得する

iOSアプリで位置情報を取得するための方法は割愛します。Swift3用で少し古いですが、Classmethodのブログに詳しく書かれています。

ジオフェンス機能を実装する

ジオフェンス機能を実装してみましょう。

コード

extension GeofenceManager: CLLocationManagerDelegate {
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        currentStatus = status
        
        switch status {
        case .notDetermined:
            locationManager.requestAlwaysAuthorization()

        default:
            break
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) {
        print("登録地点への観測を開始しました")
    }
    
    func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
        print("登録した領域に進入しました")
    }
    
    func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
        print("登録した領域から退出しました")
    }
    
    func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
        if state == .inside {
            print("登録した領域の内側にいます")
        } else if state == .outside {
            print("登録した領域の外側にいます")
        } else {
            print("わかりません")
        }
    }
    
    func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) {
        print("エラー:\(error.localizedDescription)")
    }
    
}

観測地点を追加します。祖師谷公園から半径200メートル以内に進入・退出した場合に通知が来るように設定します。

let center = CLLocationCoordinate2D(latitude: 35.6586115, longitude: 139.5910694)
let region = CLCircularRegion(center: center, radius: 200, identifier: "祖師谷公園")
locationManager.startMonitoring(for: region)

アプリが起動していなくても処理できる

ジオフェンス機能の良いところはアプリプロセスが生きていなくても、アプリを起動してくれるところにあります。

以上でiOSでのジオフェンス機能の実装は完了です。

トラブルシューティング

Info.plistへの追記

ユーザーのプライバシー保護のためにユーザーデータを利用する際には逐一利用目的を表示しないといけなくなりました。スクリーンショットを保存する場合にもフォトライブラリへアクセスする理由を表示します。

位置情報の取得を開始する際には今までアラート表示されていましたが、位置情報へアクセスするために理由も必要になりました。

Info.plistにNSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescriptionを追加します。

f:id:ch3cooh393:20180316101833p:plain

ジオフェンスはアプリ起動時以外にも利用できるようにする必要があります。

locationManager = CLLocationManager()
locationManager.delegate = self

CLLocationManagerDelegate#locationManager(_:didChangeAuthorization:)が呼ばれるので、locationManager.requestAlwaysAuthorization()を実行します。Info.plistで書いたテキストは以下のダイアログで利用されます。

f:id:ch3cooh393:20180316165516p:plain

最初から領域範囲内外にいる場合にその状態は通知されない

最初から領域範囲内外にいる場合にその状態は通知されません。一度regionを登録してしまえばアプリを消すか自分から関し領域を削除しない限りは、ジオフェンス機能は有効になったままです。

アプリ起動後にlocationManager.requestState(for: region)を実行することでlocationManager(_:didDetermineState:for:)が呼ばれて、現在の状態(領域の内側か外側か?)を知ることができます。