The Core Motion framework allows your app access to the sensors on the device. The sensors include the accelerometer, gyroscope, and magnetometer. The CMMotionManager class allows access to each of these to get raw data from them so that your app can detect when the device moves. There are a number of applications for this such as sleep tracking, step counting, to name a few. By using a combination of these sensors, your app can calculate information such as your step count.
Creating a step counter could be quite difficult if you were processing raw data and trying to work out the difference between a step and someone just picking up the phone. Thankfully, Apple does the hard work for you by providing you with the CMPedometer class. This class takes this data and provides you with a step count as well as other information such as cadence etc… To make things even better, Apple also provides 7 days worth of history, thanks to the motion coprocessor (introduced in the iPhone 5s). Even if your app isn’t actively running and tracking step counts, the phone is quietly keeping a log of all step counts and statuses and the CMPedometer is the way we retrieve this data.
CMPedometer Tutorial
First start by creating a single view application. In ViewController.swift you need to import Core Motion as follows:
import CoreMotion
Next we need to create our pedometer. We will create this as follows, just after the class declaration:
let pedometer = CMPedometer()
We can query data by using the following:
if CMPedometer.isStepCountingAvailable() { let calendar = Calendar.current pedometer.queryPedometerData(from: calendar.startOfDay(for: Date()), to: Date()) { (data, error) in print(data) } }
Line 1 we check if step counting is available. There is no point in running the code if for some reason it isn’t available. Make sure you check for this on each call.
Line 2 we get the current calendar which is used in the next line to get a date.
Line 3 we use queryPedometerData and pass in the calendar.startOfDate: function to set the start time of today. We then pass in just Date() to set the end date to right now. We then use the handler which provides us with an optional CMPedometerData object as well as an error if needed. The CMPedometerData class contains everything needed during the specified times (up to 7 days ago) which includes numberOfSteps, distance, averageActivePace, currentPace, currentCadence. Some of those items might return nil, particularly with this query as there is no current cadence for historical data. We are also provided with floorsAscended and floorsDescended.
Line 4 is used to print this data.
If you went ahead and ran this app now, it would crash with an error. Because we are accessing historical step data, Apple puts it behind a privacy window. This means we need to ask the user for permission. The error tells us that we need to add the NSMotionUsageDescription key to the info.plist file and provide a description. We can do that now by opening info.plist and right clicking on the Information Property List key at the top of the list and selecting “Add Row”. Paste in the key name, and then add a string explaining why you want to access the users step count. Try make this succinct as most uses won’t want to read paragraphs of text explaining why you want to access step count. For the test app I just put in “Need to access step count for a test app”. Only you will be reading this, so it isn’t an issue to be accurate here.
When you now run the app you will be asked permission to access the data. Agree to it, and you should see the CMPedometerData logged to the console.
You can provide any dates within the last 7 days and retrieve a step count for any time period such as an hour, minute, day, week, etc…
The startUpdates(from:withHandler:) Instance Method
If you want to be informed each time there is an update to your step count or any other pedometer data, then this is the instance method you need. Unlike the previous version which just returned the pedometer data for the dates specified, this one is long-running and will keep your app informed each time new data is generated.
pedometer.startUpdates(from: Date()) { (data, error) in print(data) }
If you add this code, your app will now see updates each time step data is counted, which is every few seconds if you are moving.
You might have noticed that because we pass in Date() (which is now) as the date, it starts with a step count of zero, and then the step count is then an accumulation of steps since that beginning date. This is useful for a pedometer app that would like to keep the user informed of their live step count. You can pass in dates up to 7 days old, and the handler will calculate the total number of steps since that start date, and then add new steps as the occur.
When you have finished being interested in that data, you should consider calling stopUpdates().
Overall, the CMPedometer provides a very simple way to fetch your step count data, either live, or up to 7 days old.
One thing to remember is that the CMPedometer on the phone provides just the step counts provided by the phone. It doesn’t share data with an Apple Watch. If your app is for users who wear the watch, you would need to also fetch that data and then combine (or get the combined totals when both the watch and phone update HealthKit with step counts).
If you want to find out more information about activity, such as walking, driving, cycling, etc… the CMMotionActivityManager class can be used. We will take a look at this in our next tutorial.
Leave a Reply
You must be logged in to post a comment.