CoreLocation speed를 이용해 현재 정지해 있는 상태인지 파악해보자!
현재 걷고 있는지, 정지해있는지를 파악하고 싶다.
피크민 꽃 심기 모드 중에 운전을 하거나, 버스를 타면 운전중은 아닌지 물어보는 알림이 뜨는데,
캡쳐를 해두지 못해 햄버거 피크민을 첨부한다.
아무튼 기기의 움직임을 감지하는 기능을 구현하고자 한다.
시도한 방법 1: CoreMotion - CMMotionActivity를 이용
CoreMotion 라이브러리 안에 CMMotionActivity라는 타입이 있는데, 기기의 움직임 분류해 주는 듯하다.
테스트코드
import CoreMotion
import SwiftUI
struct CoreMotionView: View {
@StateObject private var motionManager = CoreMotionManager()
var body: some View {
Text(motionManager.status)
}
}
class CoreMotionManager: NSObject, ObservableObject {
let motionManager = CMMotionActivityManager()
@Published var status: String = "Status Unknown"
override init() {
super.init()
startActivityUpdates()
}
func startActivityUpdates() {
guard CMMotionActivityManager.isActivityAvailable() else {
status = "Motion data not available"
return
}
motionManager.startActivityUpdates(to: .main) { [weak self] activity in
guard let self = self, let activity = activity else { return }
DispatchQueue.main.async {
if activity.running {
self.status = "Running"
} else if activity.walking {
self.status = "Walking"
} else if activity.automotive {
self.status = "In a vehicle"
} else if activity.cycling {
self.status = "Cycling"
} else if activity.stationary {
self.status = "Stationary"
} else {
self.status = "Unknown activity"
}
}
}
}
}
결과 :
정말 책상이나 정지한 곳에 기기를 놓아두지 두지 않는 이상 stationary가 뜨지 않는다.
조금이라도 움직임이 감지되면 unknown으로 분류되어버린다.
작은 움직임정도는 허용해야 하는데, 너무 정밀하게 판단하는 듯 하여 지금 구현하고자 하는 기능에는 적합하지 않다고 생각했다.
더불어 Running 과 Walking 등은 어떤 상황에 반환되는지도 궁금하다.
시도한 방법 2: CoreLocation - speed를 이용
테스트코드
import CoreLocation
import SwiftUI
class LocationManager: NSObject, CLLocationManagerDelegate, ObservableObject {
var locationManager = CLLocationManager()
@Published var location: CLLocation?
@Published var speed: Double = 0.0
override init() {
super.init()
locationManager.delegate = self
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let latestLocation = locations.last {
location = latestLocation
speed = latestLocation.speed
}
}
}
struct CoreLocationView: View {
@ObservedObject var locationManager = LocationManager()
@State private var showAlert = false
var body: some View {
VStack {
Text("Location: \(locationManager.locationManager.location?.coordinate ?? CLLocationCoordinate2D())")
Text("Speed: \(locationManager.locationManager.location?.speed ?? -100 )")
.font(.largeTitle)
.padding()
.onChange(of: locationManager.speed) {
if locationManager.speed > 0.5 {
showAlert = true
}
}
}
.alert(isPresented: $showAlert) {
Alert(title: Text("Speed Alert!"), message: Text("Your speed is above 0.5 m/s!"), dismissButton: .default(Text("OK")))
}
}
}
결과 :
CMMotionActivity처럼 enum형의 케이스가 아닌
기기의 speed수치를 받아와 원하는 조건 범위를 설정할 수 있다.
가만히 앉아 팔을 휘두르는 것 만으로 0.5 이상이 나오기도 하는데, 이 정도면 정지한 상태라고 파악해도 되지 않을까 싶어
임의로 0.5로 정지 상태를 판단하기로 했다.
speed를 내부적으로 어떻게 계산하는지는 좀 더 찾아봐야 할 듯하다!
테스트 시 마주했던 변수들 :
Core Location은 GPS신호를 기반으로 하는 것으로 알고 있는데,
이 신호가 약할 수 있는 조건(예를 들어 깊은 실내 등)에서 speed값이 잘 감지가 되지 않는 경우들이 있었다.
감지가 불가능할 때 -1 값이 뜨는 듯하다.
그리고, locationManager가 초기화될 때 즉, 앱을 켰을 때
한번씩 speed값이 튄다. 그래서 키자마자 alert가 뜨는 경우가 종종 발생했다.
이건 차차 고쳐 나가야 겠다.
참고한 블로그
https://coledennis.medium.com/tutorial-connecting-core-location-to-a-swiftui-app-dc62563bd1de
Tutorial: Connecting Core Location to a SwiftUI App
How to connect Apple’s Core Location service to a SwiftUI App
coledennis.medium.com
Core Location and CLLocationSpeed for getting speed of the device
Core Location is a powerful framework used in iOS development to get the user’s location data. It is used to determine the user’s current location, altitude, and course. It also provides the ability…
medium.com