diff --git a/ios/ReactNativeHealthkit.swift b/ios/ReactNativeHealthkit.swift index 4fbeb66..486063c 100644 --- a/ios/ReactNativeHealthkit.swift +++ b/ios/ReactNativeHealthkit.swift @@ -1,6 +1,10 @@ import HealthKit import CoreLocation +#if canImport(WorkoutKit) +import WorkoutKit +#endif + @objc(ReactNativeHealthkit) @available(iOS 10.0, *) class ReactNativeHealthkit: RCTEventEmitter { @@ -619,6 +623,7 @@ class ReactNativeHealthkit: RCTEventEmitter { @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) } @@ -658,11 +663,70 @@ 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 + //https://developer.apple.com/documentation/healthkit/hkworkoutevent + var eventArray: [[String: Any]] = [] + if let events = workout.workoutEvents { + 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 + ] + eventArray.append(eventDict) + } + } + 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 + //it seems this might be depricated in the latest beta so this might need updating! + var activitiesArray: [[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) + } + 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 + ] + activitiesArray.append(activityDict) + } + } + } + dict["activities"] = activitiesArray + if #available(iOS 11, *) { 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 + if let workoutplanId = workoutplan?.id { + dict["workoutPlanId"] = workoutplanId.uuidString + } + } catch { + // handle error + } + } + #endif + arr.add(dict) } } diff --git a/src/native-types.ts b/src/native-types.ts index 1a09fe6..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. @@ -670,6 +682,41 @@ 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', + + /** + * Running Speed + * @see {@link https://developer.apple.com/documentation/healthkit/hkquantitytypeidentifierrunningspeed Apple Docs HKQuantityTypeIdentifierRunningSpeed} + * @since iOS 16 + */ + runningSpeed = 'HKQuantityTypeIdentifierRunningSpeed', } export type TypeToUnitMapping = { @@ -768,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 @@ -1673,6 +1711,30 @@ HKCategorySampleRaw, 'device' | 'endDate' | 'startDate' | 'uuid' >; +export interface HKWorkoutEvent { + 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< TEnergy extends EnergyUnit, TDistance extends LengthUnit @@ -1695,6 +1757,9 @@ export type HKWorkoutRaw< readonly endDate: string; readonly metadata?: HKWorkoutMetadata; readonly sourceRevision?: HKSourceRevision; + readonly events?: readonly HKWorkoutEvent[]; + readonly activities?: readonly HKWorkoutActivity[]; + readonly workoutPlanId?: string; }; // Straight mapping to https://developer.apple.com/documentation/healthkit/hkcharacteristictypeidentifier