Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
50
Help us understand the problem. What is going on with this article?
@sato-shin

iOSで正しく歩数を取得する

More than 1 year has passed since last update.

この記事は、以下の資料をqiita用の記事にしたものです。
https://speakerdeck.com/satoshin/getting-step-count-on-ios

はじめに

iOSで歩数を取得する方法には以下の二つの方法があります。

  • CMPedometerから取得する方法
  • HealthKitから取得する方法

HealthKitの方では、取得方法を間違えると実際のデータと大きく異なるので注意してください。

CMPedometerから取得する

let pedometer = CMPedometer()
 pedometer.queryPedometerData(from: start, to: end) { (data, error) in
    print(data?.numberOfSteps)
}
  • start ~ end までの間で端末で検知した歩数を取得
    • AppleWatchの情報取得はWatchAppで実装する必要あり
  • 取得できるのは過去7日分

HealthKitから取得する

:warning: HKSampleQuery で取得する

HealthKitでは、いつ、何時に何歩歩いたかと言う情報をHealthStoreに保持しています。
HealthStoreからデータを取得する方法の一つにHKSampleQueryを利用できます。
取得したデータの合計値を計算すれば良いかと考えられますが、この方法はやってはいけないダメな方法です。

なぜなら、HealthStoreにはiPhoneApple Watchが自動記録した歩数データが入っているため、
素直に足し合わせてしまうと、二つの歩数計データを足し合わせてしまうことになります。

iPhoneだけでテストしてしまうと、一見正しい情報に見えてしまうため注意です。

間違った取得方法-HKSampleQueryで取得した合計値を表示する
let store = HKHealthStore()
let type = HKSampleType.quantityType(forIdentifier: .stepCount)!
let predicate = HKQuery.predicateForSamples(withStart: start, end: end)
let query = HKSampleQuery(sampleType: type, 
                          predicate: predicate, 
                          limit: HKObjectQueryNoLimit, 
                          sortDescriptors: nil) { (query, result, error) in
    let result = result as! [HKQuantitySample]
    let sum = result(0) { $0 + $1.quantity.doubleValue(for: .count()) }
    print(sum)
}
store.execute(query)

:o: HKStatisticsQuery / HKStatisticsCollectionQuery で取得する

多くの場合において、一つ一つの歩数を取得したいのではなく、データの特徴を知りたいはずです。
この場合は HKStatisticsQuery / HKStatisticsCollectionQuery を利用しましょう。

以下のサンプルでは、HKStatisticsQueryを利用しています。特定のイベントで取得したい場合にはこれで十分です。
が、 HKStatisticsCollectionQuery では データ更新のハンドリングができ、取得時間範囲の指定にDateComponentが使えるので、こちらの方が便利な場合も多いです。

HKStatisticsQueryで歩数を取得する
let store = HKHealthStore()
let type = HKSampleType.quantityType(forIdentifier: .stepCount)!
let predicate = HKQuery.predicateForSamples(withStart: start, end: end) 
let query = HKStatisticsQuery(quantityType: type, 
                              quantitySamplePredicate: predicate, 
                              options: .cumulativeSum) { (query, statistics, error) in
     print(statistics?.sumQuantity())
}
store.execute(query)

不正対策

HealthKitから取得する歩数は、時間がかぶっていなければサードパーティのアプリやHealthAppから手動で登録した値も加算されます。
これでは、歩いた歩数がポイントになるアプリなどでは、歩いていないのに多くのポイントを入手することが可能になってしまいます。

HealthStoreに保存された各データには、登録したアプリのBundle Identifierのデータも一緒に書き込まれています。
よってこれでフィルタリングすれば、iPhone、AppleWatchの自動歩数記録機能から保存されたデータのみを抽出することができます。

自動歩数記録機能で記録されたデータとHealthAppのBundle Identifierは以下です。

  • 自動歩数記録機能: com.apple.health.[Device ID] (Device ID部分は端末によって変わります)
  • HealthApp: com.apple.Health

よって、hasPrefix("com.apple.health")で判定してあげればOKです。

自動記録された歩数だけを取得する
let store = HKHealthStore()
let type = HKSampleType.quantityType(forIdentifier: .stepCount)!
let datePredicate = HKQuery.predicateForSamples(withStart: start, end: end)
let query = HKStatisticsQuery(quantityType: type, 
                              quantitySamplePredicate: datePredicate, 
                              options: .separateBySource)
    { (query, data, error) in
    if let sources = data?.sources?.filter({ $0.bundleIdentifier.hasPrefix("com.apple.health") }) {
        let sourcesPredicate = HKQuery.predicateForObjects(from: Set(sources))
        let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [datePredicate, sourcesPredicate])
        let query = HKStatisticsQuery(quantityType: type, 
                                      quantitySamplePredicate: predicate, 
                                      options: .cumulativeSum) 
        { (query, statistics, error) in
             print(statistics?.sumQuantity())
        }
       store.execute(query)
    }
}
store.execute(query)

サンプルコード

50
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
sato-shin
iOS Developer
asken-inc
ひとびとの明日を今日より健康にする

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
50
Help us understand the problem. What is going on with this article?