From 44ce99ab36e45329621fb2166bcf5b2d6558aa52 Mon Sep 17 00:00:00 2001 From: Verity Powell Date: Wed, 23 Aug 2023 15:36:08 +0100 Subject: [PATCH 01/11] chore: add in workoutKit, laps and HKQuantityTypeIdentifiers --- ios/ReactNativeHealthkit.swift | 96 +++++++++++++++++++++++++++++++--- src/native-types.ts | 41 +++++++++++++++ 2 files changed, 129 insertions(+), 8 deletions(-) diff --git a/ios/ReactNativeHealthkit.swift b/ios/ReactNativeHealthkit.swift index 8a6b042..6386167 100644 --- a/ios/ReactNativeHealthkit.swift +++ b/ios/ReactNativeHealthkit.swift @@ -1,5 +1,6 @@ import HealthKit import CoreLocation +import WorkoutKit @objc(ReactNativeHealthkit) @available(iOS 10.0, *) @@ -615,8 +616,23 @@ class ReactNativeHealthkit: RCTEventEmitter { store.execute(query) } + //Helper function with completions so that async fetching of workout plan can be done + @available(iOS 17.0, *) + func fetchWorkoutPlan(for workout: HKWorkout, completion: @escaping (WorkoutPlan?) -> Void) { + Task { + do { + let workoutplan = try await workout.workoutPlan + completion(workoutplan) + } catch { + print("Error: \(error)") + completion(nil) + } + } + } + @objc(queryWorkoutSamples:distanceUnitString:from:to:limit:ascending:resolve:reject:) func queryWorkoutSamples(energyUnitString: String, distanceUnitString: String, from: Date, to: Date, limit: Int, ascending: Bool, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { + guard let store = _store else { return reject(INIT_ERROR, INIT_ERROR_MESSAGE, nil) } @@ -632,18 +648,28 @@ class ReactNativeHealthkit: RCTEventEmitter { let distanceUnit = HKUnit.init(from: distanceUnitString) let q = HKSampleQuery(sampleType: .workoutType(), predicate: predicate, limit: limit, sortDescriptors: getSortDescriptors(ascending: ascending)) { (_: HKSampleQuery, sample: [HKSample]?, error: Error?) in - guard let err = error else { + + //check for an error + if let err = error { + reject(GENERIC_ERROR, err.localizedDescription, err) + return + } + guard let samples = sample else { return resolve([]) } let arr: NSMutableArray = [] + //create counts for completed workouts so that we can resolve the promise when all workouts have been serialized + var completedWorkoutCount = 0 + let totalWorkouts = samples.count for s in samples { if let workout = s as? HKWorkout { let endDate = self._dateFormatter.string(from: workout.endDate) let startDate = self._dateFormatter.string(from: workout.startDate) - let dict: NSMutableDictionary = [ + + var dict: NSMutableDictionary = [ "uuid": workout.uuid.uuidString, "device": serializeDevice(_device: workout.device) as Any, "duration": workout.duration, @@ -657,17 +683,71 @@ class ReactNativeHealthkit: RCTEventEmitter { "sourceRevision": serializeSourceRevision(_sourceRevision: workout.sourceRevision) as Any ] + //this is used for our laps functionality to get markers + //https://developer.apple.com/documentation/healthkit/hkworkoutevent + if let events = workout.workoutEvents { + var eventDicts: [[String: Any]] = [] + for event in events { + let eventStartDate = self._dateFormatter.string(from: event.dateInterval.start) + let eventEndDate = self._dateFormatter.string(from: event.dateInterval.end) + let eventDict: [String: Any] = [ + "type": event.type.rawValue, //https://developer.apple.com/documentation/healthkit/hkworkouteventtype + "startDate": eventStartDate, + "endDate": eventEndDate + ] + eventDicts.append(eventDict) + } + dict["events"] = eventDicts + } + + //also used for our laps functionality to get activities for custom workouts defined by the user + //https://developer.apple.com/documentation/healthkit/hkworkout/1615340-init + //it seems this might be depricated in the latest beta so this might need updating! + var activitiesDicts: [[String: Any]] = [] + if #available(iOS 16.0, *) { + let activities: [HKWorkoutActivity] = workout.workoutActivities + + if !activities.isEmpty{ + for activity in activities { + var activityStartDate = "" + var activityEndDate = "" + if let start = activity.startDate as Date? { + activityStartDate = self._dateFormatter.string(from: activity.startDate) + } + let activityDict: [String: Any] = [ + "startDate": activityStartDate, + ] + activitiesDicts.append(activityDict) + } + } + } + dict["activities"] = activitiesDicts + if #available(iOS 11, *) { dict.setValue(serializeQuantity(unit: HKUnit.count(), quantity: workout.totalFlightsClimbed), forKey: "totalFlightsClimbed") } - - arr.add(dict) + + if #available(iOS 17.0, *) { + self.fetchWorkoutPlan(for: workout) { workoutplan in + if let workoutplanId = workoutplan?.id { + dict["workoutPlanId"] = workoutplanId.uuidString + } + arr.add(dict) + completedWorkoutCount += 1 + //to avoid race condition only resolve when all workouts have been serialized + if completedWorkoutCount == totalWorkouts { + return resolve(arr) + } + } + } else { + arr.add(dict) + completedWorkoutCount += 1 + if completedWorkoutCount == totalWorkouts { + return resolve(arr) + } + } } } - - return resolve(arr) - } - reject(GENERIC_ERROR, err.localizedDescription, err) } store.execute(q) diff --git a/src/native-types.ts b/src/native-types.ts index 1a09fe6..055291e 100644 --- a/src/native-types.ts +++ b/src/native-types.ts @@ -670,6 +670,34 @@ export enum HKQuantityTypeIdentifier { * @since iOS 16 */ heartRateRecoveryOneMinute = 'HKQuantityTypeIdentifierHeartRateRecoveryOneMinute', + + /** + * Running Ground Contact Time + * @see {@link https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifierrunninggroundcontacttime Apple Docs HKQuantityTypeIdentifierRunningGroundContactTime} + * @since iOS 16 + */ + runningGroundContactTime = 'HKQuantityTypeIdentifierRunningGroundContactTime', + + /** + * Running Stride Length + * @see {@link https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifierrunningstridelength Apple Docs HKQuantityTypeIdentifierRunningStrideLength} + * @since iOS 16 + */ + runningStrideLength = 'HKQuantityTypeIdentifierRunningStrideLength', + + /** + * Running Power + * @see {@link https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifierrunningpower Apple Docs HKQuantityTypeIdentifierRunningPower} + * @since iOS 16 + */ + runningPower = 'HKQuantityTypeIdentifierRunningPower', + + /** + * Running Vertical Oscillation + * @see {@link https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifierrunningverticaloscillation Apple Docs HKQuantityTypeIdentifierRunningVerticalOscillation} + * @since iOS 16 + */ + runningVerticalOscillation = 'HKQuantityTypeIdentifierRunningVerticalOscillation', } export type TypeToUnitMapping = { @@ -1673,6 +1701,16 @@ HKCategorySampleRaw, 'device' | 'endDate' | 'startDate' | 'uuid' >; +export interface HKWorkoutEvent { + readonly type: string, + readonly startDate: string, + readonly endDate: string, +} + +export interface HKWorkoutActivity { + readonly startDate: string, +} + export type HKWorkoutRaw< TEnergy extends EnergyUnit, TDistance extends LengthUnit @@ -1695,6 +1733,9 @@ export type HKWorkoutRaw< readonly endDate: string; readonly metadata?: HKWorkoutMetadata; readonly sourceRevision?: HKSourceRevision; + readonly events?: HKWorkoutEvent; + readonly activities?: HKWorkoutActivity; + readonly workoutPlanId?: string; }; // Straight mapping to https://developer.apple.com/documentation/healthkit/hkcharacteristictypeidentifier From 30611913345cdc76df26ffc45a9ca00acf0d17c5 Mon Sep 17 00:00:00 2001 From: Walter Holohan Date: Fri, 25 Aug 2023 12:17:02 +0100 Subject: [PATCH 02/11] chore: lint fixes --- src/native-types.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/native-types.ts b/src/native-types.ts index 055291e..30e05b1 100644 --- a/src/native-types.ts +++ b/src/native-types.ts @@ -671,28 +671,28 @@ export enum HKQuantityTypeIdentifier { */ heartRateRecoveryOneMinute = 'HKQuantityTypeIdentifierHeartRateRecoveryOneMinute', - /** + /** * Running Ground Contact Time * @see {@link https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifierrunninggroundcontacttime Apple Docs HKQuantityTypeIdentifierRunningGroundContactTime} * @since iOS 16 */ runningGroundContactTime = 'HKQuantityTypeIdentifierRunningGroundContactTime', - /** + /** * Running Stride Length * @see {@link https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifierrunningstridelength Apple Docs HKQuantityTypeIdentifierRunningStrideLength} * @since iOS 16 */ runningStrideLength = 'HKQuantityTypeIdentifierRunningStrideLength', - /** + /** * Running Power * @see {@link https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifierrunningpower Apple Docs HKQuantityTypeIdentifierRunningPower} * @since iOS 16 */ runningPower = 'HKQuantityTypeIdentifierRunningPower', - /** + /** * Running Vertical Oscillation * @see {@link https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifierrunningverticaloscillation Apple Docs HKQuantityTypeIdentifierRunningVerticalOscillation} * @since iOS 16 From d024ce0fc942e3b65cad0c3ac4b4c9c8516c8a49 Mon Sep 17 00:00:00 2001 From: Walter Holohan Date: Wed, 30 Aug 2023 12:09:03 +0100 Subject: [PATCH 03/11] feat: add endDate, uuid and duration to HKWorkoutActivity --- ios/ReactNativeHealthkit.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ios/ReactNativeHealthkit.swift b/ios/ReactNativeHealthkit.swift index 6386167..bdad3ab 100644 --- a/ios/ReactNativeHealthkit.swift +++ b/ios/ReactNativeHealthkit.swift @@ -714,8 +714,14 @@ class ReactNativeHealthkit: RCTEventEmitter { if let start = activity.startDate as Date? { activityStartDate = self._dateFormatter.string(from: activity.startDate) } + if let end = activity.endDate as Date? { + activityEndDate = self._dateFormatter.string(from: activity.endDate) + } let activityDict: [String: Any] = [ "startDate": activityStartDate, + "endDate": activityEndDate, + "uuid": activity.uuid.uuidString, + "duration": activity.duration ] activitiesDicts.append(activityDict) } From b168dea75cb3e050eeb914cd2bc92b12f02b848f Mon Sep 17 00:00:00 2001 From: Walter Holohan Date: Wed, 30 Aug 2023 12:09:27 +0100 Subject: [PATCH 04/11] feat: update type for HKWorkoutEventType --- src/native-types.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/native-types.ts b/src/native-types.ts index 30e05b1..5f727bc 100644 --- a/src/native-types.ts +++ b/src/native-types.ts @@ -1702,13 +1702,27 @@ HKCategorySampleRaw, >; export interface HKWorkoutEvent { - readonly type: string, + readonly type: HKWorkoutEventType, readonly startDate: string, readonly endDate: string, } +export enum HKWorkoutEventType { + pause = 1, + resume = 2, + lap = 3, + marker = 4, + motionPaused = 5, + motionResumed = 6, + segment = 7, + pauseOrResumeRequest = 8, +} + export interface HKWorkoutActivity { readonly startDate: string, + readonly endDate: string, + readonly uuid: string, + readonly duration: number, } export type HKWorkoutRaw< From 06ef5bcb063685907109daa255d9f0448b7cf795 Mon Sep 17 00:00:00 2001 From: Walter Holohan Date: Wed, 30 Aug 2023 13:45:00 +0100 Subject: [PATCH 05/11] chore: tidy up code --- ios/ReactNativeHealthkit.swift | 58 ++++++++++++++-------------------- src/native-types.ts | 4 +-- 2 files changed, 26 insertions(+), 36 deletions(-) diff --git a/ios/ReactNativeHealthkit.swift b/ios/ReactNativeHealthkit.swift index bdad3ab..224069b 100644 --- a/ios/ReactNativeHealthkit.swift +++ b/ios/ReactNativeHealthkit.swift @@ -648,12 +648,7 @@ class ReactNativeHealthkit: RCTEventEmitter { let distanceUnit = HKUnit.init(from: distanceUnitString) let q = HKSampleQuery(sampleType: .workoutType(), predicate: predicate, limit: limit, sortDescriptors: getSortDescriptors(ascending: ascending)) { (_: HKSampleQuery, sample: [HKSample]?, error: Error?) in - - //check for an error - if let err = error { - reject(GENERIC_ERROR, err.localizedDescription, err) - return - } + guard let err = error else { guard let samples = sample else { return resolve([]) @@ -662,14 +657,14 @@ class ReactNativeHealthkit: RCTEventEmitter { //create counts for completed workouts so that we can resolve the promise when all workouts have been serialized var completedWorkoutCount = 0 let totalWorkouts = samples.count - + for s in samples { if let workout = s as? HKWorkout { let endDate = self._dateFormatter.string(from: workout.endDate) let startDate = self._dateFormatter.string(from: workout.startDate) - - - var dict: NSMutableDictionary = [ + + + let dict: NSMutableDictionary = [ "uuid": workout.uuid.uuidString, "device": serializeDevice(_device: workout.device) as Any, "duration": workout.duration, @@ -682,11 +677,11 @@ class ReactNativeHealthkit: RCTEventEmitter { "metadata": serializeMetadata(metadata: workout.metadata), "sourceRevision": serializeSourceRevision(_sourceRevision: workout.sourceRevision) as Any ] - - //this is used for our laps functionality to get markers + + //this is used for our laps functionality to get markers //https://developer.apple.com/documentation/healthkit/hkworkoutevent + var eventArray: [[String: Any]] = [] if let events = workout.workoutEvents { - var eventDicts: [[String: Any]] = [] for event in events { let eventStartDate = self._dateFormatter.string(from: event.dateInterval.start) let eventEndDate = self._dateFormatter.string(from: event.dateInterval.end) @@ -695,15 +690,15 @@ class ReactNativeHealthkit: RCTEventEmitter { "startDate": eventStartDate, "endDate": eventEndDate ] - eventDicts.append(eventDict) + eventArray.append(eventDict) } - dict["events"] = eventDicts } + dict["events"] = eventArray //also used for our laps functionality to get activities for custom workouts defined by the user - //https://developer.apple.com/documentation/healthkit/hkworkout/1615340-init + //https://developer.apple.com/documentation/healthkit/hkworkout/1615340-init //it seems this might be depricated in the latest beta so this might need updating! - var activitiesDicts: [[String: Any]] = [] + var activitiesArray: [[String: Any]] = [] if #available(iOS 16.0, *) { let activities: [HKWorkoutActivity] = workout.workoutActivities @@ -723,39 +718,34 @@ class ReactNativeHealthkit: RCTEventEmitter { "uuid": activity.uuid.uuidString, "duration": activity.duration ] - activitiesDicts.append(activityDict) + activitiesArray.append(activityDict) } } } - dict["activities"] = activitiesDicts - + dict["activities"] = activitiesArray + if #available(iOS 11, *) { dict.setValue(serializeQuantity(unit: HKUnit.count(), quantity: workout.totalFlightsClimbed), forKey: "totalFlightsClimbed") } if #available(iOS 17.0, *) { - self.fetchWorkoutPlan(for: workout) { workoutplan in + do { + let workoutplan = try await self.fetchWorkoutPlan(for: workout) if let workoutplanId = workoutplan?.id { dict["workoutPlanId"] = workoutplanId.uuidString } - arr.add(dict) - completedWorkoutCount += 1 - //to avoid race condition only resolve when all workouts have been serialized - if completedWorkoutCount == totalWorkouts { - return resolve(arr) - } - } - } else { - arr.add(dict) - completedWorkoutCount += 1 - if completedWorkoutCount == totalWorkouts { - return resolve(arr) + } catch { + // handle error } } + + arr.add(dict) } } + return resolve(arr) + } + reject(GENERIC_ERROR, err.localizedDescription, err) } - store.execute(q) } diff --git a/src/native-types.ts b/src/native-types.ts index 5f727bc..259f5a6 100644 --- a/src/native-types.ts +++ b/src/native-types.ts @@ -1747,8 +1747,8 @@ export type HKWorkoutRaw< readonly endDate: string; readonly metadata?: HKWorkoutMetadata; readonly sourceRevision?: HKSourceRevision; - readonly events?: HKWorkoutEvent; - readonly activities?: HKWorkoutActivity; + readonly events?: readonly HKWorkoutEvent[]; + readonly activities?: readonly HKWorkoutActivity[]; readonly workoutPlanId?: string; }; From 03ab99138d30f26c38c08fe2011e2925e583c108 Mon Sep 17 00:00:00 2001 From: Walter Holohan Date: Wed, 30 Aug 2023 13:53:36 +0100 Subject: [PATCH 06/11] chore: more tidy up --- ios/ReactNativeHealthkit.swift | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/ios/ReactNativeHealthkit.swift b/ios/ReactNativeHealthkit.swift index 224069b..09c51c9 100644 --- a/ios/ReactNativeHealthkit.swift +++ b/ios/ReactNativeHealthkit.swift @@ -616,20 +616,6 @@ class ReactNativeHealthkit: RCTEventEmitter { store.execute(query) } - //Helper function with completions so that async fetching of workout plan can be done - @available(iOS 17.0, *) - func fetchWorkoutPlan(for workout: HKWorkout, completion: @escaping (WorkoutPlan?) -> Void) { - Task { - do { - let workoutplan = try await workout.workoutPlan - completion(workoutplan) - } catch { - print("Error: \(error)") - completion(nil) - } - } - } - @objc(queryWorkoutSamples:distanceUnitString:from:to:limit:ascending:resolve:reject:) func queryWorkoutSamples(energyUnitString: String, distanceUnitString: String, from: Date, to: Date, limit: Int, ascending: Bool, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { @@ -730,7 +716,7 @@ class ReactNativeHealthkit: RCTEventEmitter { if #available(iOS 17.0, *) { do { - let workoutplan = try await self.fetchWorkoutPlan(for: workout) + let workoutplan = try await workout.workoutPlan if let workoutplanId = workoutplan?.id { dict["workoutPlanId"] = workoutplanId.uuidString } From 393dc860e970a65def39da367ae9cebe1281f9d6 Mon Sep 17 00:00:00 2001 From: Walter Holohan Date: Wed, 30 Aug 2023 13:55:20 +0100 Subject: [PATCH 07/11] chore: remove unused variables --- ios/ReactNativeHealthkit.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/ios/ReactNativeHealthkit.swift b/ios/ReactNativeHealthkit.swift index 09c51c9..3332524 100644 --- a/ios/ReactNativeHealthkit.swift +++ b/ios/ReactNativeHealthkit.swift @@ -640,9 +640,6 @@ class ReactNativeHealthkit: RCTEventEmitter { return resolve([]) } let arr: NSMutableArray = [] - //create counts for completed workouts so that we can resolve the promise when all workouts have been serialized - var completedWorkoutCount = 0 - let totalWorkouts = samples.count for s in samples { if let workout = s as? HKWorkout { From 0c89e417636349f7986c80cae0f7b3c4f40a5365 Mon Sep 17 00:00:00 2001 From: Walter Holohan Date: Wed, 30 Aug 2023 13:57:17 +0100 Subject: [PATCH 08/11] chore: revert white space line changes --- ios/ReactNativeHealthkit.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ios/ReactNativeHealthkit.swift b/ios/ReactNativeHealthkit.swift index 3332524..e0dc88b 100644 --- a/ios/ReactNativeHealthkit.swift +++ b/ios/ReactNativeHealthkit.swift @@ -635,18 +635,16 @@ class ReactNativeHealthkit: RCTEventEmitter { let q = HKSampleQuery(sampleType: .workoutType(), predicate: predicate, limit: limit, sortDescriptors: getSortDescriptors(ascending: ascending)) { (_: HKSampleQuery, sample: [HKSample]?, error: Error?) in guard let err = error else { - guard let samples = sample else { return resolve([]) } let arr: NSMutableArray = [] - + for s in samples { if let workout = s as? HKWorkout { let endDate = self._dateFormatter.string(from: workout.endDate) let startDate = self._dateFormatter.string(from: workout.startDate) - - + let dict: NSMutableDictionary = [ "uuid": workout.uuid.uuidString, "device": serializeDevice(_device: workout.device) as Any, @@ -725,10 +723,12 @@ class ReactNativeHealthkit: RCTEventEmitter { arr.add(dict) } } + return resolve(arr) } reject(GENERIC_ERROR, err.localizedDescription, err) } + store.execute(q) } From e0fcfddcf41910e50dd9b35d0de26439bdfa7cb8 Mon Sep 17 00:00:00 2001 From: Walter Holohan Date: Wed, 30 Aug 2023 22:14:06 +0100 Subject: [PATCH 09/11] feat: update HL types for activity summary --- src/native-types.ts | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/native-types.ts b/src/native-types.ts index 259f5a6..f53b98f 100644 --- a/src/native-types.ts +++ b/src/native-types.ts @@ -8,17 +8,29 @@ import type { EmitterSubscription, NativeModule } from 'react-native' */ export const HKWorkoutTypeIdentifier = 'HKWorkoutTypeIdentifier' as const +/** + * Represents a type that identifies activity summary objects. + * @see {@link https://developer.apple.com/documentation/healthkit/hkactivitysummarytype Apple Docs HKActivitySummaryType} + */ +export const HKActivitySummaryType = 'HKActivitySummaryType' as const + /** * Represents an audiogram type identifier. + * @see {@link https://developer.apple.com/documentation/healthkit/HKAudiogramSampleType Apple Docs HKAudiogramSampleType} */ -export const HKAudiogramTypeIdentifier = 'HKAudiogramTypeIdentifier' as const +export const HKAudiogramTypeIdentifier = 'HKAudiogramSampleType' as const /** * Represents a workout route type identifier. * @see {@link https://developer.apple.com/documentation/healthkit/hkworkoutroutetypeidentifier Apple Docs HKWorkoutRouteTypeIdentifier} */ export const HKWorkoutRouteTypeIdentifier = 'HKWorkoutRouteTypeIdentifier' as const -export const HKDataTypeIdentifierHeartbeatSeries = 'HKDataTypeIdentifierHeartbeatSeries' as const + +/** + * Represents a series sample containing heartbeat data.. + * @see {@link https://developer.apple.com/documentation/healthkit/HKDataTypeIdentifierHeartbeatSeries Apple Docs HKDataTypeIdentifierHeartbeatSeries} + */ +export declare const HKDataTypeIdentifierHeartbeatSeries: 'HKDataTypeIdentifierHeartbeatSeries' /** * Represents a quantity type identifier. @@ -698,6 +710,13 @@ export enum HKQuantityTypeIdentifier { * @since iOS 16 */ runningVerticalOscillation = 'HKQuantityTypeIdentifierRunningVerticalOscillation', + + /** + * Running Speed + * @see {@link https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifierrunningspeed Apple Docs HKQuantityTypeIdentifierRunningSpeed} + * @since iOS 16 + */ + runningSpeed = 'HKQuantityTypeIdentifierRunningSpeed', } export type TypeToUnitMapping = { @@ -796,16 +815,7 @@ export enum HKCategoryTypeIdentifier { } export type HKSampleTypeIdentifier = - | HKCategoryTypeIdentifier - | HKCorrelationTypeIdentifier - | HKQuantityTypeIdentifier - | typeof HKAudiogramTypeIdentifier - | typeof HKDataTypeIdentifierHeartbeatSeries - | typeof HKWorkoutRouteTypeIdentifier - | typeof HKWorkoutTypeIdentifier - | `${HKCategoryTypeIdentifier}` - | `${HKCorrelationTypeIdentifier}` - | `${HKQuantityTypeIdentifier}`; + HKCategoryTypeIdentifier | HKCorrelationTypeIdentifier | HKQuantityTypeIdentifier | typeof HKActivitySummaryType | typeof HKAudiogramTypeIdentifier | typeof HKDataTypeIdentifierHeartbeatSeries | typeof HKWorkoutRouteTypeIdentifier | typeof HKWorkoutTypeIdentifier | `${HKCategoryTypeIdentifier}` | `${HKCorrelationTypeIdentifier}` | `${HKQuantityTypeIdentifier}`; export type HealthkitReadAuthorization = | HKCharacteristicTypeIdentifier From 87688be53de6b60f5f4edef7807d4f63aeadc984 Mon Sep 17 00:00:00 2001 From: Walter Holohan Date: Thu, 31 Aug 2023 15:31:24 +0100 Subject: [PATCH 10/11] feat: add canImport tags so its backwards compatible --- ios/ReactNativeHealthkit.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ios/ReactNativeHealthkit.swift b/ios/ReactNativeHealthkit.swift index e0dc88b..7ec6de6 100644 --- a/ios/ReactNativeHealthkit.swift +++ b/ios/ReactNativeHealthkit.swift @@ -1,6 +1,9 @@ import HealthKit import CoreLocation + +#if canImport(WorkoutKit) import WorkoutKit +#endif @objc(ReactNativeHealthkit) @available(iOS 10.0, *) @@ -709,6 +712,7 @@ class ReactNativeHealthkit: RCTEventEmitter { dict.setValue(serializeQuantity(unit: HKUnit.count(), quantity: workout.totalFlightsClimbed), forKey: "totalFlightsClimbed") } + #if canImport(WorkoutKit) if #available(iOS 17.0, *) { do { let workoutplan = try await workout.workoutPlan @@ -719,6 +723,7 @@ class ReactNativeHealthkit: RCTEventEmitter { // handle error } } + #endif arr.add(dict) } From 6b675ebd1b4deaa4d4352f90ce05323141ba1d06 Mon Sep 17 00:00:00 2001 From: Walter Holohan Date: Thu, 31 Aug 2023 16:47:22 +0100 Subject: [PATCH 11/11] fix: handle when enddate is nil --- ios/ReactNativeHealthkit.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/ReactNativeHealthkit.swift b/ios/ReactNativeHealthkit.swift index 7ec6de6..90d222e 100644 --- a/ios/ReactNativeHealthkit.swift +++ b/ios/ReactNativeHealthkit.swift @@ -694,7 +694,7 @@ class ReactNativeHealthkit: RCTEventEmitter { activityStartDate = self._dateFormatter.string(from: activity.startDate) } if let end = activity.endDate as Date? { - activityEndDate = self._dateFormatter.string(from: activity.endDate) + activityEndDate = self._dateFormatter.string(from: activity.endDate!) } let activityDict: [String: Any] = [ "startDate": activityStartDate,