@kingstinct/react-native-healthkit 14.0.1 → 14.1.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/app.plugin.js +13 -7
- package/app.plugin.ts +39 -15
- package/ios/BackgroundDeliveryManager.swift +82 -1
- package/ios/CoreModule.swift +59 -17
- package/ios/ExceptionCatcher.h +1 -0
- package/ios/ExceptionCatcher.mm +15 -0
- package/ios/WorkoutProxy.swift +13 -1
- package/lib/commonjs/generated/healthkit.generated.js +2 -0
- package/lib/module/generated/healthkit.generated.js +2 -0
- package/lib/typescript/generated/healthkit.generated.d.ts +4 -1
- package/lib/typescript/types/Units.d.ts +1 -1
- package/lib/typescript/types/Workouts.d.ts +1 -0
- package/nitrogen/generated/ios/swift/ObjectTypeIdentifier.swift +4 -0
- package/nitrogen/generated/ios/swift/QuantityTypeIdentifier.swift +4 -0
- package/nitrogen/generated/ios/swift/QuantityTypeIdentifierWriteable.swift +4 -0
- package/nitrogen/generated/ios/swift/SampleTypeIdentifier.swift +4 -0
- package/nitrogen/generated/ios/swift/SampleTypeIdentifierWriteable.swift +4 -0
- package/nitrogen/generated/ios/swift/WorkoutActivity.swift +7 -2
- package/nitrogen/generated/shared/c++/ObjectTypeIdentifier.hpp +118 -114
- package/nitrogen/generated/shared/c++/QuantityTypeIdentifier.hpp +111 -107
- package/nitrogen/generated/shared/c++/QuantityTypeIdentifierWriteable.hpp +111 -107
- package/nitrogen/generated/shared/c++/SampleTypeIdentifier.hpp +117 -113
- package/nitrogen/generated/shared/c++/SampleTypeIdentifierWriteable.hpp +116 -112
- package/nitrogen/generated/shared/c++/WorkoutActivity.hpp +9 -3
- package/package.json +1 -1
- package/src/generated/healthkit-schema.json +13 -5
- package/src/generated/healthkit.generated.ts +4 -0
- package/src/type-tests/generated-typing.ts +14 -0
- package/src/types/Units.ts +1 -1
- package/src/types/Workouts.ts +1 -0
package/app.plugin.js
CHANGED
|
@@ -53,20 +53,26 @@ const withEntitlementsPlugin = (
|
|
|
53
53
|
const withInfoPlistPlugin = (
|
|
54
54
|
config,
|
|
55
55
|
/**
|
|
56
|
-
* @type {{NSHealthShareUsageDescription
|
|
56
|
+
* @type {{NSHealthShareUsageDescription?: string | true, NSHealthUpdateUsageDescription?: string | false} | undefined}
|
|
57
57
|
* */
|
|
58
58
|
props,
|
|
59
59
|
) =>
|
|
60
60
|
withInfoPlist(config, (config) => {
|
|
61
61
|
config.modResults.NSHealthShareUsageDescription =
|
|
62
|
-
typeof props
|
|
62
|
+
typeof props?.NSHealthShareUsageDescription === 'string'
|
|
63
63
|
? props.NSHealthShareUsageDescription
|
|
64
|
-
:
|
|
64
|
+
: typeof config.modResults.NSHealthShareUsageDescription === 'string'
|
|
65
|
+
? config.modResults.NSHealthShareUsageDescription
|
|
66
|
+
: `${config.name} wants to read your health data`
|
|
65
67
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
if (props?.NSHealthUpdateUsageDescription !== false) {
|
|
69
|
+
config.modResults.NSHealthUpdateUsageDescription =
|
|
70
|
+
typeof props?.NSHealthUpdateUsageDescription === 'string'
|
|
71
|
+
? props.NSHealthUpdateUsageDescription
|
|
72
|
+
: typeof config.modResults.NSHealthUpdateUsageDescription === 'string'
|
|
73
|
+
? config.modResults.NSHealthUpdateUsageDescription
|
|
74
|
+
: `${config.name} wants to update your health data`
|
|
75
|
+
}
|
|
70
76
|
|
|
71
77
|
return config
|
|
72
78
|
})
|
package/app.plugin.ts
CHANGED
|
@@ -13,7 +13,7 @@ type BackgroundConfig = boolean
|
|
|
13
13
|
|
|
14
14
|
type InfoPlistConfig = {
|
|
15
15
|
NSHealthShareUsageDescription?: string | true
|
|
16
|
-
NSHealthUpdateUsageDescription?: string |
|
|
16
|
+
NSHealthUpdateUsageDescription?: string | false
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
type AppPluginConfig = InfoPlistConfig & {
|
|
@@ -40,17 +40,25 @@ const withEntitlementsPlugin: ConfigPlugin<{
|
|
|
40
40
|
|
|
41
41
|
const withInfoPlistPlugin: ConfigPlugin<InfoPlistConfig> = (config, props) => {
|
|
42
42
|
return withInfoPlist(config, (configPlist) => {
|
|
43
|
+
const existingShareDescription =
|
|
44
|
+
configPlist.modResults.NSHealthShareUsageDescription
|
|
43
45
|
configPlist.modResults.NSHealthShareUsageDescription =
|
|
44
|
-
typeof props
|
|
46
|
+
typeof props?.NSHealthShareUsageDescription === 'string'
|
|
45
47
|
? props.NSHealthShareUsageDescription
|
|
46
|
-
:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
: typeof existingShareDescription === 'string'
|
|
49
|
+
? existingShareDescription
|
|
50
|
+
: `${config.name ?? pkg.name} wants to read your health data`
|
|
51
|
+
|
|
52
|
+
if (props?.NSHealthUpdateUsageDescription !== false) {
|
|
53
|
+
const existingUpdateDescription =
|
|
54
|
+
configPlist.modResults.NSHealthUpdateUsageDescription
|
|
55
|
+
configPlist.modResults.NSHealthUpdateUsageDescription =
|
|
56
|
+
typeof props?.NSHealthUpdateUsageDescription === 'string'
|
|
57
|
+
? props.NSHealthUpdateUsageDescription
|
|
58
|
+
: typeof existingUpdateDescription === 'string'
|
|
59
|
+
? existingUpdateDescription
|
|
60
|
+
: `${config.name ?? pkg.name} wants to update your health data`
|
|
61
|
+
}
|
|
54
62
|
|
|
55
63
|
return configPlist
|
|
56
64
|
})
|
|
@@ -82,12 +90,28 @@ const withAppDelegatePlugin: ConfigPlugin<{
|
|
|
82
90
|
if (
|
|
83
91
|
!configDelegate.modResults.contents.includes('BackgroundDeliveryManager')
|
|
84
92
|
) {
|
|
85
|
-
// Match the opening of didFinishLaunchingWithOptions and insert after the
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
93
|
+
// Match the opening of didFinishLaunchingWithOptions and insert after the
|
|
94
|
+
// opening brace. `[^{]*` rather than `.+` for two reasons: `.` does not
|
|
95
|
+
// match newlines, and Expo SDK 54+ templates spread this signature over
|
|
96
|
+
// several lines; and refusing to cross a `{` keeps the match from
|
|
97
|
+
// spanning out of an earlier `application(...)` overload into this one.
|
|
98
|
+
const withSetup = configDelegate.modResults.contents.replace(
|
|
99
|
+
/(func application\([^{]*didFinishLaunchingWithOptions[^{]*\{)\n/,
|
|
100
|
+
`$1\n${setupCall}`,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
if (withSetup === configDelegate.modResults.contents) {
|
|
104
|
+
// Don't fail the build, but don't fail silently either — background
|
|
105
|
+
// delivery just won't survive app termination, which is otherwise
|
|
106
|
+
// very hard to trace back to here.
|
|
107
|
+
console.warn(
|
|
108
|
+
'[react-native-healthkit] Could not find didFinishLaunchingWithOptions in AppDelegate; ' +
|
|
109
|
+
'BackgroundDeliveryManager.shared.setupBackgroundObservers() was not inserted. ' +
|
|
110
|
+
'HealthKit background delivery will not work until it is added manually.',
|
|
90
111
|
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
configDelegate.modResults.contents = withSetup
|
|
91
115
|
}
|
|
92
116
|
|
|
93
117
|
return configDelegate
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import HealthKit
|
|
3
|
+
import os.log
|
|
4
|
+
|
|
5
|
+
private let bgLog = OSLog(subsystem: "com.kingstinct.healthkit", category: "BackgroundDelivery")
|
|
3
6
|
|
|
4
7
|
/// Manages HealthKit background delivery by registering observer queries at app launch,
|
|
5
8
|
/// before the JS bridge is available. This is required by Apple — observer queries must
|
|
@@ -20,6 +23,11 @@ import HealthKit
|
|
|
20
23
|
private var observerQueries: [String: HKObserverQuery] = [:]
|
|
21
24
|
private var pendingEvents: [(typeIdentifier: String, errorMessage: String?)] = []
|
|
22
25
|
private var jsCallback: ((String, String?) -> Void)?
|
|
26
|
+
// Per-type callbacks, checked before the global `jsCallback` above. Lets
|
|
27
|
+
// CoreModule.subscribeToObserverQuery route a JS subscription for a
|
|
28
|
+
// background-configured type through this manager's already-running
|
|
29
|
+
// HKObserverQuery instead of registering a second, independent one.
|
|
30
|
+
private var typeCallbacks: [String: (String, String?) -> Void] = [:]
|
|
23
31
|
private var isSetUp = false
|
|
24
32
|
|
|
25
33
|
static let typesKey = "com.kingstinct.healthkit.backgroundTypes"
|
|
@@ -85,6 +93,37 @@ import HealthKit
|
|
|
85
93
|
}
|
|
86
94
|
}
|
|
87
95
|
|
|
96
|
+
/// Subscribe a JS callback for a specific type. Any events for this type
|
|
97
|
+
/// that arrived before JS subscribed (e.g. from a background wake, queued
|
|
98
|
+
/// in `pendingEvents` above) are flushed immediately.
|
|
99
|
+
func setCallback(typeIdentifier: String, callback: @escaping (String, String?) -> Void) {
|
|
100
|
+
queue.sync(flags: .barrier) {
|
|
101
|
+
self.typeCallbacks[typeIdentifier] = callback
|
|
102
|
+
let matching = self.pendingEvents.filter { $0.typeIdentifier == typeIdentifier }
|
|
103
|
+
self.pendingEvents.removeAll { $0.typeIdentifier == typeIdentifier }
|
|
104
|
+
for event in matching {
|
|
105
|
+
callback(typeIdentifier, event.errorMessage)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/// Remove the per-type JS callback (e.g., on unsubscribe).
|
|
111
|
+
func removeCallback(typeIdentifier: String) {
|
|
112
|
+
queue.sync(flags: .barrier) {
|
|
113
|
+
self.typeCallbacks.removeValue(forKey: typeIdentifier)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/// True if `typeIdentifier` has a native HKObserverQuery registered by
|
|
118
|
+
/// `registerObservers` — i.e. background delivery is configured for it.
|
|
119
|
+
/// CoreModule.subscribeToObserverQuery checks this before deciding whether
|
|
120
|
+
/// to reuse this manager's observer or register its own.
|
|
121
|
+
func isBackgroundConfigured(typeIdentifier: String) -> Bool {
|
|
122
|
+
return queue.sync {
|
|
123
|
+
self.observerQueries[typeIdentifier] != nil
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
88
127
|
/// Stop all observer queries and clear state.
|
|
89
128
|
func tearDown() {
|
|
90
129
|
queue.sync(flags: .barrier) {
|
|
@@ -92,6 +131,7 @@ import HealthKit
|
|
|
92
131
|
self.healthStore.stop(query)
|
|
93
132
|
}
|
|
94
133
|
self.observerQueries = [:]
|
|
134
|
+
self.typeCallbacks = [:]
|
|
95
135
|
self.isSetUp = false
|
|
96
136
|
}
|
|
97
137
|
}
|
|
@@ -121,6 +161,11 @@ import HealthKit
|
|
|
121
161
|
sampleType: sampleType,
|
|
122
162
|
predicate: nil
|
|
123
163
|
) { [weak self] (_: HKObserverQuery, completionHandler: @escaping HKObserverQueryCompletionHandler, error: Error?) in
|
|
164
|
+
// handleObserverCallback opens a beginBackgroundTask() window as its
|
|
165
|
+
// first, synchronous action, before this returns to call
|
|
166
|
+
// completionHandler() — otherwise iOS is free to suspend the process
|
|
167
|
+
// the moment HealthKit's own completion handler fires, possibly
|
|
168
|
+
// before Hermes has finished booting to run the JS callback.
|
|
124
169
|
self?.handleObserverCallback(
|
|
125
170
|
typeIdentifier: typeIdentifier,
|
|
126
171
|
error: error
|
|
@@ -147,18 +192,54 @@ import HealthKit
|
|
|
147
192
|
|
|
148
193
|
private func handleObserverCallback(typeIdentifier: String, error: Error?) {
|
|
149
194
|
let errorMessage = error?.localizedDescription
|
|
195
|
+
os_log("observer fired: %{public}@", log: bgLog, type: .info, typeIdentifier)
|
|
196
|
+
|
|
197
|
+
// Ask iOS for real execution time before doing anything else, so the
|
|
198
|
+
// process survives long enough for Hermes to boot and the JS callback to
|
|
199
|
+
// run — see the comment at this query's registration above.
|
|
200
|
+
var backgroundTaskId = UIBackgroundTaskIdentifier.invalid
|
|
201
|
+
let endTask: () -> Void = { [weak self] in
|
|
202
|
+
self?.queue.sync(flags: .barrier) {
|
|
203
|
+
guard backgroundTaskId != .invalid else { return }
|
|
204
|
+
UIApplication.shared.endBackgroundTask(backgroundTaskId)
|
|
205
|
+
backgroundTaskId = .invalid
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
backgroundTaskId = UIApplication.shared.beginBackgroundTask(withName: "healthkit-observer-\(typeIdentifier)") {
|
|
209
|
+
os_log("background task expired: %{public}@", log: bgLog, type: .info, typeIdentifier)
|
|
210
|
+
endTask()
|
|
211
|
+
}
|
|
212
|
+
os_log("background task started: %{public}@", log: bgLog, type: .info, typeIdentifier)
|
|
150
213
|
|
|
151
214
|
queue.sync(flags: .barrier) {
|
|
152
|
-
if let callback = self.
|
|
215
|
+
if let callback = self.typeCallbacks[typeIdentifier] {
|
|
216
|
+
DispatchQueue.main.async {
|
|
217
|
+
os_log("dispatching to per-type JS callback: %{public}@", log: bgLog, type: .info, typeIdentifier)
|
|
218
|
+
callback(typeIdentifier, errorMessage)
|
|
219
|
+
}
|
|
220
|
+
} else if let callback = self.jsCallback {
|
|
153
221
|
// JS is connected — dispatch to main thread for JSI safety
|
|
154
222
|
DispatchQueue.main.async {
|
|
223
|
+
os_log("dispatching to global JS callback: %{public}@", log: bgLog, type: .info, typeIdentifier)
|
|
155
224
|
callback(typeIdentifier, errorMessage)
|
|
156
225
|
}
|
|
157
226
|
} else {
|
|
158
227
|
// JS not ready yet — queue the event for later
|
|
228
|
+
os_log("no JS callback yet, queuing: %{public}@", log: bgLog, type: .info, typeIdentifier)
|
|
159
229
|
self.pendingEvents.append((typeIdentifier: typeIdentifier, errorMessage: errorMessage))
|
|
160
230
|
}
|
|
161
231
|
}
|
|
232
|
+
|
|
233
|
+
// Hold the task open for a fixed, generous window rather than trying to
|
|
234
|
+
// ack precisely when JS finishes — Hermes boot plus the JS callback's own
|
|
235
|
+
// async work (HealthKit reads + Supabase upsert) is unpredictable, and a
|
|
236
|
+
// completion-ack channel back from JS isn't worth building on the first
|
|
237
|
+
// pass for a personal-use app. First place to revisit if verification
|
|
238
|
+
// shows this window is too tight.
|
|
239
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 25) {
|
|
240
|
+
os_log("background task window elapsed: %{public}@", log: bgLog, type: .info, typeIdentifier)
|
|
241
|
+
endTask()
|
|
242
|
+
}
|
|
162
243
|
}
|
|
163
244
|
|
|
164
245
|
// Local type resolution that doesn't depend on NitroModules (which isn't available at AppDelegate time).
|
package/ios/CoreModule.swift
CHANGED
|
@@ -157,21 +157,27 @@ class CoreModule: HybridCoreModuleSpec {
|
|
|
157
157
|
returning: .unnecessary
|
|
158
158
|
)
|
|
159
159
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
continuation.resume(returning: authStatus)
|
|
160
|
+
var caughtError: NSError?
|
|
161
|
+
let started = RunBlockCatchingObjCExceptions({
|
|
162
|
+
store.getRequestStatusForAuthorization(toShare: toShare, read: toRead) {
|
|
163
|
+
status, error in
|
|
164
|
+
DispatchQueue.main.async {
|
|
165
|
+
if let error = error {
|
|
166
|
+
continuation.resume(throwing: error)
|
|
168
167
|
} else {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
168
|
+
if let authStatus = AuthorizationRequestStatus(rawValue: Int32(status.rawValue)) {
|
|
169
|
+
continuation.resume(returning: authStatus)
|
|
170
|
+
} else {
|
|
171
|
+
continuation.resume(
|
|
172
|
+
throwing: runtimeErrorWithPrefix(
|
|
173
|
+
"Unrecognized authStatus returned: \(status.rawValue)"))
|
|
174
|
+
}
|
|
172
175
|
}
|
|
173
176
|
}
|
|
174
177
|
}
|
|
178
|
+
}, &caughtError)
|
|
179
|
+
if !started, let caughtError {
|
|
180
|
+
continuation.resume(throwing: caughtError)
|
|
175
181
|
}
|
|
176
182
|
}
|
|
177
183
|
}
|
|
@@ -183,14 +189,20 @@ class CoreModule: HybridCoreModuleSpec {
|
|
|
183
189
|
let toRead = objectTypesFromArray(typeIdentifiers: toRequest.toRead ?? [])
|
|
184
190
|
|
|
185
191
|
return try await withCheckedThrowingContinuation { continuation in
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
+
var caughtError: NSError?
|
|
193
|
+
let started = RunBlockCatchingObjCExceptions({
|
|
194
|
+
store.requestAuthorization(toShare: share, read: toRead) { status, error in
|
|
195
|
+
DispatchQueue.main.async {
|
|
196
|
+
if let error = error {
|
|
197
|
+
continuation.resume(throwing: error)
|
|
198
|
+
} else {
|
|
199
|
+
continuation.resume(returning: status)
|
|
200
|
+
}
|
|
192
201
|
}
|
|
193
202
|
}
|
|
203
|
+
}, &caughtError)
|
|
204
|
+
if !started, let caughtError {
|
|
205
|
+
continuation.resume(throwing: caughtError)
|
|
194
206
|
}
|
|
195
207
|
}
|
|
196
208
|
}
|
|
@@ -349,6 +361,10 @@ class CoreModule: HybridCoreModuleSpec {
|
|
|
349
361
|
}
|
|
350
362
|
|
|
351
363
|
var _runningQueries: [String: HKQuery] = [:]
|
|
364
|
+
// queryId -> typeIdentifier for subscriptions routed through
|
|
365
|
+
// BackgroundDeliveryManager instead of getting their own HKObserverQuery
|
|
366
|
+
// (see subscribeToObserverQuery below).
|
|
367
|
+
var _backgroundRoutedQueries: [String: String] = [:]
|
|
352
368
|
|
|
353
369
|
func deleteObjects(objectTypeIdentifier: SampleTypeIdentifierWriteable, filter: FilterForSamples)
|
|
354
370
|
-> Promise<Double> {
|
|
@@ -377,6 +393,25 @@ class CoreModule: HybridCoreModuleSpec {
|
|
|
377
393
|
typeIdentifier: SampleTypeIdentifier,
|
|
378
394
|
callback: @escaping (OnChangeCallbackArgs) -> Void
|
|
379
395
|
) throws -> String {
|
|
396
|
+
let typeIdString = typeIdentifier.stringValue
|
|
397
|
+
|
|
398
|
+
if BackgroundDeliveryManager.shared.isBackgroundConfigured(typeIdentifier: typeIdString) {
|
|
399
|
+
// BackgroundDeliveryManager already has an HKObserverQuery running for
|
|
400
|
+
// this type (registered at launch, survives termination) — route
|
|
401
|
+
// through it instead of registering a second, independent observer for
|
|
402
|
+
// the same type.
|
|
403
|
+
let queryId = UUID().uuidString
|
|
404
|
+
BackgroundDeliveryManager.shared.setCallback(typeIdentifier: typeIdString) {
|
|
405
|
+
(_, errorMessage) in
|
|
406
|
+
DispatchQueue.main.async {
|
|
407
|
+
callback(
|
|
408
|
+
OnChangeCallbackArgs(typeIdentifier: typeIdentifier, errorMessage: errorMessage))
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
self._backgroundRoutedQueries[queryId] = typeIdString
|
|
412
|
+
return queryId
|
|
413
|
+
}
|
|
414
|
+
|
|
380
415
|
let sampleType = try sampleTypeFrom(sampleTypeIdentifier: typeIdentifier)
|
|
381
416
|
|
|
382
417
|
let predicate = HKQuery.predicateForSamples(
|
|
@@ -411,6 +446,13 @@ class CoreModule: HybridCoreModuleSpec {
|
|
|
411
446
|
}
|
|
412
447
|
|
|
413
448
|
func unsubscribeQuery(queryId: String) throws -> Bool {
|
|
449
|
+
if let typeIdString = self._backgroundRoutedQueries[queryId] {
|
|
450
|
+
BackgroundDeliveryManager.shared.removeCallback(typeIdentifier: typeIdString)
|
|
451
|
+
self._backgroundRoutedQueries.removeValue(forKey: queryId)
|
|
452
|
+
|
|
453
|
+
return true
|
|
454
|
+
}
|
|
455
|
+
|
|
414
456
|
guard let query = self._runningQueries[queryId] else {
|
|
415
457
|
warnWithPrefix("unsubscribeQuery: Query with id \(queryId) not found")
|
|
416
458
|
|
package/ios/ExceptionCatcher.h
CHANGED
|
@@ -2,3 +2,4 @@
|
|
|
2
2
|
#import <HealthKit/HealthKit.h>
|
|
3
3
|
|
|
4
4
|
HKUnit * _Nullable HKUnitFromStringCatchingExceptions(NSString * _Nonnull unitString, NSError * _Nullable * _Nullable outError);
|
|
5
|
+
BOOL RunBlockCatchingObjCExceptions(void (NS_NOESCAPE ^_Nonnull block)(void), NSError * _Nullable * _Nullable outError);
|
package/ios/ExceptionCatcher.mm
CHANGED
|
@@ -15,3 +15,18 @@ HKUnit * _Nullable HKUnitFromStringCatchingExceptions(NSString * _Nonnull unitSt
|
|
|
15
15
|
return nil;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
|
+
|
|
19
|
+
BOOL RunBlockCatchingObjCExceptions(void (NS_NOESCAPE ^block)(void), NSError * _Nullable * _Nullable outError) {
|
|
20
|
+
if (outError) { *outError = nil; }
|
|
21
|
+
@try {
|
|
22
|
+
block();
|
|
23
|
+
return YES;
|
|
24
|
+
}
|
|
25
|
+
@catch (NSException *exception) {
|
|
26
|
+
if (outError) {
|
|
27
|
+
NSDictionary *userInfo = exception.userInfo ?: @{};
|
|
28
|
+
*outError = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
|
|
29
|
+
}
|
|
30
|
+
return NO;
|
|
31
|
+
}
|
|
32
|
+
}
|
package/ios/WorkoutProxy.swift
CHANGED
|
@@ -370,11 +370,23 @@ class WorkoutProxy: HybridWorkoutProxySpec {
|
|
|
370
370
|
let hkActivities = workout.workoutActivities
|
|
371
371
|
|
|
372
372
|
return hkActivities.map { activity in
|
|
373
|
+
let rawActivityType = activity.workoutConfiguration.activityType.rawValue
|
|
374
|
+
let activityType = Int32(exactly: rawActivityType).flatMap {
|
|
375
|
+
WorkoutActivityType.init(rawValue: $0)
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if activityType == nil {
|
|
379
|
+
warnWithPrefix(
|
|
380
|
+
"Unknown workoutActivityType with rawValue: \(rawActivityType), falling back to 'other'"
|
|
381
|
+
)
|
|
382
|
+
}
|
|
383
|
+
|
|
373
384
|
return WorkoutActivity(
|
|
374
385
|
startDate: activity.startDate,
|
|
375
386
|
endDate: activity.endDate ?? activity.startDate,
|
|
376
387
|
uuid: activity.uuid.uuidString,
|
|
377
|
-
duration: activity.duration
|
|
388
|
+
duration: activity.duration,
|
|
389
|
+
activityType: activityType ?? WorkoutActivityType.other
|
|
378
390
|
)
|
|
379
391
|
}
|
|
380
392
|
}
|
|
@@ -18,6 +18,7 @@ exports.QUANTITY_IDENTIFIER_IOS_AVAILABILITY = {
|
|
|
18
18
|
HKQuantityTypeIdentifierBasalEnergyBurned: '8.0',
|
|
19
19
|
HKQuantityTypeIdentifierBloodAlcoholContent: '8.0',
|
|
20
20
|
HKQuantityTypeIdentifierBloodGlucose: '8.0',
|
|
21
|
+
HKQuantityTypeIdentifierBloodKetones: '8.0',
|
|
21
22
|
HKQuantityTypeIdentifierBloodPressureDiastolic: '8.0',
|
|
22
23
|
HKQuantityTypeIdentifierBloodPressureSystolic: '8.0',
|
|
23
24
|
HKQuantityTypeIdentifierBodyFatPercentage: '8.0',
|
|
@@ -212,6 +213,7 @@ exports.QUANTITY_IDENTIFIER_CANONICAL_UNITS = {
|
|
|
212
213
|
HKQuantityTypeIdentifierBasalEnergyBurned: 'kcal',
|
|
213
214
|
HKQuantityTypeIdentifierBloodAlcoholContent: '%',
|
|
214
215
|
HKQuantityTypeIdentifierBloodGlucose: 'mg/dL',
|
|
216
|
+
HKQuantityTypeIdentifierBloodKetones: 'mmol/L',
|
|
215
217
|
HKQuantityTypeIdentifierBloodPressureDiastolic: 'mmHg',
|
|
216
218
|
HKQuantityTypeIdentifierBloodPressureSystolic: 'mmHg',
|
|
217
219
|
HKQuantityTypeIdentifierBodyFatPercentage: '%',
|
|
@@ -15,6 +15,7 @@ export const QUANTITY_IDENTIFIER_IOS_AVAILABILITY = {
|
|
|
15
15
|
HKQuantityTypeIdentifierBasalEnergyBurned: '8.0',
|
|
16
16
|
HKQuantityTypeIdentifierBloodAlcoholContent: '8.0',
|
|
17
17
|
HKQuantityTypeIdentifierBloodGlucose: '8.0',
|
|
18
|
+
HKQuantityTypeIdentifierBloodKetones: '8.0',
|
|
18
19
|
HKQuantityTypeIdentifierBloodPressureDiastolic: '8.0',
|
|
19
20
|
HKQuantityTypeIdentifierBloodPressureSystolic: '8.0',
|
|
20
21
|
HKQuantityTypeIdentifierBodyFatPercentage: '8.0',
|
|
@@ -209,6 +210,7 @@ export const QUANTITY_IDENTIFIER_CANONICAL_UNITS = {
|
|
|
209
210
|
HKQuantityTypeIdentifierBasalEnergyBurned: 'kcal',
|
|
210
211
|
HKQuantityTypeIdentifierBloodAlcoholContent: '%',
|
|
211
212
|
HKQuantityTypeIdentifierBloodGlucose: 'mg/dL',
|
|
213
|
+
HKQuantityTypeIdentifierBloodKetones: 'mmol/L',
|
|
212
214
|
HKQuantityTypeIdentifierBloodPressureDiastolic: 'mmHg',
|
|
213
215
|
HKQuantityTypeIdentifierBloodPressureSystolic: 'mmHg',
|
|
214
216
|
HKQuantityTypeIdentifierBodyFatPercentage: '%',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Quantity } from '../types/QuantityType';
|
|
2
2
|
import type { BloodGlucoseUnit, CountPerTime, EnergyUnit, LengthUnit, MassUnit, PressureUnit, SpeedUnit, TemperatureUnit, TimeUnit } from '../types/Units';
|
|
3
3
|
export type QuantityTypeIdentifierReadOnly = 'HKQuantityTypeIdentifierAppleExerciseTime' | 'HKQuantityTypeIdentifierAppleStandTime' | 'HKQuantityTypeIdentifierAppleWalkingSteadiness' | 'HKQuantityTypeIdentifierAtrialFibrillationBurden' | 'HKQuantityTypeIdentifierWalkingHeartRateAverage';
|
|
4
|
-
export type QuantityTypeIdentifierWriteable = 'HKQuantityTypeIdentifierActiveEnergyBurned' | 'HKQuantityTypeIdentifierAppleMoveTime' | 'HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances' | 'HKQuantityTypeIdentifierAppleSleepingWristTemperature' | 'HKQuantityTypeIdentifierBasalBodyTemperature' | 'HKQuantityTypeIdentifierBasalEnergyBurned' | 'HKQuantityTypeIdentifierBloodAlcoholContent' | 'HKQuantityTypeIdentifierBloodGlucose' | 'HKQuantityTypeIdentifierBloodPressureDiastolic' | 'HKQuantityTypeIdentifierBloodPressureSystolic' | 'HKQuantityTypeIdentifierBodyFatPercentage' | 'HKQuantityTypeIdentifierBodyMass' | 'HKQuantityTypeIdentifierBodyMassIndex' | 'HKQuantityTypeIdentifierBodyTemperature' | 'HKQuantityTypeIdentifierCrossCountrySkiingSpeed' | 'HKQuantityTypeIdentifierCyclingCadence' | 'HKQuantityTypeIdentifierCyclingFunctionalThresholdPower' | 'HKQuantityTypeIdentifierCyclingPower' | 'HKQuantityTypeIdentifierCyclingSpeed' | 'HKQuantityTypeIdentifierDietaryBiotin' | 'HKQuantityTypeIdentifierDietaryCaffeine' | 'HKQuantityTypeIdentifierDietaryCalcium' | 'HKQuantityTypeIdentifierDietaryCarbohydrates' | 'HKQuantityTypeIdentifierDietaryChloride' | 'HKQuantityTypeIdentifierDietaryCholesterol' | 'HKQuantityTypeIdentifierDietaryChromium' | 'HKQuantityTypeIdentifierDietaryCopper' | 'HKQuantityTypeIdentifierDietaryEnergyConsumed' | 'HKQuantityTypeIdentifierDietaryFatMonounsaturated' | 'HKQuantityTypeIdentifierDietaryFatPolyunsaturated' | 'HKQuantityTypeIdentifierDietaryFatSaturated' | 'HKQuantityTypeIdentifierDietaryFatTotal' | 'HKQuantityTypeIdentifierDietaryFiber' | 'HKQuantityTypeIdentifierDietaryFolate' | 'HKQuantityTypeIdentifierDietaryIodine' | 'HKQuantityTypeIdentifierDietaryIron' | 'HKQuantityTypeIdentifierDietaryMagnesium' | 'HKQuantityTypeIdentifierDietaryManganese' | 'HKQuantityTypeIdentifierDietaryMolybdenum' | 'HKQuantityTypeIdentifierDietaryNiacin' | 'HKQuantityTypeIdentifierDietaryPantothenicAcid' | 'HKQuantityTypeIdentifierDietaryPhosphorus' | 'HKQuantityTypeIdentifierDietaryPotassium' | 'HKQuantityTypeIdentifierDietaryProtein' | 'HKQuantityTypeIdentifierDietaryRiboflavin' | 'HKQuantityTypeIdentifierDietarySelenium' | 'HKQuantityTypeIdentifierDietarySodium' | 'HKQuantityTypeIdentifierDietarySugar' | 'HKQuantityTypeIdentifierDietaryThiamin' | 'HKQuantityTypeIdentifierDietaryVitaminA' | 'HKQuantityTypeIdentifierDietaryVitaminB12' | 'HKQuantityTypeIdentifierDietaryVitaminB6' | 'HKQuantityTypeIdentifierDietaryVitaminC' | 'HKQuantityTypeIdentifierDietaryVitaminD' | 'HKQuantityTypeIdentifierDietaryVitaminE' | 'HKQuantityTypeIdentifierDietaryVitaminK' | 'HKQuantityTypeIdentifierDietaryWater' | 'HKQuantityTypeIdentifierDietaryZinc' | 'HKQuantityTypeIdentifierDistanceCrossCountrySkiing' | 'HKQuantityTypeIdentifierDistanceCycling' | 'HKQuantityTypeIdentifierDistanceDownhillSnowSports' | 'HKQuantityTypeIdentifierDistancePaddleSports' | 'HKQuantityTypeIdentifierDistanceRowing' | 'HKQuantityTypeIdentifierDistanceSkatingSports' | 'HKQuantityTypeIdentifierDistanceSwimming' | 'HKQuantityTypeIdentifierDistanceWalkingRunning' | 'HKQuantityTypeIdentifierDistanceWheelchair' | 'HKQuantityTypeIdentifierElectrodermalActivity' | 'HKQuantityTypeIdentifierEnvironmentalAudioExposure' | 'HKQuantityTypeIdentifierEnvironmentalSoundReduction' | 'HKQuantityTypeIdentifierEstimatedWorkoutEffortScore' | 'HKQuantityTypeIdentifierFlightsClimbed' | 'HKQuantityTypeIdentifierForcedExpiratoryVolume1' | 'HKQuantityTypeIdentifierForcedVitalCapacity' | 'HKQuantityTypeIdentifierHeadphoneAudioExposure' | 'HKQuantityTypeIdentifierHeartRate' | 'HKQuantityTypeIdentifierHeartRateRecoveryOneMinute' | 'HKQuantityTypeIdentifierHeartRateVariabilitySDNN' | 'HKQuantityTypeIdentifierHeight' | 'HKQuantityTypeIdentifierInhalerUsage' | 'HKQuantityTypeIdentifierInsulinDelivery' | 'HKQuantityTypeIdentifierLeanBodyMass' | 'HKQuantityTypeIdentifierNikeFuel' | 'HKQuantityTypeIdentifierNumberOfAlcoholicBeverages' | 'HKQuantityTypeIdentifierNumberOfTimesFallen' | 'HKQuantityTypeIdentifierOxygenSaturation' | 'HKQuantityTypeIdentifierPaddleSportsSpeed' | 'HKQuantityTypeIdentifierPeakExpiratoryFlowRate' | 'HKQuantityTypeIdentifierPeripheralPerfusionIndex' | 'HKQuantityTypeIdentifierPhysicalEffort' | 'HKQuantityTypeIdentifierPushCount' | 'HKQuantityTypeIdentifierRespiratoryRate' | 'HKQuantityTypeIdentifierRestingHeartRate' | 'HKQuantityTypeIdentifierRowingSpeed' | 'HKQuantityTypeIdentifierRunningGroundContactTime' | 'HKQuantityTypeIdentifierRunningPower' | 'HKQuantityTypeIdentifierRunningSpeed' | 'HKQuantityTypeIdentifierRunningStrideLength' | 'HKQuantityTypeIdentifierRunningVerticalOscillation' | 'HKQuantityTypeIdentifierSixMinuteWalkTestDistance' | 'HKQuantityTypeIdentifierStairAscentSpeed' | 'HKQuantityTypeIdentifierStairDescentSpeed' | 'HKQuantityTypeIdentifierStepCount' | 'HKQuantityTypeIdentifierSwimmingStrokeCount' | 'HKQuantityTypeIdentifierTimeInDaylight' | 'HKQuantityTypeIdentifierUnderwaterDepth' | 'HKQuantityTypeIdentifierUVExposure' | 'HKQuantityTypeIdentifierVO2Max' | 'HKQuantityTypeIdentifierWaistCircumference' | 'HKQuantityTypeIdentifierWalkingAsymmetryPercentage' | 'HKQuantityTypeIdentifierWalkingDoubleSupportPercentage' | 'HKQuantityTypeIdentifierWalkingSpeed' | 'HKQuantityTypeIdentifierWalkingStepLength' | 'HKQuantityTypeIdentifierWaterTemperature' | 'HKQuantityTypeIdentifierWorkoutEffortScore';
|
|
4
|
+
export type QuantityTypeIdentifierWriteable = 'HKQuantityTypeIdentifierActiveEnergyBurned' | 'HKQuantityTypeIdentifierAppleMoveTime' | 'HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances' | 'HKQuantityTypeIdentifierAppleSleepingWristTemperature' | 'HKQuantityTypeIdentifierBasalBodyTemperature' | 'HKQuantityTypeIdentifierBasalEnergyBurned' | 'HKQuantityTypeIdentifierBloodAlcoholContent' | 'HKQuantityTypeIdentifierBloodGlucose' | 'HKQuantityTypeIdentifierBloodKetones' | 'HKQuantityTypeIdentifierBloodPressureDiastolic' | 'HKQuantityTypeIdentifierBloodPressureSystolic' | 'HKQuantityTypeIdentifierBodyFatPercentage' | 'HKQuantityTypeIdentifierBodyMass' | 'HKQuantityTypeIdentifierBodyMassIndex' | 'HKQuantityTypeIdentifierBodyTemperature' | 'HKQuantityTypeIdentifierCrossCountrySkiingSpeed' | 'HKQuantityTypeIdentifierCyclingCadence' | 'HKQuantityTypeIdentifierCyclingFunctionalThresholdPower' | 'HKQuantityTypeIdentifierCyclingPower' | 'HKQuantityTypeIdentifierCyclingSpeed' | 'HKQuantityTypeIdentifierDietaryBiotin' | 'HKQuantityTypeIdentifierDietaryCaffeine' | 'HKQuantityTypeIdentifierDietaryCalcium' | 'HKQuantityTypeIdentifierDietaryCarbohydrates' | 'HKQuantityTypeIdentifierDietaryChloride' | 'HKQuantityTypeIdentifierDietaryCholesterol' | 'HKQuantityTypeIdentifierDietaryChromium' | 'HKQuantityTypeIdentifierDietaryCopper' | 'HKQuantityTypeIdentifierDietaryEnergyConsumed' | 'HKQuantityTypeIdentifierDietaryFatMonounsaturated' | 'HKQuantityTypeIdentifierDietaryFatPolyunsaturated' | 'HKQuantityTypeIdentifierDietaryFatSaturated' | 'HKQuantityTypeIdentifierDietaryFatTotal' | 'HKQuantityTypeIdentifierDietaryFiber' | 'HKQuantityTypeIdentifierDietaryFolate' | 'HKQuantityTypeIdentifierDietaryIodine' | 'HKQuantityTypeIdentifierDietaryIron' | 'HKQuantityTypeIdentifierDietaryMagnesium' | 'HKQuantityTypeIdentifierDietaryManganese' | 'HKQuantityTypeIdentifierDietaryMolybdenum' | 'HKQuantityTypeIdentifierDietaryNiacin' | 'HKQuantityTypeIdentifierDietaryPantothenicAcid' | 'HKQuantityTypeIdentifierDietaryPhosphorus' | 'HKQuantityTypeIdentifierDietaryPotassium' | 'HKQuantityTypeIdentifierDietaryProtein' | 'HKQuantityTypeIdentifierDietaryRiboflavin' | 'HKQuantityTypeIdentifierDietarySelenium' | 'HKQuantityTypeIdentifierDietarySodium' | 'HKQuantityTypeIdentifierDietarySugar' | 'HKQuantityTypeIdentifierDietaryThiamin' | 'HKQuantityTypeIdentifierDietaryVitaminA' | 'HKQuantityTypeIdentifierDietaryVitaminB12' | 'HKQuantityTypeIdentifierDietaryVitaminB6' | 'HKQuantityTypeIdentifierDietaryVitaminC' | 'HKQuantityTypeIdentifierDietaryVitaminD' | 'HKQuantityTypeIdentifierDietaryVitaminE' | 'HKQuantityTypeIdentifierDietaryVitaminK' | 'HKQuantityTypeIdentifierDietaryWater' | 'HKQuantityTypeIdentifierDietaryZinc' | 'HKQuantityTypeIdentifierDistanceCrossCountrySkiing' | 'HKQuantityTypeIdentifierDistanceCycling' | 'HKQuantityTypeIdentifierDistanceDownhillSnowSports' | 'HKQuantityTypeIdentifierDistancePaddleSports' | 'HKQuantityTypeIdentifierDistanceRowing' | 'HKQuantityTypeIdentifierDistanceSkatingSports' | 'HKQuantityTypeIdentifierDistanceSwimming' | 'HKQuantityTypeIdentifierDistanceWalkingRunning' | 'HKQuantityTypeIdentifierDistanceWheelchair' | 'HKQuantityTypeIdentifierElectrodermalActivity' | 'HKQuantityTypeIdentifierEnvironmentalAudioExposure' | 'HKQuantityTypeIdentifierEnvironmentalSoundReduction' | 'HKQuantityTypeIdentifierEstimatedWorkoutEffortScore' | 'HKQuantityTypeIdentifierFlightsClimbed' | 'HKQuantityTypeIdentifierForcedExpiratoryVolume1' | 'HKQuantityTypeIdentifierForcedVitalCapacity' | 'HKQuantityTypeIdentifierHeadphoneAudioExposure' | 'HKQuantityTypeIdentifierHeartRate' | 'HKQuantityTypeIdentifierHeartRateRecoveryOneMinute' | 'HKQuantityTypeIdentifierHeartRateVariabilitySDNN' | 'HKQuantityTypeIdentifierHeight' | 'HKQuantityTypeIdentifierInhalerUsage' | 'HKQuantityTypeIdentifierInsulinDelivery' | 'HKQuantityTypeIdentifierLeanBodyMass' | 'HKQuantityTypeIdentifierNikeFuel' | 'HKQuantityTypeIdentifierNumberOfAlcoholicBeverages' | 'HKQuantityTypeIdentifierNumberOfTimesFallen' | 'HKQuantityTypeIdentifierOxygenSaturation' | 'HKQuantityTypeIdentifierPaddleSportsSpeed' | 'HKQuantityTypeIdentifierPeakExpiratoryFlowRate' | 'HKQuantityTypeIdentifierPeripheralPerfusionIndex' | 'HKQuantityTypeIdentifierPhysicalEffort' | 'HKQuantityTypeIdentifierPushCount' | 'HKQuantityTypeIdentifierRespiratoryRate' | 'HKQuantityTypeIdentifierRestingHeartRate' | 'HKQuantityTypeIdentifierRowingSpeed' | 'HKQuantityTypeIdentifierRunningGroundContactTime' | 'HKQuantityTypeIdentifierRunningPower' | 'HKQuantityTypeIdentifierRunningSpeed' | 'HKQuantityTypeIdentifierRunningStrideLength' | 'HKQuantityTypeIdentifierRunningVerticalOscillation' | 'HKQuantityTypeIdentifierSixMinuteWalkTestDistance' | 'HKQuantityTypeIdentifierStairAscentSpeed' | 'HKQuantityTypeIdentifierStairDescentSpeed' | 'HKQuantityTypeIdentifierStepCount' | 'HKQuantityTypeIdentifierSwimmingStrokeCount' | 'HKQuantityTypeIdentifierTimeInDaylight' | 'HKQuantityTypeIdentifierUnderwaterDepth' | 'HKQuantityTypeIdentifierUVExposure' | 'HKQuantityTypeIdentifierVO2Max' | 'HKQuantityTypeIdentifierWaistCircumference' | 'HKQuantityTypeIdentifierWalkingAsymmetryPercentage' | 'HKQuantityTypeIdentifierWalkingDoubleSupportPercentage' | 'HKQuantityTypeIdentifierWalkingSpeed' | 'HKQuantityTypeIdentifierWalkingStepLength' | 'HKQuantityTypeIdentifierWaterTemperature' | 'HKQuantityTypeIdentifierWorkoutEffortScore';
|
|
5
5
|
export type QuantityTypeIdentifier = QuantityTypeIdentifierReadOnly | QuantityTypeIdentifierWriteable;
|
|
6
6
|
export type CategoryTypeIdentifierReadOnly = 'HKCategoryTypeIdentifierAppleStandHour' | 'HKCategoryTypeIdentifierHeadphoneAudioExposureEvent' | 'HKCategoryTypeIdentifierHighHeartRateEvent' | 'HKCategoryTypeIdentifierHypertensionEvent' | 'HKCategoryTypeIdentifierLowHeartRateEvent';
|
|
7
7
|
export type CategoryTypeIdentifierWriteable = 'HKCategoryTypeIdentifierAbdominalCramps' | 'HKCategoryTypeIdentifierAcne' | 'HKCategoryTypeIdentifierAppetiteChanges' | 'HKCategoryTypeIdentifierAppleWalkingSteadinessEvent' | 'HKCategoryTypeIdentifierAudioExposureEvent' | 'HKCategoryTypeIdentifierBladderIncontinence' | 'HKCategoryTypeIdentifierBleedingAfterPregnancy' | 'HKCategoryTypeIdentifierBleedingDuringPregnancy' | 'HKCategoryTypeIdentifierBloating' | 'HKCategoryTypeIdentifierBreastPain' | 'HKCategoryTypeIdentifierCervicalMucusQuality' | 'HKCategoryTypeIdentifierChestTightnessOrPain' | 'HKCategoryTypeIdentifierChills' | 'HKCategoryTypeIdentifierConstipation' | 'HKCategoryTypeIdentifierContraceptive' | 'HKCategoryTypeIdentifierCoughing' | 'HKCategoryTypeIdentifierDiarrhea' | 'HKCategoryTypeIdentifierDizziness' | 'HKCategoryTypeIdentifierDrySkin' | 'HKCategoryTypeIdentifierEnvironmentalAudioExposureEvent' | 'HKCategoryTypeIdentifierFainting' | 'HKCategoryTypeIdentifierFatigue' | 'HKCategoryTypeIdentifierFever' | 'HKCategoryTypeIdentifierGeneralizedBodyAche' | 'HKCategoryTypeIdentifierHairLoss' | 'HKCategoryTypeIdentifierHandwashingEvent' | 'HKCategoryTypeIdentifierHeadache' | 'HKCategoryTypeIdentifierHeartburn' | 'HKCategoryTypeIdentifierHotFlashes' | 'HKCategoryTypeIdentifierInfrequentMenstrualCycles' | 'HKCategoryTypeIdentifierIntermenstrualBleeding' | 'HKCategoryTypeIdentifierIrregularHeartRhythmEvent' | 'HKCategoryTypeIdentifierIrregularMenstrualCycles' | 'HKCategoryTypeIdentifierLactation' | 'HKCategoryTypeIdentifierLossOfSmell' | 'HKCategoryTypeIdentifierLossOfTaste' | 'HKCategoryTypeIdentifierLowCardioFitnessEvent' | 'HKCategoryTypeIdentifierLowerBackPain' | 'HKCategoryTypeIdentifierMemoryLapse' | 'HKCategoryTypeIdentifierMenstrualFlow' | 'HKCategoryTypeIdentifierMindfulSession' | 'HKCategoryTypeIdentifierMoodChanges' | 'HKCategoryTypeIdentifierNausea' | 'HKCategoryTypeIdentifierNightSweats' | 'HKCategoryTypeIdentifierOvulationTestResult' | 'HKCategoryTypeIdentifierPelvicPain' | 'HKCategoryTypeIdentifierPersistentIntermenstrualBleeding' | 'HKCategoryTypeIdentifierPregnancy' | 'HKCategoryTypeIdentifierPregnancyTestResult' | 'HKCategoryTypeIdentifierProgesteroneTestResult' | 'HKCategoryTypeIdentifierProlongedMenstrualPeriods' | 'HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat' | 'HKCategoryTypeIdentifierRunnyNose' | 'HKCategoryTypeIdentifierSexualActivity' | 'HKCategoryTypeIdentifierShortnessOfBreath' | 'HKCategoryTypeIdentifierSinusCongestion' | 'HKCategoryTypeIdentifierSkippedHeartbeat' | 'HKCategoryTypeIdentifierSleepAnalysis' | 'HKCategoryTypeIdentifierSleepApneaEvent' | 'HKCategoryTypeIdentifierSleepChanges' | 'HKCategoryTypeIdentifierSoreThroat' | 'HKCategoryTypeIdentifierToothbrushingEvent' | 'HKCategoryTypeIdentifierVaginalDryness' | 'HKCategoryTypeIdentifierVomiting' | 'HKCategoryTypeIdentifierWheezing';
|
|
@@ -19,6 +19,7 @@ export declare const QUANTITY_IDENTIFIER_IOS_AVAILABILITY: {
|
|
|
19
19
|
readonly HKQuantityTypeIdentifierBasalEnergyBurned: "8.0";
|
|
20
20
|
readonly HKQuantityTypeIdentifierBloodAlcoholContent: "8.0";
|
|
21
21
|
readonly HKQuantityTypeIdentifierBloodGlucose: "8.0";
|
|
22
|
+
readonly HKQuantityTypeIdentifierBloodKetones: "8.0";
|
|
22
23
|
readonly HKQuantityTypeIdentifierBloodPressureDiastolic: "8.0";
|
|
23
24
|
readonly HKQuantityTypeIdentifierBloodPressureSystolic: "8.0";
|
|
24
25
|
readonly HKQuantityTypeIdentifierBodyFatPercentage: "8.0";
|
|
@@ -213,6 +214,7 @@ export declare const QUANTITY_IDENTIFIER_CANONICAL_UNITS: {
|
|
|
213
214
|
readonly HKQuantityTypeIdentifierBasalEnergyBurned: "kcal";
|
|
214
215
|
readonly HKQuantityTypeIdentifierBloodAlcoholContent: "%";
|
|
215
216
|
readonly HKQuantityTypeIdentifierBloodGlucose: "mg/dL";
|
|
217
|
+
readonly HKQuantityTypeIdentifierBloodKetones: "mmol/L";
|
|
216
218
|
readonly HKQuantityTypeIdentifierBloodPressureDiastolic: "mmHg";
|
|
217
219
|
readonly HKQuantityTypeIdentifierBloodPressureSystolic: "mmHg";
|
|
218
220
|
readonly HKQuantityTypeIdentifierBodyFatPercentage: "%";
|
|
@@ -894,6 +896,7 @@ export interface QuantityUnitByIdentifierMap {
|
|
|
894
896
|
readonly HKQuantityTypeIdentifierBasalEnergyBurned: EnergyUnit;
|
|
895
897
|
readonly HKQuantityTypeIdentifierBloodAlcoholContent: '%';
|
|
896
898
|
readonly HKQuantityTypeIdentifierBloodGlucose: BloodGlucoseUnit;
|
|
899
|
+
readonly HKQuantityTypeIdentifierBloodKetones: BloodGlucoseUnit;
|
|
897
900
|
readonly HKQuantityTypeIdentifierBloodPressureDiastolic: PressureUnit;
|
|
898
901
|
readonly HKQuantityTypeIdentifierBloodPressureSystolic: PressureUnit;
|
|
899
902
|
readonly HKQuantityTypeIdentifierBodyFatPercentage: '%';
|
|
@@ -87,7 +87,7 @@ export type TemperatureUnit = 'degC' | 'degF' | 'K';
|
|
|
87
87
|
*/
|
|
88
88
|
export type UnitOfEnergy = 'kcal' | 'Cal' | 'cal' | 'J';
|
|
89
89
|
export type EnergyUnit = JouleUnit<MetricPrefix> | UnitOfEnergy;
|
|
90
|
-
export type BloodGlucoseUnit = 'mmol<180.15588000005408>/l' | 'mg/dL';
|
|
90
|
+
export type BloodGlucoseUnit = 'mmol<180.15588000005408>/l' | 'mmol/L' | 'mg/dL';
|
|
91
91
|
export type SpeedUnit<TLength extends LengthUnit, TTime extends TimeUnit> = `${TLength}/${TTime}`;
|
|
92
92
|
export type CountPerTime<TTime extends TimeUnit> = `count/${TTime}`;
|
|
93
93
|
export type Unit = BloodGlucoseUnit | CountPerTime<TimeUnit> | EnergyUnit | FrequencyUnit | Units | LengthUnit | MassUnit | PressureUnit | SpeedUnit<LengthUnit, TimeUnit> | TemperatureUnit | TimeUnit | VolumeUnit;
|
|
@@ -199,6 +199,8 @@ public extension ObjectTypeIdentifier {
|
|
|
199
199
|
self = .hkquantitytypeidentifierbloodalcoholcontent
|
|
200
200
|
case "HKQuantityTypeIdentifierBloodGlucose":
|
|
201
201
|
self = .hkquantitytypeidentifierbloodglucose
|
|
202
|
+
case "HKQuantityTypeIdentifierBloodKetones":
|
|
203
|
+
self = .hkquantitytypeidentifierbloodketones
|
|
202
204
|
case "HKQuantityTypeIdentifierBloodPressureDiastolic":
|
|
203
205
|
self = .hkquantitytypeidentifierbloodpressurediastolic
|
|
204
206
|
case "HKQuantityTypeIdentifierBloodPressureSystolic":
|
|
@@ -619,6 +621,8 @@ public extension ObjectTypeIdentifier {
|
|
|
619
621
|
return "HKQuantityTypeIdentifierBloodAlcoholContent"
|
|
620
622
|
case .hkquantitytypeidentifierbloodglucose:
|
|
621
623
|
return "HKQuantityTypeIdentifierBloodGlucose"
|
|
624
|
+
case .hkquantitytypeidentifierbloodketones:
|
|
625
|
+
return "HKQuantityTypeIdentifierBloodKetones"
|
|
622
626
|
case .hkquantitytypeidentifierbloodpressurediastolic:
|
|
623
627
|
return "HKQuantityTypeIdentifierBloodPressureDiastolic"
|
|
624
628
|
case .hkquantitytypeidentifierbloodpressuresystolic:
|
|
@@ -43,6 +43,8 @@ public extension QuantityTypeIdentifier {
|
|
|
43
43
|
self = .hkquantitytypeidentifierbloodalcoholcontent
|
|
44
44
|
case "HKQuantityTypeIdentifierBloodGlucose":
|
|
45
45
|
self = .hkquantitytypeidentifierbloodglucose
|
|
46
|
+
case "HKQuantityTypeIdentifierBloodKetones":
|
|
47
|
+
self = .hkquantitytypeidentifierbloodketones
|
|
46
48
|
case "HKQuantityTypeIdentifierBloodPressureDiastolic":
|
|
47
49
|
self = .hkquantitytypeidentifierbloodpressurediastolic
|
|
48
50
|
case "HKQuantityTypeIdentifierBloodPressureSystolic":
|
|
@@ -293,6 +295,8 @@ public extension QuantityTypeIdentifier {
|
|
|
293
295
|
return "HKQuantityTypeIdentifierBloodAlcoholContent"
|
|
294
296
|
case .hkquantitytypeidentifierbloodglucose:
|
|
295
297
|
return "HKQuantityTypeIdentifierBloodGlucose"
|
|
298
|
+
case .hkquantitytypeidentifierbloodketones:
|
|
299
|
+
return "HKQuantityTypeIdentifierBloodKetones"
|
|
296
300
|
case .hkquantitytypeidentifierbloodpressurediastolic:
|
|
297
301
|
return "HKQuantityTypeIdentifierBloodPressureDiastolic"
|
|
298
302
|
case .hkquantitytypeidentifierbloodpressuresystolic:
|
|
@@ -33,6 +33,8 @@ public extension QuantityTypeIdentifierWriteable {
|
|
|
33
33
|
self = .hkquantitytypeidentifierbloodalcoholcontent
|
|
34
34
|
case "HKQuantityTypeIdentifierBloodGlucose":
|
|
35
35
|
self = .hkquantitytypeidentifierbloodglucose
|
|
36
|
+
case "HKQuantityTypeIdentifierBloodKetones":
|
|
37
|
+
self = .hkquantitytypeidentifierbloodketones
|
|
36
38
|
case "HKQuantityTypeIdentifierBloodPressureDiastolic":
|
|
37
39
|
self = .hkquantitytypeidentifierbloodpressurediastolic
|
|
38
40
|
case "HKQuantityTypeIdentifierBloodPressureSystolic":
|
|
@@ -273,6 +275,8 @@ public extension QuantityTypeIdentifierWriteable {
|
|
|
273
275
|
return "HKQuantityTypeIdentifierBloodAlcoholContent"
|
|
274
276
|
case .hkquantitytypeidentifierbloodglucose:
|
|
275
277
|
return "HKQuantityTypeIdentifierBloodGlucose"
|
|
278
|
+
case .hkquantitytypeidentifierbloodketones:
|
|
279
|
+
return "HKQuantityTypeIdentifierBloodKetones"
|
|
276
280
|
case .hkquantitytypeidentifierbloodpressurediastolic:
|
|
277
281
|
return "HKQuantityTypeIdentifierBloodPressureDiastolic"
|
|
278
282
|
case .hkquantitytypeidentifierbloodpressuresystolic:
|
|
@@ -187,6 +187,8 @@ public extension SampleTypeIdentifier {
|
|
|
187
187
|
self = .hkquantitytypeidentifierbloodalcoholcontent
|
|
188
188
|
case "HKQuantityTypeIdentifierBloodGlucose":
|
|
189
189
|
self = .hkquantitytypeidentifierbloodglucose
|
|
190
|
+
case "HKQuantityTypeIdentifierBloodKetones":
|
|
191
|
+
self = .hkquantitytypeidentifierbloodketones
|
|
190
192
|
case "HKQuantityTypeIdentifierBloodPressureDiastolic":
|
|
191
193
|
self = .hkquantitytypeidentifierbloodpressurediastolic
|
|
192
194
|
case "HKQuantityTypeIdentifierBloodPressureSystolic":
|
|
@@ -593,6 +595,8 @@ public extension SampleTypeIdentifier {
|
|
|
593
595
|
return "HKQuantityTypeIdentifierBloodAlcoholContent"
|
|
594
596
|
case .hkquantitytypeidentifierbloodglucose:
|
|
595
597
|
return "HKQuantityTypeIdentifierBloodGlucose"
|
|
598
|
+
case .hkquantitytypeidentifierbloodketones:
|
|
599
|
+
return "HKQuantityTypeIdentifierBloodKetones"
|
|
596
600
|
case .hkquantitytypeidentifierbloodpressurediastolic:
|
|
597
601
|
return "HKQuantityTypeIdentifierBloodPressureDiastolic"
|
|
598
602
|
case .hkquantitytypeidentifierbloodpressuresystolic:
|
|
@@ -167,6 +167,8 @@ public extension SampleTypeIdentifierWriteable {
|
|
|
167
167
|
self = .hkquantitytypeidentifierbloodalcoholcontent
|
|
168
168
|
case "HKQuantityTypeIdentifierBloodGlucose":
|
|
169
169
|
self = .hkquantitytypeidentifierbloodglucose
|
|
170
|
+
case "HKQuantityTypeIdentifierBloodKetones":
|
|
171
|
+
self = .hkquantitytypeidentifierbloodketones
|
|
170
172
|
case "HKQuantityTypeIdentifierBloodPressureDiastolic":
|
|
171
173
|
self = .hkquantitytypeidentifierbloodpressurediastolic
|
|
172
174
|
case "HKQuantityTypeIdentifierBloodPressureSystolic":
|
|
@@ -551,6 +553,8 @@ public extension SampleTypeIdentifierWriteable {
|
|
|
551
553
|
return "HKQuantityTypeIdentifierBloodAlcoholContent"
|
|
552
554
|
case .hkquantitytypeidentifierbloodglucose:
|
|
553
555
|
return "HKQuantityTypeIdentifierBloodGlucose"
|
|
556
|
+
case .hkquantitytypeidentifierbloodketones:
|
|
557
|
+
return "HKQuantityTypeIdentifierBloodKetones"
|
|
554
558
|
case .hkquantitytypeidentifierbloodpressurediastolic:
|
|
555
559
|
return "HKQuantityTypeIdentifierBloodPressureDiastolic"
|
|
556
560
|
case .hkquantitytypeidentifierbloodpressuresystolic:
|