📍
Swift バックグラウンドで位置情報を処理する
概要
- iOSアプリ上で、バックグラウンドで位置情報を処理する
Step1
- これらの情報を埋めてください
- Targets > Info
- Privacy - Location Usage Description
- Privacy - Location Always and When In Use Usage Description
Step2
- Targets > Signing & CapabilitiesにBackground Modesを追加し、これらにチェックを入れましょう
Step3
- LocationManagerWithBackgroundクラスを作り、コードを書きましょう
import Foundation
import SwiftData
import CoreLocation
import Combine
@MainActor
public class LocationManagerWithBackground: NSObject, ObservableObject {
@MainActor public static let shared = LocationManagerWithBackground()
@MainActor private let session = CLBackgroundActivitySession()
@MainActor private let manager = CLLocationManager()
@MainActor private var cancellables: Set<AnyCancellable> = .init()
@MainActor private(set) public var currentLocation: CLLocation?
@MainActor
public override init() {
super.init()
}
@MainActor
public func requestAuthorization() {
manager.requestWhenInUseAuthorization()
manager.requestAlwaysAuthorization()
}
@MainActor
public func start() {
for cancellable in cancellables {
cancellable.cancel()
}
let task = Task {
var count = 0
for try await update in CLLocationUpdate.liveUpdates(.fitness) {
currentLocation = update.location
try await processOnUpdate(location: update.location)
}
}
self.cancellables.insert(.init { task.cancel() })
}
@MainActor
public func processOnUpdate(location: CLLocation?) async throws {
guard let coordinate = location?.coordinate else {
return
}
// ここで何かする
}
}
Step4
- 位置情報取得開始のコードを書きましょう
import SwiftUI
import UIKit
class AppDelegate: NSObject, UIApplicationDelegate, ObservableObject {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions
launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
let locationsHandler = LocationManagerWithBackground.shared
locationsHandler.requestAuthorization()
locationsHandler.requestAuthorization() // 1回目のrequestAuthorizationでは"アプリの起動中は許可"しか選択できないため、2回必要です。
locationsHandler.start()
return true
}
}
@main
struct IchijouhouApp: App {
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
注意点
- アプリのタスクを切ると位置情報は更新されません
- 位置情報更新時のプログラムでエラーが起きると、位置情報の更新がストップし、バックグラウンドから再起動することはできません (ユーザーがサイドアプリを開く必要がある)
Discussion