Accessing device motion data in Swift and Core Motion

When utilised correctly, accessing device motion using Core Motion in iOS can be super useful. If you’re accessing the raw accelerometer and gyroscope data, you can do all sorts of magical UI transformations in real time which can make the user experience much better. It can also be used to ascertain the user’s current motion “state”. And by this I mean whether the user is walking, cycling, stationary, in a car, etc.

This sounds great, but anyone who’s ever tried to use Core Motion knows it’s far from straightforward and processing the raw data from an accelerometer and/or a gyroscope is definitely a challenge (and beyond the scope of this article).

In this brief article, I’m going to focus on the functionality of one particular class in Core Motion, and that’s the CMMotionActivityManager.

CMMotionActivityManager can be used to find out the user’s current or past motion state. There are 2 main interaction points:

  • startActivityUpdates(...) – used to get motion updates periodically
  • queryActivityStarting(...) – used to get historical motion data

Each API call will return an array of CMMotionActivity objects. These objects provide information as to the type of motion iOS thinks your device was involved in.

Simple right? Well this is software development, so give yourself a slap if you thought it would be plain sailing…

To fully understand how this particular part of Core Motion works, I decided to build a test app and log the data for a few days as I moved around.

The good news is, startActivityUpdates performed really well and the data returned and logged from this API seemed pretty much spot on. I did however observe some anomalies with the second API call, queryActivityStarting.

Querying historical Core Motion data works…sometimes

queryActivityStarting occasionally misbehaves and either doesn’t return any motion activities, or returns “unknown” even if you’ve been out running for the last 20 minutes.

I logged the data returned from this call using the following piece of code:

The main situation I found this happening in was when the phone had been left on a surface for some time before making the query.

This also happened much more frequently on iOS 10. I found iOS 11 behaved much much better and around 90% of the time the data was spot on.

I guess the thing to take away from this test is that CMMotionActivityManager actually performs really well without annihilating your battery (yay!). I was a bit surprised especially at how well it performed on iOS 11. If you’re thinking of using it in your app, just be aware it’s not 100% reliable, but we’re certainly getting there with iOS 11.

Leave a comment