【iOS】位置情報利用許可アラートの許可/許可しないボタンのハンドリング方法

はじめに

チャット接客型不動産購入アプリ「RENOSY」(以下、RENOSYアプリ)のiOSアプリを開発している植村です。 現在はiOSアプリ開発に加え、APIなどのアプリサーバーの開発にも携わっています。

これはなに?

位置情報利用を許可をユーザーに求めるアラート(以下、位置情報利用許可アラート)のボタンイベントをハンドリングする方法を紹介します。
f:id:uemura1shi:20190823175808p:plain

RENOSYアプリでは、現在地周辺の駅を選択して物件を検索できる機能があります。 その駅情報を表示するために、ユーザーから位置情報提供の許可を取得する必要があり、アラートを表示させて許可を求めます。 そのアラートの「許可」ボタンを押したときに、現在地周辺駅画面へ遷移させるという仕様で実装を試みました。

一見簡単そうですが、悲しいことに、位置情報利用許可アラートはAppleがデフォルトで提供するViewであり、このアラートのボタンをハンドリングするメソッドなどは用意されていません。必死にボタンイベントを取ろうとして取れずに苦労したため、この記事で方法をシェアしたいと思いました。

方法

実際にアラートの許可/許可しないボタンのハンドリングをする方法を説明します。

CoreLocationフレームワークについて

はじめに、CoreLocationフレームワークについて説明します。 iOS SDKには位置情報関連の機能がパッケージされたCoreLocation フレームワークがあります。このフレームワークをimportするとCoreLocationの機能がファイル内で使えるようになります。 このCoreLocationフレームワークを用いることで、ユーザーの現在地を取得することができます。(具体的な使い方は割愛します。以下の記事がとても分かりやすいので参考にしてください!)

qiita.com

位置情報利用許可のステータスの種類

ユーザーは以下のような位置情報利用許可のステータス CLAuthorizationStatus を持っています。

  • authorizedAlways: 常に許可する
  • authorizedWhenInUse: このAppを使用中のみ許可する
  • denied: 許可しない
  • notDetermined: 許諾を取っていない

ボタンのハンドリング

上記の、これはなに?で説明したように、このボタンのハンドリングは、上で説明した位置情報利用許可ステータスの種類が変更されたイベントを取得して実現します。
変更されたイベントは、CLLocationManagerDelegeteが提供するデリゲートメソッドfunc locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus)で取得することができます。

そのメソッド内で、ステータスの状態を見て、以下のようにボタンイベントをハンドリングします。

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
    switch status {
    case .authorizedWhenInUse, .authorizedAlways:
        // 許可ボタンをタップしたとき
    case .denied:
        // 許可しないボタンをタップしたとき
    default:
        break
    }
}

ViewController内のコードの全体像も載せておきます。

import UIKit
import CoreLocation

class RailwayLineViewController: UIViewController {
    var locationManager: CLLocationManager!
    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager.delegate = self
    }
    
    @objc func tapNearbyStationViewButtonAction {
        // CLLocationManagerクラスのインスタンスを作成
        locationManager = CLLocationManager()
        guard let locationManager = locationManager else { return }
       
        // 位置情報利用許可ステータスを取得
        let status = CLLocationManager.authorizationStatus()
        switch status {
        case .authorizedWhenInUse, .authorizedAlways:
            // 許可しているとき
        case .denied:
            // 許可していないとき
        case .notDetermined:
            // 許可を一度も取っていないとき
            // アラートを表示し、許諾を求める
            locationManager.requestWhenInUseAuthorization()
        default:
            break
        }
    }
}

extension RailwayLineViewController: CLLocationManagerDelegate {
    // ユーザーの位置情報取得ステータスの変更をハンドリング
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .authorizedWhenInUse, .authorizedAlways:
            // 許可ボタンをタップしたとき
        case .denied:
            // 許可しないボタンをタップしたとき
        default:
            break
        }
    }
}

感想

「ボタンイベントをハンドリングする」→「ユーザーのステータスが変更されたタイミングをハンドリングする」と意味合いを置き換える発想がなかなか出てこず苦労しました。
これからもこういった小さなTipsをTechBlogでシェアしていこうと思います!