19
15

More than 3 years have passed since last update.

[iOS] アプリが終了している状態でもヘルスケアデータの更新を検知できる

Last updated at Posted at 2019-12-07

はじめに

iOSでは、iOSや各アプリから"ヘルスケア"にいろいろなヘルスケアデータが書き込まれます。
iOSアプリはヘルスケアデータをHealthkit経由で読み書きが可能で、またデータの更新を監視することができます。

そして更新の監視はアプリが終了している状態でも有効にすることができる、というのがこの記事の主旨です。

アプリの状態 ヘルスケアデータの更新検知
フォアグラウンドで実行されている 可能
実行されているがフォアグラウンドにない 可能
アプリが終了している 可能 ←ここ

↓のサンプルでは、アプリが終了している状態でヘルスケアへのデータ書き込みを検知して、アプリからローカル通知を送信してます。
※最初左右にスワイプしてるのはヘルスケア以外にアプリ起動してないアピールです

サンプル
sample.gif

実装方法

  1. Healthkitで任意の種類のヘルスケアデータに対して HKObserverQuery を実行する
  2. enableBackgroundDelivery(for:frequency:withCompletion:) を実行する
let objectType = HKSampleType.quantityType(forIdentifier: .bodyMass)!
let query = HKObserverQuery(sampleType: objectType, predicate: nil, updateHandler: { query, completionHandler, error in
    // 更新検知
})
HKHealthStore().execute(query)

// バックグランドでのヘルスケアデータの更新検知を有効にする
HKHealthStore().enableBackgroundDelivery(for: objectType, frequency: .immediate, withCompletion: { success, error in
})
  • 検知できる更新タイミングはenableBackgroundDelivery(for:frequency:withCompletion:)の引数として渡す HKUpdateFrequency で指定した期間に最大1回
    • 指定できる期間は immediate hourly daily weekly 、ただし特定のヘルスケアデータ(歩数など更新頻度が非常に高いものなど)は hourly 以上の頻度でしか検知できない

詳しくは公式ドキュメント参照。

サンプル

以下、体重データの更新を検知してローカル通知を送るサンプルです。

サンプルの動作環境: Xcode11.2.1 iOS13.2

プロジェクト設定

  1. ヘルスケアからデータの読み出しを許可するため、Info.plistに Privacy - Health Share Usage Description をセットする
  2. project -> target -> Signing&Capabilities で以下を設定する
    • HealthKit を有効にする
    • PushNotifications を有効にする(このサンプルでローカル通知を送るため) スクリーンショット 2019-12-05 0.23.03.png

サンプルコード

AppDelegate.swift
import UIKit
import UserNotifications
import HealthKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // プッシュ通知を有効にする
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge], completionHandler: { _, _ in
            DispatchQueue.main.async {
                UIApplication.shared.registerForRemoteNotifications()
            }
        })

        // ヘルスケアから体重データの読み込みを許可
        let objectType = HKSampleType.quantityType(forIdentifier: .bodyMass)!

        HKHealthStore().requestAuthorization(toShare: nil, read: Set([objectType]), completion: { success, error in

        })

        // ヘルスケアデータの更新を検知するクエリ
        let query = HKObserverQuery(sampleType: objectType, predicate: nil, updateHandler: {
            query, completionHandler, error in
            if error != nil {
                return
            }
            // ヘルスケアデータの更新を検知したらローカル通知を送る
            let content = UNMutableNotificationContent()
            content.body = "体重データが更新されました"
            let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3, repeats: false)
            let request = UNNotificationRequest(identifier: "detection-test", content: content, trigger: trigger)
            UNUserNotificationCenter.current().add(request)
            completionHandler()
        })
        HKHealthStore().execute(query)

        // バックグランドでのヘルスケアデータの更新検知を有効にする
        HKHealthStore().enableBackgroundDelivery(for: objectType, frequency: .immediate, withCompletion: { success, error in
        })

        return true
    }
}

参考URL

19
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
15