kingstinct / react-native-healthkit Goto Github PK
View Code? Open in Web Editor NEWHealthKit bindings for React Native with TypeScript
Home Page: https://kingstinct.com/react-native-healthkit/
License: MIT License
HealthKit bindings for React Native with TypeScript
Home Page: https://kingstinct.com/react-native-healthkit/
License: MIT License
According to Apple, the correct names are HKMetadataKeySyncIdentifier
and HKMetadataKeySyncVersion
. I actually tried both key names, but only the HKMetadataKeyXXX
key correctly deduplicated the data.
Thanks for this amazing library; it's the most comprehensive react native bridge for HealthKit ❤️
EDIT: I now notice other keys missing the MetadataKey
prefix, such as HKMetadataKeyReferenceRangeLowerLimit
Hi team,
Is there any way to check if user device installed Health app or not? It's as like as the method
isAvailable(callback); // Checks is GoogleFit available for current account / installed on device
in react-native-google-fit?
Thanks in advanced.
When the device is locked, health data becomes inaccessible and the following error is thrown in background.
Fatal error: 'try!' expression unexpectedly raised an error: Error Domain=com.apple.healthkit Code=6 "Protected health data is inaccessible" UserInfo={NSLocalizedDescription=Protected health data is inaccessible}
One solution could be to return the value of isProtectedDataAvailable or listen to applicationProtectedDataWillBecomeUnavailable / applicationProtectedDataDidBecomeAvailable or protectedDataDidBecomeAvailableNotification / protectedDataWillBecomeUnavailableNotification to check that protected files are available.
Hello, thank you for the great work with this library. It's been really helpful having such a close mapping to the native APIs.
I am trying to access a method to delete a workout by uuid. I see the delete samples methods, however I'm not seeing an option type for workouts. Any direction here would be great.
Thanks.
Hello and thanks for great library!
I see we can deleteSamples by uuid, but is it possible to add ability deleteSamples without uuid, just use startDate, endDate for it? For example like it done on deleteSamples here (https://github.com/EddyVerbruggen/HealthKit).
const authResult = await HealthKit.requestAuthorization([
HKWorkoutActivityType.cycling,
HKWorkoutActivityType.running,
]);
console.log("requestAuthorization: ", authResult);
Thanks for the nice modern lib in TypeScript!
How do you handle testing on the simulator, given that it has no health data? Would it make sense to have an ability to generate test data?
To comply with Apple recommendations and to prevent any race conditions that might arise from initialising it later, as is the case now.
There are two parts to this:
This is not really an issue, just a thread for those who are looking to move away from agencyenterprise/react-native-health.
I was looking for an alternative that doesn't hide functionality, uses non-deprecated solutions and comes with proper type definition. Even though this package doesn't have extensive documentation I think it's still a pretty good alternative. (Also, It's in swift which is a bonus over objc)
I've spent some time on creating a simple 1-way workout sync and I ended up using the following snippet:
import HealthKit, {
HKQuantityTypeIdentifier,
HKWorkoutActivityType,
HKWorkoutTypeIdentifier,
} from '@kingstinct/react-native-healthkit';
import { v4 as uuid } from 'uuid';
const main = async () => {
const isAuthed = await HealthKit.requestAuthorization(
[HKWorkoutTypeIdentifier, HKQuantityTypeIdentifier.activeEnergyBurned],
[HKWorkoutTypeIdentifier, HKQuantityTypeIdentifier.activeEnergyBurned],
);
if (!isAuthed) {
return -1;
}
// This data comes from our API
const externalId = uuid();
const startDate = new Date('2022-01-01T00:00:00.000Z');
const endDate = new Date('2022-01-01T00:13:00.000Z');
await HealthKit.saveWorkoutSample(
HKWorkoutActivityType.highIntensityIntervalTraining,
[
{
quantityType: HKQuantityTypeIdentifier.activeEnergyBurned,
unit: 'kcal',
quantity: 666,
},
],
startDate,
{
end: endDate,
metadata: {
HKExternalUUID: externalId,
},
},
);
}
Hi,
I'm trying to access vo2Max data on healthkit by requesting authorization to the HKQuantityTypeIdentifier.vo2Max
quantity type, which is available in the library. I'm requesting the authorization along with other quantity type identifiers such as heart rate, body mass, etc.
When launching the app for the first time, the iOS screen to request the user to authorize those scopes is coming up normally, however I get to see all the scopes I'm requesting EXCEPT for vo2Max. If I then try to access the vo2Max data using the queryQuantitySamples method I am obviously getting an error as the user has not authorized access to it.
Has anybody else experience this issue and are there any known workarounds to get VO2Max to work?
Thanks
I'd love to be able to delete samples in case a user creates on in error. I also don't mind contributing but don't exactly know where to start. Thanks for the great work!
https://developer.apple.com/documentation/healthkit/hkhealthstore/1614155-delete
Hi guys,
Thanks for your great work here, react native really needs a good healthkit lib. After I implemented this library into my app and submitted a release Apple rejected the app.
I thought it was because of the example app in this repo (Clinical API permission in the plist) so I removed that from my code and resubmitted it to the app store but it was still rejected.
I'm happy to contribute a PR but I'm not really sure how to go about fixing this (my native iOS knowledge is subpar to say the least) so I would need some direction.
In case I want to revoke the connection and remove all existing permissions to apple health.
SCENARIO:
I requested reading permissions - Heartrate, and stepCount but only allowed permission for Heartrate.
I have no indication i didn't give permission to stepCount and (the requestAuthorization returns 1) and no way to reask for permissions (no disconnect)
I just noticed that queryQuantitySamples
, queryCategorySamples
, and queryHeartbeatSeriesSamples
still have the ascending
parameter, but HKAnchoredObjectQuery
has no way of sorting the samples. The result is also that the getMostRecentQuantitySample
and getMostRecentCategorySample
return the wrong samples (unexpected by the ascending
parameter).
I guess the best way to deal with this is to have both query<type>Samples
and query<type>SamplesWithAnchor
methods as both have their uses?
the types have ascending
as a boolean but the Swift code has ascending
as an NSNumber
. When I try to pass true
, it throws an error in some code that looks to be related to converting code in the RN bridge
sorry, I can't provide an exact error message. I was using the library for a hackathon project and the hackathon is now over and I've been moved to other work
my company may end up going forward with my hackathon project so it's possible I'll be back in that code at some point and I can help fix
We have an old branch with health record implemented, but it was removed because it can be a blocker for app submissions if not actually using it.
I think it'd now be possible to lift this back in again - by extending the Expo Config Plugin to support opt-in to use this API. As part of this we need to make sure the Swift code referring to this is only included if the developer opts-in to use it.
The most natural way to include it would probably be to support setting the following info.plist entries in the config plugin, and only if these properties are set include the needed Swift code in the binary:
{
"expo": {
"plugins": [
["@kingstinct/react-native-healthkit", {
"NSHealthClinicalHealthRecordsShareUsageDescription": "Your own custom usage description",
"NSHealthRequiredReadAuthorizationTypeIdentifiers": ["allergyRecord"]
}]
]
}
}
Hello and thanks for great library!
Is it possible to save device data values in saveQuantitySample
method?
I see we can query Health data by device and there we use serializeDevice
method. But what about saveQuantitySample
?
Just FYI - https://developer.apple.com/documentation/healthkit/hkquantitysample/1615019-init
I'm saving sleep records using this library (among other data), but in the XCode organizer it shows up many users are having crashes which I cannot explain. I was not able to reproduce it myself. Can you please point me in the right direction here?
Let me know if you need more information. Thanks!
Date/Time: 2023-02-07 06:29:13.1467 -0600
Launch Time: 2023-02-06 21:42:01.6785 -0600
OS Version: iPhone OS 15.6.1 (19G82)
Release Type: User
Baseband Version: 4.04.02
Report Version: 104
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Triggered by Thread: 10
Last Exception Backtrace:
0 CoreFoundation 0x1813e1288 __exceptionPreprocess + 220 (NSException.m:200)
1 libobjc.A.dylib 0x19a111744 objc_exception_throw + 60 (objc-exception.mm:565)
2 CoreFoundation 0x181438390 +[NSException raise:format:] + 112 (NSException.m:156)
3 HealthKit 0x18e2494f4 -[HKObject _validateForCreation] + 144 (HKObject.m:127)
4 HealthKit 0x18e249260 +[HKObject _newDataObjectWithMetadata:device:config:] + 276 (HKObject.m:112)
5 HealthKit 0x18e249108 +[HKSample _newSampleWithType:startDate:endDate:device:metadata:config:] + 204 (HKSample.m:42)
6 HealthKit 0x18e24aa9c +[HKCategorySample categorySampleWithType:value:startDate:endDate:device:metadata:] + 296 (HKCategorySample.m:42)
7 AuraTrack 0x10040cfbc @nonobjc HKCategorySample.__allocating_init(type:value:start:end:metadata:) + 48 (<compiler-generated>:0)
8 AuraTrack 0x10040cfbc ReactNativeHealthkit.saveCategorySample(typeIdentifier:value:start:end:metadata:resolve:reject:) + 664 (ReactNativeHealthkit.swift:573)
9 AuraTrack 0x10040d268 @objc ReactNativeHealthkit.saveCategorySample(typeIdentifier:value:start:end:metadata:resolve:reject:) + 368 (<compiler-generated>:0)
10 CoreFoundation 0x181369b24 __invoking___ + 148 (:-1)
11 CoreFoundation 0x181387610 -[NSInvocation invoke] + 468 (NSForwarding.m:3378)
12 CoreFoundation 0x1813be5fc -[NSInvocation invokeWithTarget:] + 80 (NSForwarding.m:3475)
13 AuraTrack 0x1002c0728 -[RCTModuleMethod invokeWithBridge:module:arguments:] + 388 (RCTModuleMethod.mm:584)
14 AuraTrack 0x1002c28a0 facebook::react::invokeInner(RCTBridge*, RCTModuleData*, unsigned int, folly::dynamic const&, int, (anonymous namespace)::SchedulingContext) + 1190048 (RCTNativeModule.mm:183)
15 AuraTrack 0x1002c2528 invocation function for block in facebook::react::RCTNativeModule::invoke(unsigned int, folly::dynamic&&, int) + 1189160 (RCTNativeModule.mm:95)
16 libdispatch.dylib 0x181046e6c _dispatch_call_block_and_release + 32 (init.c:1517)
17 libdispatch.dylib 0x181048a30 _dispatch_client_callout + 20 (object.m:560)
18 libdispatch.dylib 0x181050124 _dispatch_lane_serial_drain + 668 (inline_internal.h:2622)
19 libdispatch.dylib 0x181050c80 _dispatch_lane_invoke + 392 (queue.c:3944)
20 libdispatch.dylib 0x18105b500 _dispatch_workloop_worker_thread + 648 (queue.c:6732)
21 libsystem_pthread.dylib 0x1f25a10bc _pthread_wqthread + 288 (pthread.c:2599)
22 libsystem_pthread.dylib 0x1f25a0e5c start_wqthread + 8 (:-1)
Hi,
I believe there is a bug when calling HealthKit.requestAuthorization([])
where the requestAuth modal only shows once when the app is running?
Steps to reproduce are as follows:
await HealthKit.authorizationStatusFor(HKCategoryTypeIdentifier.sleepAnalysis)
to check if we have access to sleepAnalysisHealthKit.isHealthDataAvailable()
which is true.await HealthKit.requestAuthorization([HKCategoryTypeIdentifier.sleepAnalysis])
HealthKit.requestAuthorization
doesn't render the UIAny thoughts on working around this?
I was able to get the underwater depth and water temperature records of the Apple Watch Ultra through this library. But I couldn't find a way to get all the quantity for each record. how can i get them?
Hi, I'm trying to run useHealthkitAuthorization
to be able to write data. I'm able to enable read permissions just fine, but I get an error when I try to request a write permission.
unrecognized selector sent to instance ... was thrown while invoking requestAuthorization on target ReactNativeHealthkit
.
I'm running this on an Expo Dev Client.
Here are my plugins:
"plugins": [
"expo-router",
["@kingstinct/react-native-healthkit", {
"NSHealthShareUsageDescription": "my app uses Apple Health to read and write data.",
"NSHealthUpdateUsageDescription": true,
"background": true
}]
],
The code I'm using looks like this:
export default function Home() {
const [authorizationStatus, requestAuthorization] = useHealthkitAuthorization(
[
HKQuantityTypeIdentifier.bodyMass,
HKQuantityTypeIdentifier.appleMoveTime,
HKQuantityTypeIdentifier.appleStandTime,
HKQuantityTypeIdentifier.heartRate,
HKQuantityTypeIdentifier.height,
HKQuantityTypeIdentifier.vo2Max,
HKQuantityTypeIdentifier.basalEnergyBurned,
HKQuantityTypeIdentifier.activeEnergyBurned,
HKQuantityTypeIdentifier.appleExerciseTime,
HKQuantityTypeIdentifier.restingHeartRate,
HKQuantityTypeIdentifier.timeInDaylight,
HKQuantityTypeIdentifier.stepCount,
HKQuantityTypeIdentifier.headphoneAudioExposure,
HKCategoryTypeIdentifier.sleepAnalysis,
HKCategoryTypeIdentifier.sexualActivity,
HKCategoryTypeIdentifier.mindfulSession,
HKActivitySummaryTypeIdentifier,
HKWorkoutTypeIdentifier,
HKWorkoutRouteTypeIdentifier,
HKCharacteristicTypeIdentifier.dateOfBirth,
HKCharacteristicTypeIdentifier.biologicalSex,
HKCharacteristicTypeIdentifier.activityMoveMode,
], [HKQuantityTypeIdentifier.bodyMass]
);
Thanks for the help!
After adding the module to my Expo SDK48 project, EAS builds started to fail. Simulator builds worked as they are more relaxed with provisioning profiles.
The error that occurred was:
doesn't match the entitlements file's value for the com.apple.developer.healthkit.background-delivery entitlement
"plugins": [
"expo-build-properties",
[
"@kingstinct/react-native-healthkit",
{
"NSHealthShareUsageDescription": false,
"NSHealthUpdateUsageDescription": "Write workout information to HealthKit",
"background": false
}
]
],
To fix the issue, and get EAS working again I had to change background
to true
Just taking a guess here, but it could be related to:
https://github.com/Kingstinct/react-native-healthkit/blob/1585007848e0ffeed9ae4f767aac881082475dec/app.plugin.js#L43
Should it be wrapped in an if statement to avoid it being added at all?
Or perhaps the EAS build is removing com.apple.developer.healthkit.background-delivery
when the value is false?
One more note, the App Store will reject your app if you have "NSHealthShareUsageDescription": false
Thanks for this incredible library!
I'd like to receive downhill skiing and snowboarding data :)
Expose HKAnchoredObjectQuery to make it easy to fetch only updated samples.
I'm using the 7.0.0 version and getting a build error. Here are the relevant lines from the build logs:
The following build commands failed:
CompileSwift normal arm64 (in target 'kingstinct-react-native-healthkit' from project 'Pods')
CompileSwiftSources normal arm64 com.apple.xcode.tools.swift.compiler (in target 'kingstinct-react-native-healthkit' from project 'Pods')
(2 failures)
Exit status: 65
I can build a local simulator version and it works fine, but can't build for ad-hoc distribution.
Any idea why it would fail to compile?
Official documentation shows it should return an enum that evaluates to numbers (DOCS):
The function in the lib returns a boolean instead.
When I first grant access in the app, it shows the permission sheet because it results in notDetermined
(0). After that, when testing and disabling/enabling access through settings -> health -> data for my app, it always results in 1.
Now:
boolean
so why is it a number
? I guess it's because JS converts somehow 1 and 2 to true and then converts that to a 1 but not sure.sharingDenied
(1) and sharingAuthorized
(2) SHOULD differ so that's false info. But Apple says they don't show if the user denied access so it's weird it's there in the first placeIs there any way to solve this and differentiate between denied and authorized?
I have noticed a strange issue with the Apple Health permissions for when trying to use the Native.getWorkoutRoutes(currentRun.uuid)
What happens is the user accepts permissions to access
"HKWorkoutTypeIdentifier" and "HKWorkoutRouteTypeIdentifier"
the getWorkoutRoutes works for a few days but then it just returns null after that for some users.
I have been able to reproduce this on my device as well and when I navigate to Apple Health app and go to the workouts section and scroll to the bottom and view the following permissions:
Data Sources and Access
Workout Route Data Sources & Access
They are both turned on for my app.
The strange thing is if I unselect the permission and turn it back on again then when I try and call getWorkoutRoutes again it begins to work again. Long term though this isn't really a viable solution to expect the user to turn off and turn on the permission each time so maybe theres an issue with how this function checks the permission as it is already enabled in Apple Health but only works when you toggle it off and on again.
I don't really have any logs to help debug this issue so apologies for that but hopefully that is enough to investigate.
Hi @robertherber !
Fist of all, thanks for this super cool library! I've seen since I updated the xcode version to the v15 that the background refresh has stopped working. Well, I first saw this issue in the useStatisticsForQuantity
hook, but also in useSubscribeChange
which makes sense as it is used in the first one! I'm using expo v50, in case it helps you to know it. Can it be that we are missing a commit like 7ecfd9b for Xcode15?
I attach here a chunk of code using the hook mentioned above
const energy = useStatisticsForQuantity(
HKQuantityTypeIdentifier.activeEnergyBurned,
[HKStatisticsOptions.cumulativeSum],
from,
undefined,
UnitOfEnergy.Kilocalories
)
Thanks!!
Hi,
Couple of questions:
Q1: I am trying to save blood pressure values (sys/dia) and I am using iOS device, I tried this but it seems the values are not persisted:
Healthkit.saveQuantitySample(
HKQuantityTypeIdentifier.bloodPressureSystolic,
HKUnit.MillimetersOfMercury,
120, {
start: new Date()
}
);
Healthkit.saveQuantitySample(
HKQuantityTypeIdentifier.bloodPressureDiastolic,
HKUnit.MillimetersOfMercury,
70, {
start: new Date()
}
);
Q2: I am trying to save the heart rate measurement and I am using this code, but it seems there is a problem in the "Count" unit, I think the code expects "count/min" but it seems the value is not mapped:
Healthkit.saveQuantitySample(
HKQuantityTypeIdentifier.heartRate,
HKUnit.Count,
68,
{
start: new Date(),
}
);
Appreciate any help on this, thanks!
Hello there!
I was trying to walk thru some of the examples on the README, but am getting errors when trying to use the hooks.
For example when I add this line to my project:
import { HKQuantityTypeIdentifier, useHealthkitAuthorization } from '@kingstinct/react-native-healthkit';
VSCode shows the following error:
'"@kingstinct/react-native-healthkit"' has no exported member named 'useHealthkitAuthorization'. Did you mean 'HealthkitReadAuthorization'?ts(2724)
Is there something else I have to configure here? I did notice in the example app we're doing it a bit differently:
import useHealthkitAuthorization from '@kingstinct/react-native-healthkit/hooks/useHealthkitAuthorization'
However this also resulted in the same issue on my side.
In iOS 16 Apple has introduced a sharing option in which you can share data with friends/family. I was looking through the docs to see if it's an accessible from the API side but didn't see it. Do you know if it's around? I'd love to implement it if so.
Hi! I'm having this problem and I don't know if it is a bug or I'm just not understanding how I should manage it.
I coded two hooks in the imperative way, one to request permissions and other to read the data that I have requested.
So I first request these permissions in the onboarding (first hook) and then consulting them when the user makes some update of his data like changing his username or nutritional goals (here is where the crash occurs).
I don't know if I'm doing wrong by use the hooks separately or what, thanks in advance for your cooperation.
Here's my code:
const useAppleRequest = (request: boolean) => {
const navigation = useNavigation();
const routes = navigation.getState()?.routes;
const prevRoute = routes[routes.length - 2];
useEffect(() => {
try {
if (request) {
const read = async () => {
const isAvailable = await HealthKit.isHealthDataAvailable();
if (!isAvailable) {
return;
}
const permissionStatus = await HealthKit.requestAuthorization([
HKQuantityTypeIdentifier.stepCount,
HKCategoryTypeIdentifier.sleepAnalysis,
HKCharacteristicTypeIdentifier.biologicalSex,
HKCharacteristicTypeIdentifier.bloodType,
HKCharacteristicTypeIdentifier.dateOfBirth,
HKQuantityTypeIdentifier.height,
HKQuantityTypeIdentifier.bodyMass,
HKCategoryTypeIdentifier.pregnancy,
HKCategoryTypeIdentifier.diarrhea,
]);
return permissionStatus;
};
read();
// I could cut this lines but just in case I don't take it out
if (prevRoute === "AllowApple") {
navigation.navigate("Name");
} else if (prevRoute === "Father") {
navigation.goBack();
}
}
} catch (error) {
logEventAsync(JSON.stringify(error));
}
}, [request]);
};
export default useAppleRequest;
`
import HealthKit, {
HKQuantityTypeIdentifier,
HKCategoryTypeIdentifier,
HKUnits,
HKCharacteristicTypeIdentifier,
} from "@kingstinct/react-native-healthkit";
import { customAxios } from "../../App";
import { useAppSelector } from "./hooks";
const useAppleRead = (use: boolean) => {
const userId = useAppSelector((state) => state.user.id);
useEffect(() => {
if (use) {
const read = async () => {
const sleepAuth = await HealthKit.authorizationStatusFor(
HKCategoryTypeIdentifier.sleepAnalysis
);
const stepsAuth = await HealthKit.authorizationStatusFor(
HKQuantityTypeIdentifier.stepCount
);
const heightAuth = await HealthKit.authorizationStatusFor(
HKQuantityTypeIdentifier.height
);
const bodyMassAuth = await HealthKit.authorizationStatusFor(
HKQuantityTypeIdentifier.bodyMass
);
const pregnancyAuth = await HealthKit.authorizationStatusFor(
HKCategoryTypeIdentifier.pregnancy
);
const diarrheaAuth = await HealthKit.authorizationStatusFor(
HKCategoryTypeIdentifier.diarrhea
);
const genderAuth = await HealthKit.authorizationStatusFor(
HKCharacteristicTypeIdentifier.biologicalSex
);
const bloodTypeAuth = await HealthKit.authorizationStatusFor(
HKCharacteristicTypeIdentifier.bloodType
);
const ageAuth = await HealthKit.authorizationStatusFor(
HKCharacteristicTypeIdentifier.dateOfBirth
);
const sleep = sleepAuth
? await HealthKit.getMostRecentCategorySample(
HKCategoryTypeIdentifier.sleepAnalysis
)
: null;
const steps = stepsAuth
? await HealthKit.getMostRecentQuantitySample(
HKQuantityTypeIdentifier.stepCount,
HKUnits.Count
)
: null;
const height = heightAuth
? await HealthKit.getMostRecentQuantitySample(
HKQuantityTypeIdentifier.height,
HKUnits.Count
)
: null;
const bodyMass = bodyMassAuth
? await HealthKit.getMostRecentQuantitySample(
HKQuantityTypeIdentifier.bodyMass,
HKUnits.Count
)
: null;
const pregnancy = pregnancyAuth
? await HealthKit.getMostRecentCategorySample(
HKCategoryTypeIdentifier.pregnancy
)
: null;
const diarrhea = diarrheaAuth
? await HealthKit.getMostRecentCategorySample(
HKCategoryTypeIdentifier.diarrhea
)
: null;
const gender = genderAuth ? await HealthKit.getBiologicalSex() : null;
const bloodType = bloodTypeAuth ? await HealthKit.getBloodType() : null;
const age = ageAuth ? await HealthKit.getDateOfBirth() : null;
await customAxios.post("MY_ROUTE", {
steps,
sleep,
gender,
bloodType,
age,
height,
bodyMass,
pregnancy,
diarrhea,
userId,
});
};
read();
}
}, [use]);
};
export default useAppleRead;`
Hi there, we're attempting to use the Expo plugin, however we're seeing the following when running the app:
> [email protected] ios
> expo start --ios
Starting project at /Users/josh/Desktop/rn-health-test-app
PluginError: Package "@kingstinct/react-native-healthkit" does not contain a valid config plugin.
Learn more: https://docs.expo.dev/guides/config-plugins/#creating-a-plugin
Cannot use import statement outside a module
/Users/josh/Desktop/rn-health-test-app/node_modules/@kingstinct/react-native-healthkit/lib/module/index.js:1
import { Platform } from 'react-native';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at internalCompileFunction (node:internal/vm:73:18)
at wrapSafe (node:internal/modules/cjs/loader:1176:20)
at Module._compile (node:internal/modules/cjs/loader:1218:27)
at Module._extensions..js (node:internal/modules/cjs/loader:1308:10)
at Module.load (node:internal/modules/cjs/loader:1117:32)
at Module._load (node:internal/modules/cjs/loader:958:12)
at Module.require (node:internal/modules/cjs/loader:1141:19)
at require (node:internal/modules/cjs/helpers:110:18)
at requirePluginFile (/Users/josh/Desktop/rn-health-test-app/node_modules/@expo/config-plugins/build/utils/plugin-resolver.js:214:12)
at resolveConfigPluginFunctionWithInfo (/Users/josh/Desktop/rn-health-test-app/node_modules/@expo/config-plugins/build/utils/plugin-resolver.js:155:14)
Is this what is meant by the comment in the repo "just keep in mind it will not work in Expo Go"? I note there's an open discussion in the Expo repo about supporting ESM for expo plugins: expo/expo#19359
npx create-expo-app rn-health-test-app
npm i @kingstinct/react-native-healthkit
npm run ios
Observe error message.
I'm figuring this is a problem not everybody is having, just me missing a step or so.
I've just installed the package, updated app.json with infoPlist and entitlements.
After opening the app in a dev-build in my physical phone the app crashes immediately when requesting for authorization.
import HealthKit, { HKQuantityTypeIdentifier } from "@kingstinct/react-native-healthkit";
const authResult = await HealthKit.requestAuthorization([
Healthkit.useMostRecentQuantitySample(HKQuantityTypeIdentifier.walkingStepLength),
]);
console.log("authResult: ", authResult);
Got same result when using the examples in readme of package
Works fine on simulator but fails on Archive with error "no such module combine"
(Xcode Version 12.5, React Native 0.64.0)
I already tried to build with iOS Deployment Target 9, 13 and 14
HI @robertherber - I'm building an app where I'd like to show step counts by day for the last 30 days (or year etc.)
I think the right way to do this is using a HKStatisticsCollectionQuery where interval is something like day = 1. I haven't tested against a real user with lots of step data but I'm guessing calculating it via step samples will be too slow.
Curious if you agree with the above statement? If so, I'm happy to work on adding that API to the library.
Thanks again for putting this library together, very well designed and I've learned a lot about Swift, HealthKit and native module dev from it!
true
value:HealthKit.requestAuthorization(
[
HKQuantityTypeIdentifier.heartRate,
HKQuantityTypeIdentifier.stepCount,
HKQuantityTypeIdentifier.height,
]
)
.then(r => {
console.log(r); // always returns true
})
.catch(e => {
console.log('error: ', e);
});
Can it return the list of allowed permissions instead?
HealthKit.getRequestStatusForAuthorization([
HKQuantityTypeIdentifier.heartRate,
]).then(r => {
console.log(r); //returns 2 => corresponding to `unnecessary`
});
The issue persists even when I enable manually the permission in phone settings->health
The above method accepts an array of data type authorizations, but always return just 1 HKAuthorizationRequestStatus
. Shouldnt it return a value for each of the data types in the request array?
HealthKit.authorizationStatusFor(HKQuantityTypeIdentifier.heartRate).then(
permissionStatus => {
console.log('Permission Status', 'appleMoveTime', permissionStatus);
if (permissionStatus === 0) {
HealthKit.requestAuthorization([
HKQuantityTypeIdentifier.heartRate,
]).then(r => {
console.log(r); //returns 1 => HKAuthorizationStatus = `sharindDenied`
});
}
},
);
The above method doesnt work as expected as well, returning a value of 1 after the permissions were requested for all, even for those that the user has accepted in the first step
I cannot request a specific authorization if it was asked before in a previous step using both imperative methods and hooks.
Is there another way to get the list of authorized data types or revoke and ask for the authorizations again?
First of all, thanks for the great and modern library in TypeScript and Swift! Fantastic work.
One thing that seems to be missing is the ability to obtaining raw heartbeat data by first querying HKHeartbeatSeriesSample
, which can be done with a normal anchored query, and then obtaining the underlying heartbeat data of each sample with a HKHeartbeatSeriesQuery
.
I went ahead and implemented it myself, exposing the queryHeartbeatSeriesSamples
method that returns the serialized samples comprising the heartbeat data as described above.
However, before submitting any PR, I wanted to be sure that there is no other way to do it with the already existing implementation that I might have missed.
Cheers!
HealthKit.queryStatisticsForQuantity()'s Promise (and other functions too) is stuck in the Pending state if there are no samples for the time frame specified. In other words, it never resolves. Meaning:
I think the correct way of doing things is if there are no samples for the specified period instead of having a non-resolved promised we should have either a failed Promise that we're able to capture with .catch() or a successful Promise with the response being undefined or something like that that we're able to capture with .then(). This is so that we're able to handle this situation ourselves in the code.
I tried to enable background delivery by calling:
HealthKit.enableBackgroundDelivery(HKQuantityTypeIdentifier.bodyMass, HKUpdateFrequency.immediate)
and got an exception:
enabledBackgroundDelivery:updateFrequency:withResolver:withRejector: is not a recognized Objective-C method
I investigated a little and found that the method signatures in ios/ReactNativeHealthkit.m and ios/ReactNativeHealthkit.swift don't match.
I'm putting together a pull request that fixes this and a few other methods.
I am using this package to query swimming data.
I got most of the information, but I couldn't get the Swimming Stroke Style.
My Code
export async function querySwimming(from?: Date, to?: Date) {
if (!from || !to) {
from = getFirstDayOfMonth()
to = getLastDayOfMonth()
}
const workouts = (
await HealthKit.queryWorkouts({
energyUnit: UnitOfEnergy.Kilocalories,
distanceUnit: UnitOfLength.Meter,
from,
to,
})
)
.filter(v => v.workoutActivityType === HKWorkoutActivityType.swimming)
.map(async v => {
const [bpm] = await HealthKit.queryQuantitySamples(
HKQuantityTypeIdentifier.heartRate,
{
from: new Date(v.startDate.getTime() - 1000),
to: new Date(v.endDate.getTime() + 1000),
},
)
Object.assign(v, {
bpm: bpm,
})
return v as HKWorkout<UnitOfEnergy.Kilocalories, UnitOfLength.Meter> & {
bpm: HKQuantitySample<HKQuantityTypeIdentifier.heartRate, 'count/min'>
}
})
return Promise.all(workouts)
}
Since HKWorkoutSwimmingLocationType is present in the queried metadata, I think HKSwimmingStrokeStyle should also be present in the metadata.
But I can't find that data at all. Can I get some advice on this part?
The official reference address for the part I am looking for is
https://developer.apple.com/documentation/healthkit/hkswimmingstrokestyle
I want to try and get the GPS location data for a users run from healthkit so thought I would call this method:
import Native from '@kingstinct/react-native-healthkit/src/native-types'
const gpsMarkers = await Native.getWorkoutRoutes("XXXXXXX-6485-48A4-BA19-XXXXXXXXXXX")
// uuid redacted
However right after that code runs the app just goes to the apple home page and there are no crash logs or anything indicating that it broke, it just exits the app. I would provide a minimal reproduction but there isn't really any helpful logs or anything to see.
I only make that call once I have gotten the permissions
`const [status, request] = useHealthkitAuthorization(readPermissions, [
HKQuantityTypeIdentifier.bodyMass,
...saveableCountTypes,
...saveableMassTypes,
...saveableWorkoutStuff,
]);
const [canAccessProtectedData, setAccessProtectedData] =
useState(false);
useEffect(() => {
if(Platform.OS=="ios") {
Healthkit.canAccessProtectedData()
.then(setAccessProtectedData)
.catch(() => setAccessProtectedData(false));
}
}, []);`
and I have called other methods like queryWorkouts fine which is where I got the uuid from in the first place.
import queryWorkouts from "@kingstinct/react-native-healthkit/src/utils/queryWorkouts";
const data = await queryWorkouts({ from: start, to: end, } );
I have tried wrapping the getWorkoutRoutes in a try catch block but that doesn't help either.
I am making use of activity mappings when the user has our react native app open but I'm wondering if it is possible to sync activities in the background (app in closed or background state) with this library.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.