I am working on an iOS app where I need to detect when a user starts and stops driving using the Apple Core Motion framework. I've implemented the following MotionActivityManager class to handle activity updates and display the detected states in a SwiftUI view.
While I can accurately detect "Stationary" and "Walking" states, detecting the "Driving" (Automotive) state has been unreliable. The accuracy often fails, and the framework frequently misclassifies driving as other states like "Unknown" or "Walking."
Here's the implementation:
@Published var motionStates: [MotionState] = []
@Published var startDate: String = ""
@Published var confidence: String = ""
init() {
setupDefaultStates()
startActivityUpdates()
}
private func setupDefaultStates() {
motionStates = [
MotionState(label: "Stationary", value: false),
MotionState(label: "Walking", value: false),
MotionState(label: "Running", value: false),
MotionState(label: "Automotive", value: false),
MotionState(label: "Cycling", value: false),
MotionState(label: "Unknown", value: false)
]
}
func startActivityUpdates() {
guard CMMotionActivityManager.isActivityAvailable() else {
print("Motion activity is not available.")
return
}
motionActivityManager.startActivityUpdates(to: .main) { [weak self] motion in
guard let self = self, let motion = motion else { return }
DispatchQueue.main.async {
self.updateProperties(with: motion)
}
}
}
private func updateProperties(with motion: CMMotionActivity) {
motionStates = [
MotionState(label: "Stationary", value: motion.stationary),
MotionState(label: "Walking", value: motion.walking),
MotionState(label: "Running", value: motion.running),
MotionState(label: "Automotive", value: motion.automotive),
MotionState(label: "Cycling", value: motion.cycling),
MotionState(label: "Unknown", value: motion.unknown)
]
startDate = dateFormatter.string(from: motion.startDate)
switch motion.confidence {
case .low:
confidence = "Low"
case .medium:
confidence = "Medium"
case .high:
confidence = "High"
@unknown default:
confidence = "Unknown"
}
}
}
struct MotionState: Identifiable { let id = UUID() let label: String let value: Bool }
struct ContentView: View { @StateObject private var motionManager = MotionActivityManager()
var body: some View {
ScrollView {
VStack(spacing: 16) {
ForEach(motionManager.motionStates) { state in
LabelView(label: state.label, value: state.value ? "True" : "False")
}
LabelView(label: "Confidence", value: motionManager.confidence)
}
.padding()
}
.onAppear {
UIApplication.shared.isIdleTimerDisabled = true
motionManager.startActivityUpdates()
}
.navigationTitle("Motion Activity")
}
} Issues:
The motion.automotive state is often not detected accurately. The confidence level remains low for the automotive state, even when the device is clearly in a car.
How can I improve the detection accuracy of the "Driving" state using the Core Motion framework?