React Native MasteryThe Ultimate React Native and Expo Course. Launching November 26

React-Native Apple HealtKit

Part of:  Health Application with React Native: Step Counter  

Vadim Savin profile picture
Vadim SavinApr 20, 2024

In this tutorial, you will learn how to integrate a React Native (Expo) app with Apple HealthKit and how you can fetch Health & Fitness data directly in your app. We will use the react-native-health library, which will make things easier.

More specifically, you will learn to:

  • Use libraries with native code inside Expo by creating a Custom dev client
  • Install and work with react-native-health
  • Manage app permissions to Health data on iOS
  • Query health data like step counts, distance walked, flights climbed, etc.

Project

This tutorial is part of the Step Counter Project. You can check it out if you are interested in building a cross-platform Health Application by integrating it with Apple HealthKit on ios and Android Health Connect on Android.

This post only covers the Apple HealthKit integration.

Video tutorial

If you prefer a video tutorial, we covered this integration live (1:20:00 → 2:20:00) on our channel.

Prerequisites

For this project, we will work inside an Expo application.

You can either integrate it in your app, if you already have one, or you can initialize a blank expo app with npx create-expo-app@latest StepCounter -t and choose the "Blank (TypeScript)" template**.**

Everything is also compatible with bare React Native application, if you are not using Expo. Check the documentation of our packages for extra installation steps for bare React Native apps.

Let’s prepare our project

Let’s set up all the files, and the basic structure of our app, to prepare for the Health Integration.

To keep our project clean, I want to separate all the logic related to "how we get the data" from HealthKit. For that, let’s define a custom hook, that will handle all the HealthKit integration, and will simply return the data our app needs using the hook:

TYPESCRIPT
const {steps, distance, flights} = useHealthData();

For that, let’s create our custom hook inside src/hooks/useHealthData.ts that will fetch and store the health data.

TYPESCRIPT
import { useEffect, useState } from 'react';
const useHealthData = () => {
const [steps, setSteps] = useState(0);
const [flights, setFlights] = useState(0);
const [distance, setDistance] = useState(0);
// HealthKit implementation
return { steps, flights, distance };
};
export default useHealthData;

Now, import this hook where you need it (ex: in App.tsx), and use the data to render it in your UI.

TYPESCRIPT
import useHealthData from './src/hooks/useHealthData';
export default function App() {
const {steps, distance, flights} = useHealthData();
console.log(`Steps: ${steps} | Distance: ${distance}m | Flights: ${flights}`);
return (...)
}

If you are following the Health app project, you can render the values on the screen using the <Value /> component.

TYPESCRIPT
<Value label="Steps" value={steps.toString()} />
<Value label="Distance" value={`${(distance / 1000).toFixed(2)} km`} />
<Value label="Flights Climbed" value={flights.toString()} />

Also, if you have the RingProgress component, you can render the progress based on the number of steps devided by the goal (ex: 10000 steps a day).

TYPESCRIPT
<RingProgress progress={steps / 10000} />

React Native - Apple HealthKit integration

To interact with Apple HealthKit inside our React Native app, we will use the react-native-health library.

If you are installing it in a bare React Native app (no expo), make sure to follow these installation steps.

If you are using Expo, Let’s start by installing the library:

TYPESCRIPT
npx expo install react-native-health

React Native Health library contains native code. That means that when running our app inside Expo Go, the native code that we depend on from react native health will not be included.

This is not a problem. All we have to do is create a custom development client.

Create a custom dev client

Think about the custom development client as your own version of the Expo Go app that will include all the native code your app includes. This allows us to use libraries that have native code inside our Expo apps.

All we have to do is install the expo-dev-client library

TYPESCRIPT
npx expo install expo-dev-client

Then, we can build our native project and run it on a device with the command

TYPESCRIPT
npx expo run:ios

Press enter to accept the default bundle identifier, and wait for the native project to be built.

Alright, now the library is installed and configured for us to start using it.

Let’s initialize react-native-health

Let’s start by initializing the react-native-health library inside src/hooks/useHealthData.ts file.

Import the next fields from react-native-health and define the Permissions we will need later. For a list of all available permissions, check out this page.

TYPESCRIPT
import AppleHealthKit, {
HealthInputOptions,
HealthKitPermissions,
HealthUnit,
} from "react-native-health";
const { Permissions } = AppleHealthKit.Constants;
const permissions: HealthKitPermissions = {
permissions: {
read: [
Permissions.Steps,
Permissions.FlightsClimbed,
Permissions.DistanceWalkingRunning,
],
write: [],
},
};

Now, inside the useHealthData we can initialize AppleHealthKit:

TYPESCRIPT
const useHealthData = (date: Date) => {
...
const [hasPermissions, setHasPermission] = useState(false);
useEffect(() => {
AppleHealthKit.initHealthKit(permissions, (err) => {
if (err) {
console.log('Error getting permissions');
return;
}
setHasPermission(true);
});
}, []);
...
}

Initializing AppleHealthKit with the above-defined permissions will open up the Health Access permissions window. Here the users will be able to granularly allow your app access to the data it needs.

Simulator_Screenshot_-iPhone_14_Pro_Max-_2023-06-20_at_16.38.37.png

For now, make sure to allow all permissions, because this window is displayed only once. If you press "Don’t allow", you will have to manually go to the Apple Health app and enable the permissions required by your app.

Restrict HealthKit for iOS devices only

If your app will be built both for iOS and Android, we have to make sure that we interact with HealthKit only if the app runs on iOS. For the Android implementation, check this post.

Inside the src/hooks/useHealthData.tsx, before you call AppleHealthKit.initHealthKit(), check if the platform is iOS.

JAVASCRIPT
import { Platform } from 'react-native';
...
useEffect(() => {
if (Platform.OS !== 'ios') {
return;
}
AppleHealthKit.initHealthKit(...)
}, [])

Query Health data

Now that our app has the necessary permissions to query the health data, let’s do that.

When should we query the health data?

As soon as the app receives permission to do so. For that, we have a state variable called hasPermissions. So, let’s define a useEffect that will be executed when hasPermissions state changes

JAVASCRIPT
useEffect(() => {
if (!hasPermissions) {
return;
}
// Query Health data
}, [hasPermissions]);

Get steps count

To get the steps count, we have to call AppleHealthKit.getStepCount(options, callback), providing the options, and a callback function that will be called with the result.

Let’s add this call to our useEffect:

JAVASCRIPT
useEffect(() => {
if (!hasPermissions) {
return;
}
// Query Health data
const options: HealthInputOptions = {
date: new Date().toISOString(),
};
AppleHealthKit.getStepCount(options, (err, results) => {
if (err) {
console.log('Error getting the steps');
return;
}
setSteps(results.value);
});
}, [hasPermissions]);

Now, if you run this app on your physical device, you should see real data about your step count displayed on the screen.

To run the app on a physical device, connect it to your computer with a cable and then run npx expo run:ios -d and then select your device from the list.

If you are using the emulator, you can open the Health app, and manually add steps data.

Get Distance and Flights climbed

To get other data, like distance walked and flights climbed, the process is the same. Just call the necessary method, provide options describing what data you want to request, and also the callback function.

In the same useEffect, after the getStepCount, add the next 2 calls:

JAVASCRIPT
AppleHealthKit.getFlightsClimbed(options, (err, results) => {
if (err) {
console.log('Error getting the Flights Climbed:', err);
return;
}
setFlights(results.value);
});
AppleHealthKit.getDistanceWalkingRunning(options, (err, results) => {
if (err) {
console.log('Error getting the Distance:', err);
return;
}
setDistance(results.value);
});

Demo

In the end, you should see the information about the steps, distance walked and flights climbed on the screen.

Untitled.jpeg


Check other episodes from the  Health Application with React Native: Step Counter series


Vadim Savin profile picture

Vadim Savin

Hi 👋 Let me introduce myself

I started my career as a Fullstack Developer when I was 16 y.o.

In search of more freedom, I transitioned to freelancing, which quickly grew into a global software development agency 🔥

Because that was not challenging enough, I started my startup which is used by over 20k users. This experience gave another meaning to being a (notJust) developer 🚀

I am also a proud ex-Amazon SDE and Certified AWS Architect, Developer and SysOps. You are in good hands 👌