HealthKitReporter 3.0.0

HealthKitReporter 3.0.0

kronvel2014 维护。



HealthKitReporter

关于

HealthKit Apple 框架数据操作的包装器。该库支持操作来自 HealthKit 仓库的值,并将它们转换为 Codable 模型,允许将结果编码为简单的 JSON 有效负载。此外,您可以使用 Codable 包装器编写自己的 HealthKit 对象,这些对象将被转换为 HealthKit 仓库中的 HKObjectType 对象。

开始

准备

首先,在您的应用程序权限中选中HealthKit,并在您的应用程序的info.plist文件中添加权限

<key>NSHealthShareUsageDescription</key>
<string>WHY_YOU_NEED_TO_SHARE_DATA</string>
<key>NSHealthUpdateUsageDescription</key>
<string>WHY_YOU_NEED_TO_USE_DATA</string>

如果您计划使用WorkoutRoute 系列,请另外提供CoreLocation权限

<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>WHY_YOU_NEED_TO_ALWAYS_SHARE_LOCATION</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>WHY_YOU_NEED_TO_SHARE_LOCATION</string>

通用用法

您在一个do catch块中创建一个HealthKitReporter实例。如果苹果健康不支持该设备(例如iPad),则会调用catch块。

报告实例包含几个属性

  • 读取器
  • 写入器
  • 管理者
  • 观察者

每个属性都负责HealthKit框架的相应部分。从命名可以看出,读取器将处理有关读取数据的所有操作,而写入器将处理与HealthKit库中写入相关的一切,观察者将处理观察并通知 HealthKit 中是否发生任何更改,管理者负责读写类型的授权和启动您制作的WatchApp。

如果您想读取、写入数据或观察数据更改,您必须始终确保数据类型已授权进行读取/写入/观察。在这种情况下,manager使用一个完成块的方法来授权,其中通知授权窗口的出现。注意,苹果健康库将在整个应用程序安装期间仅显示此窗口一次,在这种情况下,如果某些类型被拒绝读取或写入,用户应手动在苹果健康应用程序中允许此操作。

以下示例中,每个操作都在授权块内发生。这样做是有推荐性的,因为如果添加了新类型,则将抛出权限异常。如果确认没有新类型出现,您可以在应用程序中调用授权块外的操作,前提是已授予该类型的数据读取/写入权限。

读取数据

创建一个HealthKitReporter实例。

授权读取所需类型,如步数。

如果授权成功(显示授权窗口),调用步数类型的样本查询以创建一个Query对象。

使用报告者的managerexecuteQuery执行查询。 (或stopQuery停止)

do {
    let reporter = try HealthKitReporter()
    let types = [QuantityType.stepCount]
    reporter.manager.requestAuthorization(
        toRead: types,
        toWrite: types
    ) { (success, error) in
        if success && error == nil {
            reporter.manager.preferredUnits(for: types) { (preferredUnits, error) in
                if error == nil {
                    for preferredUnit in preferredUnits {
                        do {
                            let query = try reporter.reader.quantityQuery(
                                type: try QuantityType.make(from: preferredUnit.identifier),
                                unit: preferredUnit.unit
                            ) { (results, error) in
                                if error == nil {
                                    for element in results {
                                        do {
                                            print(try element.encoded())
                                        } catch {
                                            print(error)
                                        }
                                    }
                                } else {
                                    print(error)
                                }
                            }
                            reporter.manager.executeQuery(query)
                        } catch {
                            print(error)
                        }
                    }
                } else {
                    print(error)
                }
            }
        } else {
            print(error)
        }
    }
} catch {
    print(error)
}

以下是步数的样本响应

{
  "sourceRevision" : {
    "productType" : "iPhone8,1",
    "systemVersion" : "14.0.0",
    "source" : {
      "name" : "Guy’s iPhone",
      "bundleIdentifier" : "com.apple.health.47609E07-490D-4E5F-8E68-9D8904E9BA08"
    },
    "version" : "14.0"
  },
  "harmonized" : {
    "value" : 298,
    "unit" : "count"
  },
  "device" : {
    "softwareVersion" : "14.0",
    "manufacturer" : "Apple Inc.",
    "model" : "iPhone",
    "name" : "iPhone",
    "hardwareVersion" : "iPhone8,1"
  },
  "endTimestamp" : 1601066077.5886581,
  "identifier" : "HKQuantityTypeIdentifierStepCount",
  "startTimestamp" : 1601065755.8829093
}

写入数据

创建一个HealthKitReporter实例。

授权写入所需类型,如步数。

您可以调用管理器的函数来传递单位(对于数量类型)。

如果授权成功(显示授权窗口),请调用包含步骤计数的保存方法。

do {
    let reporter = try HealthKitReporter()
    let types = [QuantityType.stepCount]
    reporter.manager.requestAuthorization(
        toRead: types,
        toWrite: types
    ) { (success, error) in
        if success && error == nil {
            reporter.manager.preferredUnits(for: types) { (preferredUnits, error) in
                for preferredUnit in preferredUnits {
                    //Do write steps
                    let identifier = preferredUnit.identifier
                    guard
                        identifier == QuantityType.stepCount.identifier
                    else {
                        return
                    }
                    let now = Date()
                    let quantity = Quantity(
                        identifier: identifier,
                        startTimestamp: now.addingTimeInterval(-60).timeIntervalSince1970,
                        endTimestamp: now.timeIntervalSince1970,
                        device: Device(
                            name: "Guy's iPhone",
                            manufacturer: "Guy",
                            model: "6.1.1",
                            hardwareVersion: "some_0",
                            firmwareVersion: "some_1",
                            softwareVersion: "some_2",
                            localIdentifier: "some_3",
                            udiDeviceIdentifier: "some_4"
                        ),
                        sourceRevision: SourceRevision(
                            source: Source(
                                name: "mySource",
                                bundleIdentifier: "com.kvs.hkreporter"
                            ),
                            version: "1.0.0",
                            productType: "CocoaPod",
                            systemVersion: "1.0.0.0",
                            operatingSystem: SourceRevision.OperatingSystem(
                                majorVersion: 1,
                                minorVersion: 1,
                                patchVersion: 1
                            )
                        ),
                        harmonized: Quantity.Harmonized(
                            value: 123.0,
                            unit: preferredUnit.unit,
                            metadata: nil
                        )
                    )
                    reporter.writer.save(sample: quantity) { (success, error) in
                        if success && error == nil {
                            print("success")
                        } else {
                            print(error)
                        }
                    }
                }
            }
        } else {
            print(error)
        }
    }
} catch {
    print(error)
}

提示:如果您在选择要保存的对象的单位时遇到困难,可以调用管理器的一个函数,这将返回一个字典,其中键为数量类型的标识符以及当前本地化首选项的单位。

reporter.manager.preferredUnits(for: [.stepCount]) { (dictionary, error) in
    for (identifier, unit) in dictionary {
        print("\(identifier) - \(unit)")
    }
}

观测数据

创建一个HealthKitReporter实例。

授权读取/写入所需类型,如步数和睡眠分析。

您可能创建一个HealthKit每次都会调用的应用,并接收通知,指示HealthKit中某些数据已更改,具体取决于频率。但请注意,有时您设置的所需频率可能无法由HealthKit满足。

在您的AppDelegate的方法中调用观测查询方法。这将允许Apple Health在应用在后台中发送事件,甚至在它之前已处于"不运行"状态时唤醒应用并执行observerQuery更新处理程序提供的代码。

警告:要使应用被系统杀掉时运行observerQuery,提供一个额外的功能Background Mode并选择Background fetch

使用报告者的managerexecuteQuery执行查询。 (或stopQuery停止)

func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
    do {
        let reporter = try HealthKitReporter()
        let types: [SampleType] = [
            QuantityType.stepCount,
            CategoryType.sleepAnalysis
        ]
        reporter.manager.requestAuthorization(
            toRead: types,
            toWrite: types
        ) { (success, error) in
            if success && error == nil {
                for type in types {
                    do {
                        let query = try reporter.observer.observerQuery(
                            type: type
                        ) { (query, identifier, error) in
                            if error == nil && identifier != nil {
                                print("updates for \(identifier!)")
                            }
                        }
                        reporter.observer.enableBackgroundDelivery(
                            type: type,
                            frequency: .daily
                        ) { (success, error) in
                            if error == nil {
                                print("enabled")
                            }
                        }
                        reporter.manager.executeQuery(query)
                    } catch {
                        print(error)
                    }
                }
            }
        }
    } catch {
        print(error)
    }
    return true
}

示例

要运行示例项目,请复制存储库,并首先从示例目录运行pod install

需求

库支持iOS 9及以上版本。一些特性,如HKHeartbeatSeries,从iOS 13.0开始可用,而HKElectrocardiogramm则从iOS 14.0开始可用。

安装

Cocoapods

HealthKitReporter通过CocoaPods提供。要安装它,只需将以下行添加到您的Podfile中

pod 'HealthKitReporter'

或者

pod 'HealthKitReporter', '~> 3.0.0'

Swift Package Manager

要安装它,只需将以下行添加到您的Package.swift文件中(或者只需从XCode中使用包管理器并引用此存储库)

dependencies: [
    .package(url: "https://github.com/VictorKachalov/HealthKitReporter.git", from: "3.0.0")
]

Carthage

在您的Cartfile中添加此行

github "VictorKachalov/HealthKitReporter" "3.0.0"

作者

维克多·卡夏洛夫,[保密邮箱]

许可证

HealthKitReporter 在 MIT 许可证下可用。更多信息请参阅 LICENSE 文件。

赞助

如果您认为我的仓库帮助您解决了困难,请不要害羞,请赞助吧!:-)