I started running recently, and I was impressed to see the circle of “fitness record” every day.

The daily “circle” shows the amount of activity, exercise time and standing time during the day.

After opening the details, you can also see the number of steps you ran, the distance you ran, and the data synchronized from a third party.

Today, our goal is to get the first quantified data: the “fitness log” circle data, the IPhone-provided HealthKit Data export, into a third-party database for subsequent statistics and analysis.

The data source

A quick look at my “health” APP:

With health apps, you can keep all kinds of health and fitness information in one place and have it all under your control. It’s up to you to decide what information to keep and which apps can access your data through the health app. When you lock your phone with a password, touch ID or face ID, all health and exercise data in the health app is encrypted, with the exception of information in the medical emergency card. With iCloud, you can keep your health data up to date automatically on all your devices, both in transit and stored. Also, apps that access HealthKit must have a privacy policy, so be sure to review these policies carefully before granting them access to your health and fitness data.

Let’s take a look at which third-party apps are authorized to access our health data:

Export data

With the data source in place, the next step is to consider how to export the health data. Based on our understanding of HealthKit, we need to develop an iOS app ourselves to obtain health data and upload it to our server to achieve the goal of data export.

This “circle” chart is my data on November 9th. Today’s goal is to obtain the data of this circle through HealthKit, mainly including:

  1. Active data: 1048 kcal
  2. Workout time: 92 minutes
  3. Standing time: 11 hours

The development of preparation

When creating an iOS app ID, you need to have “HealthKit” capabilities:

Add the following two items to the info.plist configuration:

MBHealthTracker

Referring to the HealthKit development documentation, to get loop motion statistics, use an ActivitySummaryQuery, or HKActivitySummaryQuery.

The result field type is HKActivitySummary.

HKActivitySummaryQuery

A query for read activity summary objects from the HealthKit store.

Reference: developer.apple.com/documentati…

HKActivitySummary

An object that contains the move, exercise, and stand data for a given day.

Reference: developer.apple.com/documentati…

Now that we know the HKActivitySummaryQuery and HKActivitySummary, we’re ready to move on to development.

Here I mainly use “MBHealthTracker”, MBHealthTracker encapsulates the authorization to interact with HealthKit, get data and so on, as long as the direct call.

MBHealthTracker lot: github.com/matybrennan…

When I found that MBHealthTracker does not have the corresponding function to obtain HKActivitySummary, we need to add the corresponding method to obtain the dus on the basis of MBHealthTracker.

ActivitySummaryService

First add ActivitySummary model under Presentation, mainly create array.

import Foundation
import HealthKit

public struct ActivitySummary {
    public let items: [HKActivitySummary]}Copy the code

Next, at the Business Logic layer, create the protocol and implementation method:

// ActivitySummaryServiceProtocol.swift
import Foundation
import HealthKit

public protocol ActivitySummaryServiceProtocol {
    
    // Get ActivitySummary based on the start and end times
    func getActivitySummary(startDate: Date, endDate: Date, completionHandler: @escaping (MBAsyncCallResult<ActivitySummary>) -> Void) throws
}

// ActivitySummaryService.swift
import Foundation
import HealthKit

class ActivitySummaryService {
    public init() {}}extension ActivitySummaryService: ActivitySummaryServiceProtocol {
    
    func getActivitySummary(startDate: Date, endDate: Date, completionHandler: @escaping (MBAsyncCallResult<ActivitySummary>) -> Void) throws {
        
        
        try isDataStoreAvailable()
        
        // Create the date components for the predicate
        guard let calendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian) else {
            fatalError("*** This should never fail. ***")}let units: NSCalendar.Unit = [.day, .month, .year, .era]
        
        var startDateComponents = calendar.components(units, from: startDate)
        startDateComponents.calendar = calendar as Calendar
        
        var endDateComponents = calendar.components(units, from: endDate)
        endDateComponents.calendar = calendar as Calendar
        
        // Create the predicate for the query
        let summariesWithinRange = HKQuery.predicate(forActivitySummariesBetweenStart: startDateComponents, end: endDateComponents)
         
        // Build the query
        let query = HKActivitySummaryQuery(predicate: summariesWithinRange) { (query, summaries, error) -> Void in
            self.configure(query: query, summaries: summaries, error: error, completionHandler: completionHandler)
        }
        
        healthStore.execute(query)
    }
}

private extension ActivitySummaryService {
    
    func configure(query: HKActivitySummaryQuery, summaries: [HKActivitySummary]? , error: Error? , completionHandler: @escaping(MBAsyncCallResult<ActivitySummary>) -> Void) {
        
        guard error == nil else{ completionHandler(.failed(error!) )return
        }
        let activitySummary = ActivitySummary(items: summaries!)
        completionHandler(.success(activitySummary))
    }
}
Copy the code

Refer to the official website of the demo and MBHealthTracker method, according to the gourd gourd write good implementation class, simple code, will not elaborate.

All that remains is to load the methods in MBHealthTrackerProtocol and MBHealthTracker.

// MBHealthTrackerProtocol.swift
var activitySummary: ActivitySummaryServiceProtocol { get }

// MBHealthTracker.swift
private lazy var privateActivitySummaryService: ActivitySummaryServiceProtocol = {
    return ActivitySummaryService()} ()...public var activitySummary: ActivitySummaryServiceProtocol {
    return privateActivitySummaryService
}
Copy the code

Now that we’re done getting the data, the next step is to configure and get authorization to read ActivitySummary data.

/// Just has read capabilities
public enum MBReadType: ReadableType {
    
    // Characteristics
    case dob
    case gender
    case activitySummary
    
    public var readable: HKObjectType {
        switch self {
        case .dob:
            return HKCharacteristicType.characteristicType(forIdentifier: .dateOfBirth)!
        case .gender:
            return HKCharacteristicType.characteristicType(forIdentifier: .biologicalSex)!
        case .activitySummary: return HKActivitySummaryType.activitySummaryType()
        }
    }
}
Copy the code

We’re all set. Let’s test it out and see how it works.

import Foundation
import HealthKit

protocol ViewInteractorProtocol {
    func configurePermissions(a)
    func runTest(a)
}

class ViewInteractor {
    
    private let healthTracker: MBHealthTrackerProtocol
    
    init(healthTracker: MBHealthTrackerProtocol) {
        self.healthTracker = healthTracker
    }
}

// MARK: - ViewInteractorProtocol
extension ViewInteractor: ViewInteractorProtocol {
    
    // Configure the categories for write and read authorization
    func configurePermissions(a) {
        healthTracker.configuration.requestAuthorization(toShare: []
        
        ,toRead: [MBReadType.activitySummary]) { _ in}}// Check the data from 11-9 to 11-3
    func runTest(a) {
        do {
            print("-----------------get summary begin----------------")
            let date = Date(a)let start = date.parse("2019-11-09")
            let end = date.parse("2019-11-13")
            try healthTracker.activitySummary.getActivitySummary(startDate: start, endDate: end, completionHandler: { (result) in
                print(result)
            })
            print("-----------------get summary end----------------")}catch {
            print("Unable to get: \(error.localizedDescription)")}}}Copy the code

Run the printed result:

success(Lianghua.ActivitySummary(items: [<<HKActivitySummary: 0x2832480c0>: Date=(Year: 2019, Month: 11, Day: 9) Active Energy Burned=(1048.476259360438/310) Apple Exercise Minutes=(92/30) Apple Stand Hours=(12/12)> <<HKActivitySummary: 0x283248180>: Date=(Year: 2019, Month: 11, Day: 10) Active Energy Burned=(474.8101270220084/310) Apple Exercise Minutes=(33/30) Apple Stand Hours=(6/12)> <<HKActivitySummary: 0x283240f00>: Date=(Year: 2019, Month: 11, Day: 11) Active Energy Burned=(357.55/310) Apple Exercise Minutes=(22/30) Apple Stand Hours=(16/12)>, <<HKActivitySummary: 0x283241200>: Date=(Year: 2019, Month: 11, Day: 12) Active Energy Burned=(344.8089999999997/310) Apple Exercise Minutes=(17/30) Apple Stand Hours=(16/12)> <<HKActivitySummary: 0x2832412c0>: Date=(Year: 2019, Month: 11, Day: 13) Active Energy Burned=(181.595/310) Apple Exercise Minutes=(21/30) Apple Stand Hours=(4/12)>])Copy the code

Here we refer to the “circle” diagram at the beginning, which is exactly the same as the data here.

conclusion

After we export health data, we should consider storing it on cloud platform or third-party storage platform for subsequent statistical analysis. What platform do you choose to store data on? We’ll talk about that next time!

recommended

  1. Quantitative opening myself: ziwolianghua. Coding01. Cn / 1.1 HTML

To be continued

Reference:

  1. Developer.apple.com/documentati…
  2. Github.com/openmhealth…
  3. www.openmhealth.org/
  4. www.apple.com/cn/ios/heal…
  5. Github.com/mseemann/he…
  6. Github.com/matybrennan…
  7. www.openmhealth.org/features/ca…
  8. Developer.apple.com/documentati…