仕事でiOSアプリを作っていて、妙なところでハマってしまったので備忘録までに。
- 位置情報やモーション フィットネスを使うための事前設定
- 任意のタイミングで許諾を求める処理
- アプリを開いたときの権限不足チェック
位置情報やモーション フィットネスを使うための事前設定
アプリを作成したら、info.plistに位置情報とモーションの項目を追加します
Targets > Signing&Capabilitiesの左上の「+Capability」からBackgroundModesを選択すると項目が追加されます
これにてアプリ側の初期設定は終了かなと思います
任意のタイミングで許諾を求める処理
例えばウォークスルーの途中など、ユーザとコミュニケーションを撮っている流れの中で許諾を取りたい場面もあるかと思います
SceneDelegate.swift
class SceneDelegate: UIResponder, UIWindowSceneDelegate, CLLocationManagerDelegate { // CLLocationManagerDelegate
private let locationManager = CLLocationManager()
private let motionManager = CMMotionActivityManager()
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
self.locationManager.requestAlwaysAuthorization()
self.locationManager.delegate = self
self.motionManager.startActivityUpdates(
to: OperationQueue.current!) { (data: CMMotionActivity?) in
/* do nothing */
}
self.motionManager.stopActivityUpdates()
}
〜 略 〜
}
ハマったポイントとしては、
- 位置情報のアクセスを求めるときは、delegateをしないといけない
- モーションには位置情報のように権限リクエストするメソッドが見当たらず、一瞬start/stopして動かしている
アプリを起動すると、位置情報アクセスとモーションフィットネスへのアクセスを要求するダイアログが出るようになりました
アプリを開いたときの権限チェック
アプリを使っている途中やウォークスルーで許可しそびれたときに、アプリ側から権限チェックをする機能です。アプリを起動して最前面にもっていくごとにチェックするため、SceneDelegateからダイアログを表示しています
SceneDelegate.swift
class SceneDelegate: UIResponder, UIWindowSceneDelegate, CLLocationManagerDelegate {
private let locationManager = CLLocationManager()
private let motionManager = CMMotionActivityManager()
〜 略 〜
func sceneDidBecomeActive(_ scene: UIScene) {
if #available(iOS 14.0, *) {
if locationManager.authorizationStatus != .authorizedAlways {
showPermitDialog(title: "権限が不足しています", body: "位置情報アクセスを「常に許可」にしてください")
}
if locationManager.accuracyAuthorization != .fullAccuracy {
showPermitDialog(title: "権限が不足しています", body: "正確な位置情報を許可にしてください")
}
} else {
if CLLocationManager.authorizationStatus() != .authorizedAlways {
showPermitDialog(title: "権限が不足しています", body: "位置情報アクセスを「常に許可」にしてください")
}
}
if CMMotionActivityManager.authorizationStatus() != .authorized {
showPermitDialog(title: "権限が不足しています", body: "モーション&フィットネスを許可にしてください")
}
if ProcessInfo.processInfo.isLowPowerModeEnabled {
showPermitDialog(title: "権限が不足しています", body: "低電力モードを無効にしてください")
}
}
private func showPermitDialog(title: String, body: String) {
let dialog = UIAlertController(title: title, message: body, preferredStyle: .alert)
dialog.addAction(UIAlertAction(title: "設定を開く", style: .default, handler: {
(action: UIAlertAction!) -> Void in
if let url = URL(string: UIApplication.openSettingsURLString), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}))
dialog.addAction(UIAlertAction(title: "キャンセル", style: .cancel, handler: nil))
self.window?.rootViewController?.present(dialog, animated: true, completion: nil)
}
〜 略 〜
}