@kingstinct/react-native-healthkit 13.4.0 → 14.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ReactNativeHealthkit.podspec +1 -0
- package/app.plugin.ts +40 -2
- package/ios/BackgroundDeliveryManager.swift +196 -0
- package/ios/CategoryTypeModule.swift +1 -1
- package/ios/CoreModule.swift +24 -0
- package/ios/CorrelationTypeModule.swift +2 -35
- package/ios/ElectrocardiogramModule.swift +2 -34
- package/ios/HeartbeatSeriesModule.swift +2 -34
- package/ios/MedicationModule.swift +3 -35
- package/ios/PredicateHelpers.swift +2 -2
- package/ios/QuantityTypeModule.swift +11 -11
- package/ios/Serializers.swift +58 -90
- package/ios/StateOfMindModule.swift +2 -34
- package/ios/WorkoutProxy.swift +3 -149
- package/ios/generated/HealthkitGenerated.swift +52 -0
- package/lib/commonjs/generated/healthkit.generated.js +745 -0
- package/lib/commonjs/healthkit.ios.js +51 -17
- package/lib/commonjs/healthkit.js +120 -34
- package/lib/commonjs/specs/QuantityTypeModule.nitro.js +1 -0
- package/lib/commonjs/type-tests/generated-typing.js +2 -0
- package/lib/commonjs/types/CategoryType.js +19 -99
- package/lib/commonjs/types/Medication.js +2 -0
- package/lib/commonjs/types/MetadataEnums.js +17 -0
- package/lib/commonjs/types/QuantityType.js +4 -15
- package/lib/commonjs/types/WeatherCondition.js +2 -32
- package/lib/commonjs/types/Workouts.js +3 -98
- package/lib/commonjs/types/index.js +2 -0
- package/lib/module/generated/healthkit.generated.js +742 -0
- package/lib/module/healthkit.ios.js +49 -15
- package/lib/module/healthkit.js +94 -20
- package/lib/module/specs/QuantityTypeModule.nitro.js +1 -0
- package/lib/module/type-tests/generated-typing.js +1 -0
- package/lib/module/types/CategoryType.js +2 -98
- package/lib/module/types/Medication.js +1 -0
- package/lib/module/types/MetadataEnums.js +1 -0
- package/lib/module/types/QuantityType.js +2 -14
- package/lib/module/types/WeatherCondition.js +1 -32
- package/lib/module/types/Workouts.js +2 -98
- package/lib/module/types/index.js +2 -0
- package/lib/typescript/generated/healthkit.generated.d.ts +1006 -0
- package/lib/typescript/healthkit.d.ts +39 -36
- package/lib/typescript/healthkit.ios.d.ts +64 -53
- package/lib/typescript/hooks/useMostRecentQuantitySample.d.ts +3 -2
- package/lib/typescript/hooks/useMostRecentWorkout.d.ts +2 -2
- package/lib/typescript/hooks/useQuantitySampleById.d.ts +5 -4
- package/lib/typescript/hooks/useStatisticsForQuantity.d.ts +2 -2
- package/lib/typescript/hooks/useSubscribeToQuantitySamples.d.ts +1 -1
- package/lib/typescript/modules.d.ts +2 -2
- package/lib/typescript/specs/CategoryTypeModule.nitro.d.ts +3 -3
- package/lib/typescript/specs/CoreModule.nitro.d.ts +15 -0
- package/lib/typescript/specs/QuantityTypeModule.nitro.d.ts +20 -9
- package/lib/typescript/type-tests/generated-typing.d.ts +1 -0
- package/lib/typescript/types/CategoryType.d.ts +10 -104
- package/lib/typescript/types/CategoryTypeIdentifier.d.ts +1 -61
- package/lib/typescript/types/CorrelationType.d.ts +8 -2
- package/lib/typescript/types/ElectrocardiogramSample.d.ts +8 -1
- package/lib/typescript/types/HeartbeatSeries.d.ts +8 -1
- package/lib/typescript/types/InterfaceVerification.d.ts +14 -1
- package/lib/typescript/types/Medication.d.ts +10 -0
- package/lib/typescript/types/MetadataEnums.d.ts +1 -0
- package/lib/typescript/types/QuantitySample.d.ts +9 -1
- package/lib/typescript/types/QuantityType.d.ts +14 -18
- package/lib/typescript/types/QuantityTypeIdentifier.d.ts +1 -671
- package/lib/typescript/types/QueryOptions.d.ts +8 -4
- package/lib/typescript/types/Shared.d.ts +12 -41
- package/lib/typescript/types/StateOfMind.d.ts +8 -1
- package/lib/typescript/types/Subscriptions.d.ts +11 -11
- package/lib/typescript/types/WeatherCondition.d.ts +1 -30
- package/lib/typescript/types/Workouts.d.ts +18 -104
- package/lib/typescript/types/index.d.ts +2 -0
- package/lib/typescript/utils/getMostRecentQuantitySample.d.ts +2 -1
- package/lib/typescript/utils/getMostRecentWorkout.d.ts +2 -1
- package/lib/typescript/utils/getPreferredUnit.d.ts +2 -1
- package/lib/typescript/utils/getQuantitySampleById.d.ts +2 -1
- package/lib/typescript/utils/subscribeToQuantitySamples.d.ts +1 -1
- package/nitrogen/generated/ios/ReactNativeHealthkit-Swift-Cxx-Bridge.hpp +55 -109
- package/nitrogen/generated/ios/ReactNativeHealthkit-Swift-Cxx-Umbrella.hpp +12 -18
- package/nitrogen/generated/ios/c++/HybridCategoryTypeModuleSpecSwift.hpp +5 -14
- package/nitrogen/generated/ios/c++/HybridCoreModuleSpecSwift.hpp +18 -2
- package/nitrogen/generated/ios/c++/HybridCorrelationTypeModuleSpecSwift.hpp +1 -13
- package/nitrogen/generated/ios/c++/HybridElectrocardiogramModuleSpecSwift.hpp +1 -13
- package/nitrogen/generated/ios/c++/HybridHeartbeatSeriesModuleSpecSwift.hpp +2 -14
- package/nitrogen/generated/ios/c++/HybridMedicationModuleSpecSwift.hpp +1 -13
- package/nitrogen/generated/ios/c++/HybridQuantityTypeModuleSpecSwift.hpp +19 -28
- package/nitrogen/generated/ios/c++/HybridStateOfMindModuleSpecSwift.hpp +2 -14
- package/nitrogen/generated/ios/c++/HybridWorkoutProxySpecSwift.hpp +2 -115
- package/nitrogen/generated/ios/swift/CategorySample.swift +4 -329
- package/nitrogen/generated/ios/swift/CategoryTypeIdentifier.swift +112 -108
- package/nitrogen/generated/ios/swift/CategoryTypeIdentifierWriteable.swift +292 -0
- package/nitrogen/generated/ios/swift/CorrelationSample.swift +4 -347
- package/nitrogen/generated/ios/swift/ElectrocardiogramSample.swift +4 -329
- package/nitrogen/generated/ios/swift/FilterForWorkouts.swift +30 -30
- package/nitrogen/generated/ios/swift/FilterForWorkoutsBase.swift +30 -30
- package/nitrogen/generated/ios/swift/GeneralForm.swift +4 -4
- package/nitrogen/generated/ios/swift/HeartbeatSeriesSample.swift +4 -329
- package/nitrogen/generated/ios/swift/HybridCategoryTypeModuleSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridCategoryTypeModuleSpec_cxx.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridCoreModuleSpec.swift +2 -0
- package/nitrogen/generated/ios/swift/HybridCoreModuleSpec_cxx.swift +38 -0
- package/nitrogen/generated/ios/swift/HybridQuantityTypeModuleSpec.swift +6 -6
- package/nitrogen/generated/ios/swift/HybridQuantityTypeModuleSpec_cxx.swift +6 -6
- package/nitrogen/generated/ios/swift/HybridWorkoutProxySpec.swift +1 -27
- package/nitrogen/generated/ios/swift/HybridWorkoutProxySpec_cxx.swift +2 -340
- package/nitrogen/generated/ios/swift/MedicationDoseEvent.swift +4 -329
- package/nitrogen/generated/ios/swift/ObjectTypeIdentifier.swift +492 -492
- package/nitrogen/generated/ios/swift/QuantitySample.swift +4 -329
- package/nitrogen/generated/ios/swift/QuantityTypeIdentifier.swift +380 -384
- package/nitrogen/generated/ios/swift/QuantityTypeIdentifierWriteable.swift +372 -376
- package/nitrogen/generated/ios/swift/{QueryOptionsWithAnchorAndUnit.swift → QueryOptionsWithAnchorAndStringUnit.swift} +5 -5
- package/nitrogen/generated/ios/swift/{QueryOptionsWithSortOrderAndUnit.swift → QueryOptionsWithSortOrderAndStringUnit.swift} +5 -5
- package/nitrogen/generated/ios/swift/QueryStatisticsResponseFromSingleSource.swift +37 -37
- package/nitrogen/generated/ios/swift/SampleTypeIdentifier.swift +492 -492
- package/nitrogen/generated/ios/swift/SampleTypeIdentifierWriteable.swift +482 -486
- package/nitrogen/generated/ios/swift/StateOfMindSample.swift +4 -329
- package/nitrogen/generated/ios/swift/{StatisticsQueryOptions.swift → StatisticsQueryOptionsWithStringUnit.swift} +5 -5
- package/nitrogen/generated/ios/swift/WorkoutSample.swift +4 -402
- package/nitrogen/generated/shared/c++/CategorySample.hpp +8 -100
- package/nitrogen/generated/shared/c++/CategoryTypeIdentifier.hpp +153 -149
- package/nitrogen/generated/shared/c++/CategoryTypeIdentifierWriteable.hpp +328 -0
- package/nitrogen/generated/shared/c++/CorrelationSample.hpp +9 -105
- package/nitrogen/generated/shared/c++/ElectrocardiogramSample.hpp +7 -99
- package/nitrogen/generated/shared/c++/FilterForWorkouts.hpp +13 -13
- package/nitrogen/generated/shared/c++/FilterForWorkoutsBase.hpp +13 -13
- package/nitrogen/generated/shared/c++/GeneralForm.hpp +7 -7
- package/nitrogen/generated/shared/c++/HeartbeatSeriesSample.hpp +8 -100
- package/nitrogen/generated/shared/c++/HybridCategoryTypeModuleSpec.hpp +5 -2
- package/nitrogen/generated/shared/c++/HybridCoreModuleSpec.cpp +2 -0
- package/nitrogen/generated/shared/c++/HybridCoreModuleSpec.hpp +4 -2
- package/nitrogen/generated/shared/c++/HybridQuantityTypeModuleSpec.hpp +15 -15
- package/nitrogen/generated/shared/c++/HybridWorkoutProxySpec.cpp +1 -27
- package/nitrogen/generated/shared/c++/HybridWorkoutProxySpec.hpp +2 -37
- package/nitrogen/generated/shared/c++/MedicationDoseEvent.hpp +7 -99
- package/nitrogen/generated/shared/c++/ObjectTypeIdentifier.hpp +565 -565
- package/nitrogen/generated/shared/c++/QuantitySample.hpp +8 -100
- package/nitrogen/generated/shared/c++/QuantityTypeIdentifier.hpp +407 -411
- package/nitrogen/generated/shared/c++/QuantityTypeIdentifierWriteable.hpp +398 -402
- package/nitrogen/generated/shared/c++/{QueryOptionsWithAnchorAndUnit.hpp → QueryOptionsWithAnchorAndStringUnit.hpp} +11 -11
- package/nitrogen/generated/shared/c++/{QueryOptionsWithSortOrderAndUnit.hpp → QueryOptionsWithSortOrderAndStringUnit.hpp} +11 -11
- package/nitrogen/generated/shared/c++/QueryStatisticsResponseFromSingleSource.hpp +12 -12
- package/nitrogen/generated/shared/c++/SampleTypeIdentifier.hpp +559 -559
- package/nitrogen/generated/shared/c++/SampleTypeIdentifierWriteable.hpp +541 -545
- package/nitrogen/generated/shared/c++/StateOfMindSample.hpp +8 -100
- package/nitrogen/generated/shared/c++/{StatisticsQueryOptions.hpp → StatisticsQueryOptionsWithStringUnit.hpp} +11 -11
- package/nitrogen/generated/shared/c++/WorkoutSample.hpp +7 -120
- package/package.json +5 -2
- package/src/generated/healthkit-schema.json +3680 -0
- package/src/generated/healthkit.generated.ts +1307 -0
- package/src/healthkit.ios.ts +225 -19
- package/src/healthkit.ts +181 -55
- package/src/hooks/useMostRecentQuantitySample.ts +6 -5
- package/src/hooks/useMostRecentWorkout.ts +2 -2
- package/src/hooks/useQuantitySampleById.ts +6 -5
- package/src/hooks/useStatisticsForQuantity.ts +2 -1
- package/src/hooks/useSubscribeToQuantitySamples.ts +1 -1
- package/src/modules.ts +7 -2
- package/src/specs/CategoryTypeModule.nitro.ts +8 -5
- package/src/specs/CoreModule.nitro.ts +20 -0
- package/src/specs/QuantityTypeModule.nitro.ts +81 -7
- package/src/test-setup.ts +2 -0
- package/src/type-tests/generated-typing.ts +133 -0
- package/src/types/CategoryType.ts +52 -148
- package/src/types/CategoryTypeIdentifier.ts +5 -134
- package/src/types/CorrelationType.ts +13 -3
- package/src/types/ElectrocardiogramSample.ts +13 -1
- package/src/types/HeartbeatSeries.ts +13 -1
- package/src/types/InterfaceVerification.ts +38 -1
- package/src/types/Medication.ts +19 -0
- package/src/types/MetadataEnums.ts +15 -0
- package/src/types/QuantitySample.ts +14 -2
- package/src/types/QuantityType.ts +22 -122
- package/src/types/QuantityTypeIdentifier.ts +5 -772
- package/src/types/QueryOptions.ts +11 -4
- package/src/types/Shared.ts +22 -49
- package/src/types/StateOfMind.ts +13 -1
- package/src/types/Subscriptions.ts +19 -13
- package/src/types/WeatherCondition.ts +1 -31
- package/src/types/Workouts.ts +44 -108
- package/src/types/index.ts +2 -0
- package/src/utils/getMostRecentQuantitySample.ts +4 -3
- package/src/utils/getMostRecentWorkout.ts +5 -2
- package/src/utils/getPreferredUnit.ts +5 -4
- package/src/utils/getQuantitySampleById.ts +4 -3
- package/src/utils/subscribeToQuantitySamples.ts +5 -3
- package/nitrogen/generated/ios/swift/HeartRateMotionContext.swift +0 -44
- package/nitrogen/generated/ios/swift/InsulinDeliveryReason.swift +0 -40
- package/nitrogen/generated/ios/swift/WeatherCondition.swift +0 -144
- package/nitrogen/generated/shared/c++/HeartRateMotionContext.hpp +0 -67
- package/nitrogen/generated/shared/c++/InsulinDeliveryReason.hpp +0 -62
- package/nitrogen/generated/shared/c++/WeatherCondition.hpp +0 -88
|
@@ -35,6 +35,7 @@ Pod::Spec.new do |s|
|
|
|
35
35
|
load 'nitrogen/generated/ios/ReactNativeHealthkit+autolinking.rb'
|
|
36
36
|
add_nitrogen_files(s)
|
|
37
37
|
|
|
38
|
+
|
|
38
39
|
# Workaround for Swift 6.2 (Xcode 26): shared_ptr lost automatic CxxConvertibleToBool conformance,
|
|
39
40
|
# causing nitrogen-generated Bool(fromCxx:) calls to fail. Replace with use_count() > 0.
|
|
40
41
|
# This can be removed once nitrogen fixes the codegen template upstream.
|
package/app.plugin.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type ConfigPlugin,
|
|
3
3
|
createRunOncePlugin,
|
|
4
|
+
withAppDelegate,
|
|
4
5
|
withEntitlementsPlist,
|
|
5
6
|
withInfoPlist,
|
|
6
7
|
withPlugins,
|
|
@@ -8,8 +9,6 @@ import {
|
|
|
8
9
|
|
|
9
10
|
import pkg from './package.json'
|
|
10
11
|
|
|
11
|
-
// please note that the BackgroundConfig currently doesn't actually enable background delivery for any types, but you
|
|
12
|
-
// can set it to false if you don't want the entitlement
|
|
13
12
|
type BackgroundConfig = boolean
|
|
14
13
|
|
|
15
14
|
type InfoPlistConfig = {
|
|
@@ -57,10 +56,49 @@ const withInfoPlistPlugin: ConfigPlugin<InfoPlistConfig> = (config, props) => {
|
|
|
57
56
|
})
|
|
58
57
|
}
|
|
59
58
|
|
|
59
|
+
const withAppDelegatePlugin: ConfigPlugin<{
|
|
60
|
+
background?: BackgroundConfig
|
|
61
|
+
}> = (config, props) => {
|
|
62
|
+
if (props?.background === false) {
|
|
63
|
+
return config
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return withAppDelegate(config, (configDelegate) => {
|
|
67
|
+
const contents = configDelegate.modResults.contents
|
|
68
|
+
|
|
69
|
+
// Add import for HealthKit if not already present
|
|
70
|
+
if (!contents.includes('import HealthKit')) {
|
|
71
|
+
configDelegate.modResults.contents =
|
|
72
|
+
configDelegate.modResults.contents.replace(
|
|
73
|
+
/^(import .+\n)/m,
|
|
74
|
+
'$1import HealthKit\n',
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Insert BackgroundDeliveryManager setup into didFinishLaunchingWithOptions
|
|
79
|
+
const setupCall =
|
|
80
|
+
' BackgroundDeliveryManager.shared.setupBackgroundObservers()\n'
|
|
81
|
+
|
|
82
|
+
if (
|
|
83
|
+
!configDelegate.modResults.contents.includes('BackgroundDeliveryManager')
|
|
84
|
+
) {
|
|
85
|
+
// Match the opening of didFinishLaunchingWithOptions and insert after the opening brace
|
|
86
|
+
configDelegate.modResults.contents =
|
|
87
|
+
configDelegate.modResults.contents.replace(
|
|
88
|
+
/(func application\(.+didFinishLaunchingWithOptions.+\{)\n/,
|
|
89
|
+
`$1\n${setupCall}`,
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return configDelegate
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
60
97
|
const healthkitAppPlugin: ConfigPlugin<AppPluginConfig> = (config, props) => {
|
|
61
98
|
return withPlugins(config, [
|
|
62
99
|
[withEntitlementsPlugin, props],
|
|
63
100
|
[withInfoPlistPlugin, props],
|
|
101
|
+
[withAppDelegatePlugin, props],
|
|
64
102
|
])
|
|
65
103
|
}
|
|
66
104
|
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import HealthKit
|
|
3
|
+
|
|
4
|
+
/// Manages HealthKit background delivery by registering observer queries at app launch,
|
|
5
|
+
/// before the JS bridge is available. This is required by Apple — observer queries must
|
|
6
|
+
/// be set up in `application(_:didFinishLaunchingWithOptions:)` to receive background
|
|
7
|
+
/// delivery callbacks after the app has been terminated.
|
|
8
|
+
///
|
|
9
|
+
/// Usage from AppDelegate.swift:
|
|
10
|
+
/// BackgroundDeliveryManager.shared.setupBackgroundObservers()
|
|
11
|
+
///
|
|
12
|
+
/// The types to observe are persisted in UserDefaults by `configureBackgroundTypes()`
|
|
13
|
+
/// called from JS. On subsequent cold launches, the manager reads these and registers
|
|
14
|
+
/// observers immediately, queuing any events until JS subscribes via `drainPendingEvents()`.
|
|
15
|
+
@objc public class BackgroundDeliveryManager: NSObject {
|
|
16
|
+
@objc public static let shared = BackgroundDeliveryManager()
|
|
17
|
+
|
|
18
|
+
private let healthStore = HKHealthStore()
|
|
19
|
+
private let queue = DispatchQueue(label: "com.kingstinct.healthkit.background", attributes: .concurrent)
|
|
20
|
+
private var observerQueries: [String: HKObserverQuery] = [:]
|
|
21
|
+
private var pendingEvents: [(typeIdentifier: String, errorMessage: String?)] = []
|
|
22
|
+
private var jsCallback: ((String, String?) -> Void)?
|
|
23
|
+
private var isSetUp = false
|
|
24
|
+
|
|
25
|
+
static let typesKey = "com.kingstinct.healthkit.backgroundTypes"
|
|
26
|
+
static let frequencyKey = "com.kingstinct.healthkit.backgroundFrequency"
|
|
27
|
+
|
|
28
|
+
private override init() {
|
|
29
|
+
super.init()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/// Call this from AppDelegate.didFinishLaunchingWithOptions to register observer queries
|
|
33
|
+
/// for any previously configured background delivery types.
|
|
34
|
+
@objc public func setupBackgroundObservers() {
|
|
35
|
+
guard HKHealthStore.isHealthDataAvailable() else { return }
|
|
36
|
+
|
|
37
|
+
guard let typeIdentifiers = UserDefaults.standard.stringArray(forKey: BackgroundDeliveryManager.typesKey) else {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let frequencyRaw = UserDefaults.standard.integer(forKey: BackgroundDeliveryManager.frequencyKey)
|
|
42
|
+
let frequency = HKUpdateFrequency(rawValue: frequencyRaw) ?? .immediate
|
|
43
|
+
|
|
44
|
+
registerObservers(typeIdentifiers: typeIdentifiers, frequency: frequency)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/// Persist types and frequency, then register observers for the current session.
|
|
48
|
+
/// Called from JS via CoreModule.configureBackgroundTypes().
|
|
49
|
+
func configure(typeIdentifiers: [String], frequency: HKUpdateFrequency) {
|
|
50
|
+
UserDefaults.standard.set(typeIdentifiers, forKey: BackgroundDeliveryManager.typesKey)
|
|
51
|
+
UserDefaults.standard.set(frequency.rawValue, forKey: BackgroundDeliveryManager.frequencyKey)
|
|
52
|
+
|
|
53
|
+
// Tear down existing observers before re-registering
|
|
54
|
+
tearDown()
|
|
55
|
+
registerObservers(typeIdentifiers: typeIdentifiers, frequency: frequency)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// Subscribe a JS callback. Any events that arrived before JS was ready are flushed immediately.
|
|
59
|
+
func setCallback(_ callback: @escaping (String, String?) -> Void) {
|
|
60
|
+
queue.sync(flags: .barrier) {
|
|
61
|
+
self.jsCallback = callback
|
|
62
|
+
let events = self.pendingEvents
|
|
63
|
+
self.pendingEvents = []
|
|
64
|
+
|
|
65
|
+
for event in events {
|
|
66
|
+
callback(event.typeIdentifier, event.errorMessage)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/// Remove the JS callback (e.g., on teardown).
|
|
72
|
+
func removeCallback() {
|
|
73
|
+
queue.sync(flags: .barrier) {
|
|
74
|
+
self.jsCallback = nil
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// Returns any pending events and clears the queue. Used by CoreModule.subscribeToObserverQuery
|
|
79
|
+
/// to flush events that arrived before JS subscribed.
|
|
80
|
+
func drainPendingEvents() -> [(typeIdentifier: String, errorMessage: String?)] {
|
|
81
|
+
return queue.sync(flags: .barrier) {
|
|
82
|
+
let events = self.pendingEvents
|
|
83
|
+
self.pendingEvents = []
|
|
84
|
+
return events
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// Stop all observer queries and clear state.
|
|
89
|
+
func tearDown() {
|
|
90
|
+
queue.sync(flags: .barrier) {
|
|
91
|
+
for (_, query) in self.observerQueries {
|
|
92
|
+
self.healthStore.stop(query)
|
|
93
|
+
}
|
|
94
|
+
self.observerQueries = [:]
|
|
95
|
+
self.isSetUp = false
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// Clear persisted configuration (disables background delivery on next launch).
|
|
100
|
+
func clearConfiguration() {
|
|
101
|
+
UserDefaults.standard.removeObject(forKey: BackgroundDeliveryManager.typesKey)
|
|
102
|
+
UserDefaults.standard.removeObject(forKey: BackgroundDeliveryManager.frequencyKey)
|
|
103
|
+
tearDown()
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private func registerObservers(typeIdentifiers: [String], frequency: HKUpdateFrequency) {
|
|
107
|
+
queue.sync(flags: .barrier) {
|
|
108
|
+
guard !self.isSetUp else { return }
|
|
109
|
+
self.isSetUp = true
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
for typeIdentifier in typeIdentifiers {
|
|
113
|
+
guard let sampleType = sampleTypeFromString(typeIdentifier) else {
|
|
114
|
+
print("[react-native-healthkit] BackgroundDeliveryManager: skipping unrecognized type \(typeIdentifier)")
|
|
115
|
+
continue
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Use nil predicate to catch all samples, including those written while the app was terminated.
|
|
119
|
+
// The current subscribeToObserverQuery uses Date.init() which misses data from when the app was dead.
|
|
120
|
+
let query = HKObserverQuery(
|
|
121
|
+
sampleType: sampleType,
|
|
122
|
+
predicate: nil
|
|
123
|
+
) { [weak self] (_: HKObserverQuery, completionHandler: @escaping HKObserverQueryCompletionHandler, error: Error?) in
|
|
124
|
+
self?.handleObserverCallback(
|
|
125
|
+
typeIdentifier: typeIdentifier,
|
|
126
|
+
error: error
|
|
127
|
+
)
|
|
128
|
+
// Must call the completion handler promptly so iOS knows we processed the update.
|
|
129
|
+
completionHandler()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
healthStore.execute(query)
|
|
133
|
+
|
|
134
|
+
healthStore.enableBackgroundDelivery(for: sampleType, frequency: frequency) { success, error in
|
|
135
|
+
if let error = error {
|
|
136
|
+
print("[react-native-healthkit] BackgroundDeliveryManager: enableBackgroundDelivery failed for \(typeIdentifier): \(error.localizedDescription)")
|
|
137
|
+
} else if !success {
|
|
138
|
+
print("[react-native-healthkit] BackgroundDeliveryManager: enableBackgroundDelivery returned false for \(typeIdentifier)")
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
queue.sync(flags: .barrier) {
|
|
143
|
+
self.observerQueries[typeIdentifier] = query
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private func handleObserverCallback(typeIdentifier: String, error: Error?) {
|
|
149
|
+
let errorMessage = error?.localizedDescription
|
|
150
|
+
|
|
151
|
+
queue.sync(flags: .barrier) {
|
|
152
|
+
if let callback = self.jsCallback {
|
|
153
|
+
// JS is connected — dispatch to main thread for JSI safety
|
|
154
|
+
DispatchQueue.main.async {
|
|
155
|
+
callback(typeIdentifier, errorMessage)
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
// JS not ready yet — queue the event for later
|
|
159
|
+
self.pendingEvents.append((typeIdentifier: typeIdentifier, errorMessage: errorMessage))
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Local type resolution that doesn't depend on NitroModules (which isn't available at AppDelegate time).
|
|
165
|
+
// Uses the older factory APIs (quantityType(forIdentifier:) etc.) for iOS 13+ compatibility.
|
|
166
|
+
private func sampleTypeFromString(_ identifier: String) -> HKSampleType? {
|
|
167
|
+
if identifier.starts(with: "HKQuantityTypeIdentifier") {
|
|
168
|
+
let typeId = HKQuantityTypeIdentifier(rawValue: identifier)
|
|
169
|
+
return HKSampleType.quantityType(forIdentifier: typeId)
|
|
170
|
+
}
|
|
171
|
+
if identifier.starts(with: "HKCategoryTypeIdentifier") {
|
|
172
|
+
let typeId = HKCategoryTypeIdentifier(rawValue: identifier)
|
|
173
|
+
return HKSampleType.categoryType(forIdentifier: typeId)
|
|
174
|
+
}
|
|
175
|
+
if identifier == "HKWorkoutTypeIdentifier" {
|
|
176
|
+
return HKSampleType.workoutType()
|
|
177
|
+
}
|
|
178
|
+
if identifier.starts(with: "HKCorrelationTypeIdentifier") {
|
|
179
|
+
let typeId = HKCorrelationTypeIdentifier(rawValue: identifier)
|
|
180
|
+
return HKSampleType.correlationType(forIdentifier: typeId)
|
|
181
|
+
}
|
|
182
|
+
if identifier == "HKAudiogramSampleType" {
|
|
183
|
+
return HKObjectType.audiogramSampleType()
|
|
184
|
+
}
|
|
185
|
+
if identifier == "HKDataTypeIdentifierHeartbeatSeries" || identifier == "HKWorkoutRouteTypeIdentifier" {
|
|
186
|
+
return HKObjectType.seriesType(forIdentifier: identifier)
|
|
187
|
+
}
|
|
188
|
+
if identifier == "HKElectrocardiogramType" {
|
|
189
|
+
if #available(iOS 14.0, *) {
|
|
190
|
+
return HKSampleType.electrocardiogramType()
|
|
191
|
+
}
|
|
192
|
+
return nil
|
|
193
|
+
}
|
|
194
|
+
return nil
|
|
195
|
+
}
|
|
196
|
+
}
|
package/ios/CoreModule.swift
CHANGED
|
@@ -430,6 +430,30 @@ class CoreModule: HybridCoreModuleSpec {
|
|
|
430
430
|
}
|
|
431
431
|
}
|
|
432
432
|
|
|
433
|
+
func configureBackgroundTypes(
|
|
434
|
+
typeIdentifiers: [String], updateFrequency: UpdateFrequency
|
|
435
|
+
) -> Promise<Bool> {
|
|
436
|
+
return Promise.async {
|
|
437
|
+
guard let frequency = HKUpdateFrequency(rawValue: Int(updateFrequency.rawValue)) else {
|
|
438
|
+
throw runtimeErrorWithPrefix("Invalid update frequency rawValue: \(updateFrequency)")
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
BackgroundDeliveryManager.shared.configure(
|
|
442
|
+
typeIdentifiers: typeIdentifiers,
|
|
443
|
+
frequency: frequency
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
return true
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
func clearBackgroundTypes() -> Promise<Bool> {
|
|
451
|
+
return Promise.async {
|
|
452
|
+
BackgroundDeliveryManager.shared.clearConfiguration()
|
|
453
|
+
return true
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
433
457
|
func unsubscribeQueries(queryIds: [String]) -> Double {
|
|
434
458
|
let successCounts = queryIds.map { queryId in
|
|
435
459
|
if let query = self._runningQueries[queryId] {
|
|
@@ -24,47 +24,14 @@ func serializeCorrelationSample(correlation: HKCorrelation, unitMap: [HKQuantity
|
|
|
24
24
|
return CorrelationSample(
|
|
25
25
|
correlationType: CorrelationTypeIdentifier(fromString: correlation.correlationType.identifier)!,
|
|
26
26
|
objects: objects,
|
|
27
|
-
metadataFoodType: correlation.metadata?[HKMetadataKeyFoodType] as? String,
|
|
28
27
|
sampleType: serializeSampleType(correlation.sampleType),
|
|
29
28
|
startDate: correlation.startDate,
|
|
30
29
|
endDate: correlation.endDate,
|
|
31
30
|
hasUndeterminedDuration: correlation.hasUndeterminedDuration,
|
|
32
|
-
|
|
33
|
-
metadataWeatherCondition: serializeWeatherCondition(
|
|
34
|
-
correlation.metadata?[HKMetadataKeyWeatherCondition] as? HKWeatherCondition),
|
|
35
|
-
metadataWeatherHumidity: serializeUnknownQuantityTyped(
|
|
36
|
-
quantity: correlation.metadata?[HKMetadataKeyWeatherHumidity] as? HKQuantity),
|
|
37
|
-
metadataWeatherTemperature: serializeUnknownQuantityTyped(
|
|
38
|
-
quantity: correlation.metadata?[HKMetadataKeyWeatherTemperature] as? HKQuantity),
|
|
39
|
-
metadataInsulinDeliveryReason: serializeInsulinDeliveryReason(
|
|
40
|
-
correlation.metadata?[HKMetadataKeyInsulinDeliveryReason] as? HKInsulinDeliveryReason),
|
|
41
|
-
metadataHeartRateMotionContext: serializeHeartRateMotionContext(
|
|
42
|
-
correlation.metadata?[HKMetadataKeyHeartRateMotionContext] as? HKHeartRateMotionContext),
|
|
43
|
-
|
|
31
|
+
metadata: serializeMetadata(correlation.metadata),
|
|
44
32
|
uuid: correlation.uuid.uuidString,
|
|
45
33
|
sourceRevision: serializeSourceRevision(correlation.sourceRevision),
|
|
46
|
-
device: serializeDevice(hkDevice: correlation.device)
|
|
47
|
-
metadata: serializeMetadata(correlation.metadata),
|
|
48
|
-
|
|
49
|
-
metadataExternalUUID: correlation.metadata?[HKMetadataKeyExternalUUID] as? String,
|
|
50
|
-
metadataTimeZone: correlation.metadata?[HKMetadataKeyTimeZone] as? String,
|
|
51
|
-
metadataWasUserEntered: correlation.metadata?[HKMetadataKeyWasUserEntered] as? Bool,
|
|
52
|
-
metadataDeviceSerialNumber: correlation.metadata?[HKMetadataKeyDeviceSerialNumber] as? String,
|
|
53
|
-
metadataUdiDeviceIdentifier: correlation.metadata?[HKMetadataKeyUDIDeviceIdentifier] as? String,
|
|
54
|
-
metadataUdiProductionIdentifier: correlation.metadata?[HKMetadataKeyUDIProductionIdentifier]
|
|
55
|
-
as? String,
|
|
56
|
-
metadataDigitalSignature: correlation.metadata?[HKMetadataKeyDigitalSignature] as? String,
|
|
57
|
-
metadataDeviceName: correlation.metadata?[HKMetadataKeyDeviceName] as? String,
|
|
58
|
-
metadataDeviceManufacturerName: correlation.metadata?[HKMetadataKeyDeviceManufacturerName]
|
|
59
|
-
as? String,
|
|
60
|
-
metadataSyncIdentifier: correlation.metadata?[HKMetadataKeySyncIdentifier] as? String,
|
|
61
|
-
metadataSyncVersion: correlation.metadata?[HKMetadataKeySyncVersion] as? Double,
|
|
62
|
-
metadataWasTakenInLab: correlation.metadata?[HKMetadataKeyWasTakenInLab] as? Bool,
|
|
63
|
-
metadataReferenceRangeLowerLimit: correlation.metadata?[HKMetadataKeyReferenceRangeLowerLimit]
|
|
64
|
-
as? Double,
|
|
65
|
-
metadataReferenceRangeUpperLimit: correlation.metadata?[HKMetadataKeyReferenceRangeUpperLimit]
|
|
66
|
-
as? Double,
|
|
67
|
-
metadataAlgorithmVersion: correlation.metadata?[HKMetadataKeyAlgorithmVersion] as? Double
|
|
34
|
+
device: serializeDevice(hkDevice: correlation.device)
|
|
68
35
|
)
|
|
69
36
|
}
|
|
70
37
|
|
|
@@ -38,42 +38,10 @@ private func serializeECGSample(sample: HKElectrocardiogram, includeVoltages: Bo
|
|
|
38
38
|
startDate: sample.startDate,
|
|
39
39
|
endDate: sample.endDate,
|
|
40
40
|
hasUndeterminedDuration: sample.hasUndeterminedDuration,
|
|
41
|
-
|
|
42
|
-
metadataWeatherCondition: serializeWeatherCondition(
|
|
43
|
-
sample.metadata?[HKMetadataKeyWeatherCondition] as? HKWeatherCondition),
|
|
44
|
-
metadataWeatherHumidity: serializeUnknownQuantityTyped(
|
|
45
|
-
quantity: sample.metadata?[HKMetadataKeyWeatherHumidity] as? HKQuantity),
|
|
46
|
-
metadataWeatherTemperature: serializeUnknownQuantityTyped(
|
|
47
|
-
quantity: sample.metadata?[HKMetadataKeyWeatherTemperature] as? HKQuantity),
|
|
48
|
-
metadataInsulinDeliveryReason: serializeInsulinDeliveryReason(
|
|
49
|
-
sample.metadata?[HKMetadataKeyInsulinDeliveryReason] as? HKInsulinDeliveryReason),
|
|
50
|
-
metadataHeartRateMotionContext: serializeHeartRateMotionContext(
|
|
51
|
-
sample.metadata?[HKMetadataKeyHeartRateMotionContext] as? HKHeartRateMotionContext),
|
|
52
|
-
|
|
41
|
+
metadata: serializeMetadata(sample.metadata),
|
|
53
42
|
uuid: sample.uuid.uuidString,
|
|
54
43
|
sourceRevision: serializeSourceRevision(sample.sourceRevision),
|
|
55
|
-
device: serializeDevice(hkDevice: sample.device)
|
|
56
|
-
metadata: serializeMetadata(sample.metadata),
|
|
57
|
-
|
|
58
|
-
metadataExternalUUID: sample.metadata?[HKMetadataKeyExternalUUID] as? String,
|
|
59
|
-
metadataTimeZone: sample.metadata?[HKMetadataKeyTimeZone] as? String,
|
|
60
|
-
metadataWasUserEntered: sample.metadata?[HKMetadataKeyWasUserEntered] as? Bool,
|
|
61
|
-
metadataDeviceSerialNumber: sample.metadata?[HKMetadataKeyDeviceSerialNumber] as? String,
|
|
62
|
-
metadataUdiDeviceIdentifier: sample.metadata?[HKMetadataKeyUDIDeviceIdentifier] as? String,
|
|
63
|
-
metadataUdiProductionIdentifier: sample.metadata?[HKMetadataKeyUDIProductionIdentifier]
|
|
64
|
-
as? String,
|
|
65
|
-
metadataDigitalSignature: sample.metadata?[HKMetadataKeyDigitalSignature] as? String,
|
|
66
|
-
metadataDeviceName: sample.metadata?[HKMetadataKeyDeviceName] as? String,
|
|
67
|
-
metadataDeviceManufacturerName: sample.metadata?[HKMetadataKeyDeviceManufacturerName]
|
|
68
|
-
as? String,
|
|
69
|
-
metadataSyncIdentifier: sample.metadata?[HKMetadataKeySyncIdentifier] as? String,
|
|
70
|
-
metadataSyncVersion: sample.metadata?[HKMetadataKeySyncVersion] as? Double,
|
|
71
|
-
metadataWasTakenInLab: sample.metadata?[HKMetadataKeyWasTakenInLab] as? Bool,
|
|
72
|
-
metadataReferenceRangeLowerLimit: sample.metadata?[HKMetadataKeyReferenceRangeLowerLimit]
|
|
73
|
-
as? Double,
|
|
74
|
-
metadataReferenceRangeUpperLimit: sample.metadata?[HKMetadataKeyReferenceRangeUpperLimit]
|
|
75
|
-
as? Double,
|
|
76
|
-
metadataAlgorithmVersion: sample.metadata?[HKMetadataKeyAlgorithmVersion] as? Double
|
|
44
|
+
device: serializeDevice(hkDevice: sample.device)
|
|
77
45
|
)
|
|
78
46
|
}
|
|
79
47
|
|
|
@@ -11,42 +11,10 @@ func serializeHeartbeatSeriesSample(sample: HKHeartbeatSeriesSample) async throw
|
|
|
11
11
|
startDate: sample.startDate,
|
|
12
12
|
endDate: sample.endDate,
|
|
13
13
|
hasUndeterminedDuration: sample.hasUndeterminedDuration,
|
|
14
|
-
|
|
15
|
-
metadataWeatherCondition: serializeWeatherCondition(
|
|
16
|
-
sample.metadata?[HKMetadataKeyWeatherCondition] as? HKWeatherCondition),
|
|
17
|
-
metadataWeatherHumidity: serializeUnknownQuantityTyped(
|
|
18
|
-
quantity: sample.metadata?[HKMetadataKeyWeatherHumidity] as? HKQuantity),
|
|
19
|
-
metadataWeatherTemperature: serializeUnknownQuantityTyped(
|
|
20
|
-
quantity: sample.metadata?[HKMetadataKeyWeatherTemperature] as? HKQuantity),
|
|
21
|
-
metadataInsulinDeliveryReason: serializeInsulinDeliveryReason(
|
|
22
|
-
sample.metadata?[HKMetadataKeyInsulinDeliveryReason] as? HKInsulinDeliveryReason),
|
|
23
|
-
metadataHeartRateMotionContext: serializeHeartRateMotionContext(
|
|
24
|
-
sample.metadata?[HKMetadataKeyHeartRateMotionContext] as? HKHeartRateMotionContext),
|
|
25
|
-
|
|
14
|
+
metadata: serializeMetadata(sample.metadata),
|
|
26
15
|
uuid: sample.uuid.uuidString,
|
|
27
16
|
sourceRevision: serializeSourceRevision(sample.sourceRevision),
|
|
28
|
-
device: serializeDevice(hkDevice: sample.device)
|
|
29
|
-
metadata: serializeMetadata(sample.metadata),
|
|
30
|
-
|
|
31
|
-
metadataExternalUUID: sample.metadata?[HKMetadataKeyExternalUUID] as? String,
|
|
32
|
-
metadataTimeZone: sample.metadata?[HKMetadataKeyTimeZone] as? String,
|
|
33
|
-
metadataWasUserEntered: sample.metadata?[HKMetadataKeyWasUserEntered] as? Bool,
|
|
34
|
-
metadataDeviceSerialNumber: sample.metadata?[HKMetadataKeyDeviceSerialNumber] as? String,
|
|
35
|
-
metadataUdiDeviceIdentifier: sample.metadata?[HKMetadataKeyUDIDeviceIdentifier] as? String,
|
|
36
|
-
metadataUdiProductionIdentifier: sample.metadata?[HKMetadataKeyUDIProductionIdentifier]
|
|
37
|
-
as? String,
|
|
38
|
-
metadataDigitalSignature: sample.metadata?[HKMetadataKeyDigitalSignature] as? String,
|
|
39
|
-
metadataDeviceName: sample.metadata?[HKMetadataKeyDeviceName] as? String,
|
|
40
|
-
metadataDeviceManufacturerName: sample.metadata?[HKMetadataKeyDeviceManufacturerName]
|
|
41
|
-
as? String,
|
|
42
|
-
metadataSyncIdentifier: sample.metadata?[HKMetadataKeySyncIdentifier] as? String,
|
|
43
|
-
metadataSyncVersion: sample.metadata?[HKMetadataKeySyncVersion] as? Double,
|
|
44
|
-
metadataWasTakenInLab: sample.metadata?[HKMetadataKeyWasTakenInLab] as? Bool,
|
|
45
|
-
metadataReferenceRangeLowerLimit: sample.metadata?[HKMetadataKeyReferenceRangeLowerLimit]
|
|
46
|
-
as? Double,
|
|
47
|
-
metadataReferenceRangeUpperLimit: sample.metadata?[HKMetadataKeyReferenceRangeUpperLimit]
|
|
48
|
-
as? Double,
|
|
49
|
-
metadataAlgorithmVersion: sample.metadata?[HKMetadataKeyAlgorithmVersion] as? Double
|
|
17
|
+
device: serializeDevice(hkDevice: sample.device)
|
|
50
18
|
)
|
|
51
19
|
}
|
|
52
20
|
|
|
@@ -97,21 +97,6 @@ import NitroModules
|
|
|
97
97
|
startDate: sample.startDate,
|
|
98
98
|
endDate: sample.endDate,
|
|
99
99
|
hasUndeterminedDuration: sample.hasUndeterminedDuration,
|
|
100
|
-
|
|
101
|
-
metadataWeatherCondition: serializeWeatherCondition(
|
|
102
|
-
sample.metadata?[HKMetadataKeyWeatherCondition] as? HKWeatherCondition),
|
|
103
|
-
metadataWeatherHumidity: serializeUnknownQuantityTyped(
|
|
104
|
-
quantity: sample.metadata?[HKMetadataKeyWeatherHumidity] as? HKQuantity),
|
|
105
|
-
metadataWeatherTemperature: serializeUnknownQuantityTyped(
|
|
106
|
-
quantity: sample.metadata?[HKMetadataKeyWeatherTemperature] as? HKQuantity),
|
|
107
|
-
metadataInsulinDeliveryReason: serializeInsulinDeliveryReason(
|
|
108
|
-
sample.metadata?[HKMetadataKeyInsulinDeliveryReason] as? HKInsulinDeliveryReason),
|
|
109
|
-
metadataHeartRateMotionContext: serializeHeartRateMotionContext(
|
|
110
|
-
sample.metadata?[HKMetadataKeyHeartRateMotionContext] as? HKHeartRateMotionContext),
|
|
111
|
-
|
|
112
|
-
uuid: sample.uuid.uuidString,
|
|
113
|
-
sourceRevision: serializeSourceRevision(sample.sourceRevision),
|
|
114
|
-
device: serializeDevice(hkDevice: sample.device),
|
|
115
100
|
metadata: {
|
|
116
101
|
var meta = serializeMetadata(sample.metadata)
|
|
117
102
|
if let nick = info?.nickname {
|
|
@@ -119,26 +104,9 @@ import NitroModules
|
|
|
119
104
|
}
|
|
120
105
|
return meta
|
|
121
106
|
}(),
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
metadataWasUserEntered: sample.metadata?[HKMetadataKeyWasUserEntered] as? Bool,
|
|
126
|
-
metadataDeviceSerialNumber: sample.metadata?[HKMetadataKeyDeviceSerialNumber] as? String,
|
|
127
|
-
metadataUdiDeviceIdentifier: sample.metadata?[HKMetadataKeyUDIDeviceIdentifier] as? String,
|
|
128
|
-
metadataUdiProductionIdentifier: sample.metadata?[HKMetadataKeyUDIProductionIdentifier]
|
|
129
|
-
as? String,
|
|
130
|
-
metadataDigitalSignature: sample.metadata?[HKMetadataKeyDigitalSignature] as? String,
|
|
131
|
-
metadataDeviceName: sample.metadata?[HKMetadataKeyDeviceName] as? String,
|
|
132
|
-
metadataDeviceManufacturerName: sample.metadata?[HKMetadataKeyDeviceManufacturerName]
|
|
133
|
-
as? String,
|
|
134
|
-
metadataSyncIdentifier: sample.metadata?[HKMetadataKeySyncIdentifier] as? String,
|
|
135
|
-
metadataSyncVersion: sample.metadata?[HKMetadataKeySyncVersion] as? Double,
|
|
136
|
-
metadataWasTakenInLab: sample.metadata?[HKMetadataKeyWasTakenInLab] as? Bool,
|
|
137
|
-
metadataReferenceRangeLowerLimit: sample.metadata?[HKMetadataKeyReferenceRangeLowerLimit]
|
|
138
|
-
as? Double,
|
|
139
|
-
metadataReferenceRangeUpperLimit: sample.metadata?[HKMetadataKeyReferenceRangeUpperLimit]
|
|
140
|
-
as? Double,
|
|
141
|
-
metadataAlgorithmVersion: sample.metadata?[HKMetadataKeyAlgorithmVersion] as? Double
|
|
107
|
+
uuid: sample.uuid.uuidString,
|
|
108
|
+
sourceRevision: serializeSourceRevision(sample.sourceRevision),
|
|
109
|
+
device: serializeDevice(hkDevice: sample.device)
|
|
142
110
|
)
|
|
143
111
|
}
|
|
144
112
|
|
|
@@ -71,10 +71,10 @@ func getPredicateForWorkoutBase(_ filter: FilterForWorkouts?) -> FilterForWorkou
|
|
|
71
71
|
return FilterForWorkoutsBase(
|
|
72
72
|
workoutActivityType: filter.workoutActivityType,
|
|
73
73
|
duration: filter.duration,
|
|
74
|
-
|
|
74
|
+
metadata: filter.metadata,
|
|
75
75
|
uuid: filter.uuid,
|
|
76
|
+
sources: filter.sources,
|
|
76
77
|
uuids: filter.uuids,
|
|
77
|
-
metadata: filter.metadata,
|
|
78
78
|
date: filter.date,
|
|
79
79
|
)
|
|
80
80
|
}
|
|
@@ -19,7 +19,7 @@ func emptyStatisticsResponse(from: Date?, to: Date?) -> QueryStatisticsResponse
|
|
|
19
19
|
func queryStatisticsForQuantityInternal(
|
|
20
20
|
quantityType: HKQuantityType,
|
|
21
21
|
statistics: [StatisticsOptions],
|
|
22
|
-
options:
|
|
22
|
+
options: StatisticsQueryOptionsWithStringUnit?
|
|
23
23
|
) async throws -> HKStatistics? {
|
|
24
24
|
let predicate = createPredicateForSamples(options?.filter)
|
|
25
25
|
|
|
@@ -128,7 +128,7 @@ func queryStatisticsCollectionForQuantityInternal(
|
|
|
128
128
|
statistics: [StatisticsOptions],
|
|
129
129
|
anchorDate: Date,
|
|
130
130
|
intervalComponents: IntervalComponents,
|
|
131
|
-
options:
|
|
131
|
+
options: StatisticsQueryOptionsWithStringUnit?
|
|
132
132
|
) async throws -> HKStatisticsCollection? {
|
|
133
133
|
let predicate = createPredicateForSamples(options?.filter)
|
|
134
134
|
|
|
@@ -245,15 +245,15 @@ func serializeStatisticsPerSource(gottenStats: HKStatistics, unit: HKUnit)
|
|
|
245
245
|
|
|
246
246
|
return QueryStatisticsResponseFromSingleSource(
|
|
247
247
|
source: serializeSource(source),
|
|
248
|
+
startDate: gottenStats.startDate,
|
|
249
|
+
endDate: gottenStats.endDate,
|
|
248
250
|
duration: duration,
|
|
249
251
|
averageQuantity: averageQuantity,
|
|
250
252
|
maximumQuantity: maximumQuantity,
|
|
251
253
|
minimumQuantity: minimumQuantity,
|
|
252
254
|
sumQuantity: sumQuantity,
|
|
253
255
|
mostRecentQuantity: mostRecentQuantity,
|
|
254
|
-
mostRecentQuantityDateInterval: mostRecentQuantityDateInterval
|
|
255
|
-
startDate: gottenStats.startDate,
|
|
256
|
-
endDate: gottenStats.endDate
|
|
256
|
+
mostRecentQuantityDateInterval: mostRecentQuantityDateInterval
|
|
257
257
|
)
|
|
258
258
|
}
|
|
259
259
|
}
|
|
@@ -308,7 +308,7 @@ func handleHKNoDataOrThrow<T>(
|
|
|
308
308
|
class QuantityTypeModule: HybridQuantityTypeModuleSpec {
|
|
309
309
|
func queryStatisticsForQuantitySeparateBySource(
|
|
310
310
|
identifier: QuantityTypeIdentifier, statistics: [StatisticsOptions],
|
|
311
|
-
options:
|
|
311
|
+
options: StatisticsQueryOptionsWithStringUnit?
|
|
312
312
|
) -> Promise<[QueryStatisticsResponseFromSingleSource]> {
|
|
313
313
|
return Promise.async {
|
|
314
314
|
let quantityType = try initializeQuantityType(identifier.stringValue)
|
|
@@ -331,7 +331,7 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
|
|
|
331
331
|
|
|
332
332
|
func queryStatisticsCollectionForQuantitySeparateBySource(
|
|
333
333
|
identifier: QuantityTypeIdentifier, statistics: [StatisticsOptions], anchorDate: Date,
|
|
334
|
-
intervalComponents: IntervalComponents, options:
|
|
334
|
+
intervalComponents: IntervalComponents, options: StatisticsQueryOptionsWithStringUnit?
|
|
335
335
|
) -> Promise<[QueryStatisticsResponseFromSingleSource]> {
|
|
336
336
|
return Promise.async {
|
|
337
337
|
let quantityType = try initializeQuantityType(identifier.stringValue)
|
|
@@ -380,7 +380,7 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
|
|
|
380
380
|
func queryStatisticsForQuantity(
|
|
381
381
|
identifier: QuantityTypeIdentifier,
|
|
382
382
|
statistics: [StatisticsOptions],
|
|
383
|
-
options:
|
|
383
|
+
options: StatisticsQueryOptionsWithStringUnit?
|
|
384
384
|
) -> Promise<QueryStatisticsResponse> {
|
|
385
385
|
return Promise.async {
|
|
386
386
|
let quantityType = try initializeQuantityType(identifier.stringValue)
|
|
@@ -407,7 +407,7 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
|
|
|
407
407
|
|
|
408
408
|
func queryStatisticsCollectionForQuantity(
|
|
409
409
|
identifier: QuantityTypeIdentifier, statistics: [StatisticsOptions], anchorDate: Date,
|
|
410
|
-
intervalComponents: IntervalComponents, options:
|
|
410
|
+
intervalComponents: IntervalComponents, options: StatisticsQueryOptionsWithStringUnit?
|
|
411
411
|
) -> Promise<[QueryStatisticsResponse]> {
|
|
412
412
|
return Promise.async {
|
|
413
413
|
let quantityType = try initializeQuantityType(identifier.stringValue)
|
|
@@ -434,7 +434,7 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
|
|
|
434
434
|
}
|
|
435
435
|
|
|
436
436
|
func queryQuantitySamplesWithAnchor(
|
|
437
|
-
identifier: QuantityTypeIdentifier, options:
|
|
437
|
+
identifier: QuantityTypeIdentifier, options: QueryOptionsWithAnchorAndStringUnit
|
|
438
438
|
) -> Promise<QuantitySamplesWithAnchorResponse> {
|
|
439
439
|
return Promise.async {
|
|
440
440
|
let quantityType = try initializeQuantityType(identifier.stringValue)
|
|
@@ -505,7 +505,7 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
|
|
|
505
505
|
}
|
|
506
506
|
|
|
507
507
|
func queryQuantitySamples(
|
|
508
|
-
identifier: QuantityTypeIdentifier, options:
|
|
508
|
+
identifier: QuantityTypeIdentifier, options: QueryOptionsWithSortOrderAndStringUnit
|
|
509
509
|
) -> Promise<[QuantitySample]> {
|
|
510
510
|
return Promise.async {
|
|
511
511
|
let quantityType = try initializeQuantityType(identifier.stringValue)
|