My app reports and records location, altitude, rotation and accelerometer data (DeviceMotion) while in the background. This works fine on ios 10.3.3. On IOS 11, I no longer have access motion data while the device is locked. Altitude data and location data is still streaming to the console, though.
Has something changed in IOS 11 that prevents me from accessing motion data or am I doing trying to access it in a way that Apple now blocks like OperationQueue.main
Here is how I'm starting motion updates. If the phone is unlocked, all works fine. If I locking the phone, no more updates.:
let motionManager = self.motionManager
if motionManager.isDeviceMotionAvailable {
motionUpdateInterval = 0.15
motionManager.deviceMotionUpdateInterval = motionUpdateInterval
motionManager.startDeviceMotionUpdates(using: .xArbitraryZVertical, to: OperationQueue.main) {deviceMotion, error in
guard let deviceMotion = deviceMotion else { return }
I can't find anything about Motion background modes changing but it seems there must be a way otherwise RunKeeper, Strava will break. Can someone help me get this working again before IOS11 launch?
Thanks!
Also came across this problem.
Our solution was to ensure we have another background mode enabled and running (in our case location updates + audio) and restart core motion updates when switching background/foreground.
Code sample:
import UIKit
import CoreMotion
final class MotionDetector {
private let motionManager = CMMotionManager()
private let opQueue: OperationQueue = {
let o = OperationQueue()
o.name = "core-motion-updates"
return o
}()
private var shouldRestartMotionUpdates = false
init() {
NotificationCenter.default.addObserver(self,
selector: #selector(appDidEnterBackground),
name: .UIApplicationDidEnterBackground,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(appDidBecomeActive),
name: .UIApplicationDidBecomeActive,
object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self,
name: .UIApplicationDidEnterBackground,
object: nil)
NotificationCenter.default.removeObserver(self,
name: .UIApplicationDidBecomeActive,
object: nil)
}
func start() {
self.shouldRestartMotionUpdates = true
self.restartMotionUpdates()
}
func stop() {
self.shouldRestartMotionUpdates = false
self.motionManager.stopDeviceMotionUpdates()
}
@objc private func appDidEnterBackground() {
self.restartMotionUpdates()
}
@objc private func appDidBecomeActive() {
self.restartMotionUpdates()
}
private func restartMotionUpdates() {
guard self.shouldRestartMotionUpdates else { return }
self.motionManager.stopDeviceMotionUpdates()
self.motionManager.startDeviceMotionUpdates(using: .xArbitraryZVertical, to: self.opQueue) { deviceMotion, error in
guard let deviceMotion = deviceMotion else { return }
print(deviceMotion)
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With