Работа с HealthKit. Часть 2

в 18:36, , рубрики: HealthKit, iOS, swift, Блог компании Techmas, разработка под iOS, метки:

Конец и начало года у разработчиков, как правило, всегда наполнены большим количеством проектов. Разобравшись со срочными делами и закатав повыше рукава, мы в Techmas пообещали себе делиться еще бОльшим количеством своих разработок с коллегами.

Несмотря на растущую популярность приложений, которые уже используют HealthKit, спрос на мобильные решения для оценки состояния здоровья продолжает развиваться.

Для пояснения всех основных принципов работы c платформой, мы решили вернуться к примеру из прошлой публикации и дополнить его работой с выборками данных из Health.

Работа с HealthKit. Часть 2 - 1

Введение

Напомним, ранее мы сделали обзор общего функционала HealthKit, рассмотрели приложение для аутентификации в Health и вывода характеристик (characteristics) пользователя. Сейчас мы разберемся с выборками (samples) для чтения и записи новых данных по тренировкам.

Выборки (samples) отличаются от характеристик (characteristics) тем, что они меняются с течением времени и зависят от поведения пользователя. Например, выборки используются для добавления новых данных по тренировкам, их визуализации, определения и расчета дополнительных параметров.

В примере мы покажем как считывать данные по росту и весу пользователя из приложения Health. Далее по ним рассчитаем показатель BMI (индекс массы тела) и добавим полученное значение для отслеживания динамики его изменения.

Работа с HealthKit. Часть 2 - 2

Итак, вернемся к приложению из предыдущей части. Его код находится здесь.

Подготовка выборки

Создадим тестовые данные для выборки в приложение Health.

Для этого выберем на закладке Body Measurements пункт Weight и внесем несколько ключевых точек с информацией о весе (weight) через Add Data Point.

Работа с HealthKit. Часть 2 - 3

Данные можно вводить какие угодно и сколько угодно за разные промежутки времени.

Теперь получим разрешение работы с параметрами выборки. Добавим в функцию авторизации authorizeHealthKit() (отдельно мы говорили об авторизации ранее):

let healthKitTypesToWrite = Set(arrayLiteral:
HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass)!,
    HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierActiveEnergyBurned)!,
    HKObjectType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDistanceWalkingRunning)!
)

Чтение выборки из Health

В нашем примере создадим функцию readMostRecentSample(), которая будет считывать показатели по дате и типу.

Для получения выборки необходимо использовать подкласс HKSampleQuery, который наследуется от HKQuery. По сути, он работает аналогично NSFetchedRequest в Core Data.

При формировании запроса доступны параметры:
1. Тип выборки (например, вес или рост), Type.
2. Условия выделения выборки (период, значения, пр.), NSPredicate.
3. Метод сортировки, NSSortDescriptors.

Второй и третий параметры задаются опционально. После формирования запроса необходимо выполнить executeQuery() для вывода его результата.

В нашем примере создадим метод получения последнего значения для указанного типа выборки. Добавим следующий код в функцию readMostRecentSample():

// 1. Подготовим параметры периода
let past = NSDate.distantPast()
let now = NSDate()
let mostRecentPredicate = HKQuery.predicateForSamplesWithStartDate(past, endDate:now, options: .None)

// 2. Зададим значение сортировки в обратном порядке 
let sortDescriptor = NSSortDescriptor(key:HKSampleSortIdentifierStartDate, ascending: false)

// 3. Ограничим вывод одним значением
let limit = 1

// 4. Выполним построение запроса
let sampleQuery = HKSampleQuery(sampleType: sampleType, predicate: mostRecentPredicate, limit: limit, sortDescriptors: [sortDescriptor])
    { (sampleQuery, results, error ) -> Void in
        
        if let queryError = error {
            completion(nil,error)
            return;
        }
        
        // Выделим крайнее значение
        let mostRecentSample = results!.first as? HKQuantitySample
        
        if completion != nil {
            completion(mostRecentSample,nil)
        }
}

// 5. Выполним сам запрос
self.healthKitStore.executeQuery(sampleQuery)

Наша функция позволяет получать последние данные по выборкам определенного типа. Для простоты, вызов readMostRecentSample() добавим в метод viewDidLoad():

// 1. Подготовка параметра HKSampleType для определения веса
let sampleType = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMass)

// 2. Вызов функции для выделения крайнего значения
self.readMostRecentSample(sampleType!, completion: { (mostRecentWeight, error) -> Void in
    
    if( error != nil )
    {
        print("Error reading weight from HealthKit Store: (error.localizedDescription)")
        return;
    }

Здесь мы используем quantityTypeForIdentifier для определения необходимой выборки, в нашем случае это HKQuantityTypeIdentifierBodyMass.

Расчет значения BMI

Теперь создадим набор для расчета и записи BMI. Он будет рассчитываться по формуле:

bmi = weight / height ^ 2

Как было показано выше, выделяем значение веса (weight) из Health. Таким же образом мы получим рост (height) пользователя (заменив тип данных и формат, используем HKQuantityTypeIdentifierHeight).

Здесь нам понадобится объект HKQuantitySample. Также необходимо указать:

• Тип объекта HKQuantityType для сохранения. В нашем случае это HKQuantityTypeIdentifierBodyMassIndex.
• Объект HKQuantity. Он инициализируется с передаваемым значением из параметра bmi. Важно, что для преобразования скалярного типа Double используется HKUnit.countUnit(), который позволяет конвертировать типы в необходимые единицы измерения.

Тогда расчет BMI будет выглядеть следующим образом:

var weight: HKQuantitySample
var weightLocalizedString = “empty"

weight = (mostRecentWeight as? HKQuantitySample)!;
kilograms = weight.quantity.doubleValueForUnit(HKUnit.gramUnitWithMetricPrefix(.Kilo))
let weightFormatter = NSMassFormatter()
weightFormatter.forPersonMassUse = true;
weightLocalizedString = weightFormatter.stringFromKilograms(kilograms)

print(weightLocalizedString)

let weightInKilograms = kilograms
let heightInMeters: Double = 180

let bmi  = weightInKilograms / heightInMeters * heightInMeters

print(String(format: "%.02f", bmi))

Также отметим использование форматирование результатов с помощью NSMassFormatter. Сам NSMassFormater, в сущности, не является частью HelathKit, но позволяет работать с типами данных Health. В частности, если в приложение используются килограммы, а устройство не использует метрическую систему, мы имеем возможность привести единицы измерения к нужному виду.

Мы не будем останавливаться на вопросах интерфейса, поэтому результаты выведем в консоль.

Добавление новой выборки в Health

Наконец, для записи полученного значения BMI в HelathKit создадим метод saveBMISample(bmi:Double, date:NSDate). Выходные параметры: само значение BMI и дата его регистрации.

// 1. Создадим выборку BMI
let bmiType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBodyMassIndex)
let bmiQuantity = HKQuantity(unit: HKUnit.countUnit(), doubleValue: bmi)
let bmiSample = HKQuantitySample(type: bmiType, quantity: bmiQuantity, startDate: date, endDate: date)

// 2. Сохраним выборку в Health
healthKitStore.saveObject(bmiSample, withCompletion: { (success, error) -> Void in
if( error != nil ) {
  println("Error saving BMI sample: (error.localizedDescription)")
} else {
  println("BMI sample saved successfully!")
}
})

Новое значение BMI доступно как для стандартного просмотра, так и может быть использовано сторонним авторизованным приложением.

Примечание

На практике все методы для работы c HealthKit имеет смысл вынести в отдельный класс.
Для нашего примера мы ограничились лишь демонстрацией ключевых этапов работы с платформой.

Код конечного приложения находится здесь.

Автор: Techmas

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js