# React Native

## 1. Install and Setup the Terra React Native Plugin

1. Install the [`terra-react` package](https://www.npmjs.com/package/terra-react) using npm (`npm install terra-react`).
2. Complete the following iOS and/or Android setup.

{% tabs %}
{% tab title="iOS Setup" %}

1. In your terminal, cd to your `/ios` folder, and run `pod install` to install all the dependencies.
2. **Add Capabilities:**
   1. Healthkit > Healthkit Background Delivery
   2. Background Modes > Background processing
   3. Background modes > Background fetch
3. **Add the following keys to your info.plist:**

#### **Method 1: Using XCode**

* 1\) Go to the `/ios` directory of your project, open the `.xcworkspace` in XCode.
* 2\) Go to ***info.plist,*** and add the following keys and values:

<table><thead><tr><th width="370.9501953125">Key</th><th>Value</th></tr></thead><tbody><tr><td>Privacy - Health Share Usage Description</td><td><p>Description of how Health data is used</p><p><strong>(Min 3 words)</strong></p></td></tr><tr><td>Privacy - Health Records Usage Description</td><td><p>Description of how Health data is used</p><p><strong>(Min 3 words)</strong></p></td></tr><tr><td>Privacy - Health Update Usage Description</td><td><p>Description of how Health data is used</p><p><strong>(Min 3 words)</strong></p></td></tr><tr><td>Permitted background task scheduler</td><td><code>co.tryterra.data.post.request</code></td></tr></tbody></table>

#### **Method 2: Directly editing info.plist**

* 1\) In your app project, go to your `/ios` folder
* 2\) Go to ***info.plist,*** and add the following tags:

{% code title="info.plist" lineNumbers="true" %}

```xml
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
  <string>co.tryterra.data.post.request</string>
</array>
  
<key>NSHealthClinicalHealthRecordsShareUsageDescription</key>
<string>Using TerraiOS to gather health data</string>

<key>NSHealthShareUsageDescription</key>
<string>Using TerraiOS as a mean of getting Health Data</string>

<key>NSHealthUpdateUsageDescription</key>
<string>Allow writing data to health kit</string>
```

{% endcode %}
{% endtab %}

{% tab title="Android Setup" %}

## Access Samsung Health

Terra has a privileged partnership with Samsung that gives you direct access to the Samsung Health SDK — no Health Connect intermediary needed. This is the recommended route for Samsung devices.

**1. Apply for Samsung Health access**

Submit your application through the [Samsung Health partnership portal](https://developer.samsung.com/SHealth/business-partner/m48wvqi1mt9w2w4c).

{% hint style="info" %}
While waiting for approval, you can start development immediately using the **Health Connect** route below. Switching to Samsung direct later is just a version bump — no code changes needed.
{% endhint %}

**2. Install the Samsung-tagged SDK**

After approval, install the Samsung-tagged version of the Terra SDK:

* **React Native:** `npm install terra-react@<samsung-version>` — find Samsung-tagged versions on the [npm versions page](https://www.npmjs.com/package/terra-react?activeTab=versions)
* **Flutter:** Use the Samsung-tagged version of `terra_flutter_bridge` — find versions on [pub.dev](https://pub.dev/packages/terra_flutter_bridge/versions)

**3. Add ProGuard rule (required for release builds)**

In your `android/app/proguard-rules.pro`, add:

```proguard
-keep class com.samsung.android.** { *; }
```

Without this, R8 minification will strip Samsung SDK classes and cause runtime crashes in production.

**4. Requirements**

* **Samsung Health** app must be installed on the device
* **Android 28 (minSDK 28)** and above
* Enable **Developer Mode** in Samsung Health on test devices (Settings > About Samsung Health > tap version number repeatedly)
* No additional manifest or Gradle changes needed — the Terra SDK handles everything

***

## Access Health Connect

#### **1. In the Health Connect app**

Give all permissions between the apps you wish to read from (e.g. **Samsung Health, Google Fit, etc**) & Health Connect.

#### **2. Add Health Connect capability to your app**

In your app project, go to the `/android` folder.

Include the permission tags under the Activity you wish to link the user to when they click the **privacy policy** link in the Health Connect permission screen. Here are the steps:

1. Go to your Android App's `AndroidManifest.xml`
2. Go to your **Privacy Policy** <mark style="color:purple;">`<activity>`</mark> and include the following tags under this <mark style="color:purple;">`<activity>`</mark> tag.

"Your Android manifest needs to have an Activity that displays your app's **privacy policy**, which is your app's rationale of the requested permissions, describing how the user's data is used and handled." — Health Connect.

<pre class="language-xml" data-title="AndroidManifest.xml" data-line-numbers><code class="lang-xml"><strong>&#x3C;intent-filter>
</strong>  &#x3C;action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE"/>
 &#x3C;/intent-filter>
  
&#x3C;intent-filter>
   &#x3C;action android:name="android.intent.action.VIEW_PERMISSION_USAGE"/>
  &#x3C;category android:name="android.intent.category.HEALTH_PERMISSIONS"/>
&#x3C;/intent-filter>
</code></pre>

{% hint style="warning" %}

### Apply for Health Connect access

Before going **live** (release), you will need to apply for permissions to access the Health Connect API with Google.

1. Use this [application form](https://developer.android.com/health-and-fitness/guides/health-connect/publish/declare-access#explain-use-data-types).
2. For each permission which you are ***not*** using, please add the following lines to your AndroidManifest.xml

{% code title="AndroidManifest.xml" overflow="wrap" %}

```xml
<uses-permission android:name="android.permission.health.READ_HEART_RATE" tools:node="remove"/>
```

{% endcode %}

with `android.permission.health.XXX` for each permission you aren't using
{% endhint %}
{% endtab %}
{% endtabs %}

***

## 2. Initialize the SDK

The first step is to **initialize the Terra SDK.**

The initialization only needs to be done **once** **on** **app** **start**, (e.g. in your `app.tsx` or an equivalent file), and ideally, **and** **everytime** the app is brought into the foreground. This ensures that the SDK is properly set up and ready to be used.

{% hint style="warning" %}
The SDK should be initialized every time your app is opened.

This is a necessary prerequisite for other SDK functions to run as expected
{% endhint %}

#### **Step 1: Import the Terra Plugin**

In your project, you should now be able to import function from the Terra Plugin. Here is an example:

{% code title="app.tsx" lineNumbers="true" %}

```tsx
import { initTerra } from 'terra-react';
```

{% endcode %}

#### **Step 2: Initialize the Terra SDK**

In order to interact with the SDK, you need to call `initTerra` first.

Call `initTerra()` with the following arguments:

* `devId`: Your **Developer ID** provided by Terra.
* `referenceId`: An **ID of your choice** to identify your app user.

Find more details in the SDK Reference: [Terra manager initialization function](https://github.com/tryterra/gitbook-docs/blob/master/broken/pages/5ndyWIp3sQqelSRzXmZM/README.md#terra.instance)

{% code title="app.tsx" lineNumbers="true" %}

```typescript
import React, { useEffect, useState } from 'react';
import { View, Text } from 'react-native';
import { initTerra } from 'terra-react';

const App = () => {
  const [initialized, setInitialized] = useState<boolean>(false);
  
  useEffect(() => {
    const initializeTerra = async () => {
      try {
        const devID = 'YOUR_DEV_ID';
        const referenceId = 'YOUR_REFERENCE_ID';
        
        const successMessage = await initTerra(devID, referenceId);
        if (successMessage.error !== null) {
          throw new Error("Terra manager failed to initialise");
        }
        // Can proceed with other Terra plugin methods
        setInitialized(true);
      } catch (error) {
        console.error('Failed to initialize Terra:', error);
      }
    };

    initializeTerra();
  }, []);

  return (
    <View>
      <Text>Welcome to the App using Terra</Text>
    </View>
  );
};

export default App;
```

{% endcode %}

(**N.B** This call is asynchronous, please ensure this is complete before using other SDK functions).

***

## 3. Connect a User

Once Terra is initialized, you can create a connection by calling the function `initConnection()` to trigger a permission screen pop up.

#### 1. Call [`initConnection()`](https://app.gitbook.com/s/eJJpVMsUARUJq9lYmL6t/health-and-fitness-api/sdk-references/ios-swift#initconnection)

From `terra-react`, import `initConnection` and call the function with the following arguments:

* `type`: Specify the connection type — `Connections.APPLE_HEALTH`, `Connections.SAMSUNG`, or `Connections.HEALTH_CONNECT`
* `token`: A **one-time authentication token** generated from your backend server. This ensures secure communication between your app and the Terra servers.
* `schedulerOn`:
  * **iOS**: This parameter has no effect. Background delivery is controlled by calling `Terra.setUpBackgroundDelivery()` in your AppDelegate — see [Step 5](#id-5.-background-delivery-setup-ios-only) below.
  * **Android**: To allow Terra to make scheduled requests whenever the app is in the foreground.
* `customPermissions`: A **set of permissions** that define what data you want to request (e.g., heart rate, steps). If empty, it defaults to all available permissions.

{% tabs %}
{% tab title="Apple Health (iOS)" %}
{% code title="app.tsx" lineNumbers="true" %}

```tsx
import { Connections, initConnection } from 'terra-react';

const initializeConnection = async () => {
  try {
    const token = 'example_token';

    const successMessage = await initConnection(
      Connections.APPLE_HEALTH,
      token,
      true,   // schedulerOn — no effect on iOS, see setUpBackgroundDelivery() below
      [],     // customPermissions — empty defaults to all
    );
    if (successMessage.error !== null) {
      throw new Error("Error initialising a connection");
    }
  } catch (error) {
    console.error('Connection failed:', error);
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="Samsung Health (Android)" %}
{% code title="app.tsx" lineNumbers="true" %}

```tsx
import { Connections, initConnection } from 'terra-react';

const initializeConnection = async () => {
  try {
    const token = 'example_token';

    const successMessage = await initConnection(
      Connections.SAMSUNG,
      token,
      true,   // schedulerOn — enables foreground scheduler
      [],     // customPermissions — empty defaults to all
    );
    if (successMessage.error !== null) {
      throw new Error("Error initialising a connection");
    }
  } catch (error) {
    console.error('Connection failed:', error);
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="Health Connect (Android)" %}
{% code title="app.tsx" lineNumbers="true" %}

```tsx
import { Connections, initConnection } from 'terra-react';

const initializeConnection = async () => {
  try {
    const token = 'example_token';

    const successMessage = await initConnection(
      Connections.HEALTH_CONNECT,
      token,
      true,   // schedulerOn — enables foreground scheduler
      [],     // customPermissions — empty defaults to all
    );
    if (successMessage.error !== null) {
      throw new Error("Error initialising a connection");
    }
  } catch (error) {
    console.error('Connection failed:', error);
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}

### Apple Health Kit Permission Screen: `initConnection()`

**Apple Health** only shows the permission popup **once**, so calling `initConnection()` multiple times won’t trigger the popup again unless:

a. you call initConnection with **an expanded set of** `customPermissions`

b. the **app is deleted & reinstalled.**
{% endhint %}

{% hint style="info" %}

### **`initConnection` only needs to be called a single time.**

**Health Connect** prohibits the permission popup to appear more than once for any given permission, so calling `initConnection` more than once will result in no action at all

The only case where it would re-appear is if:

* you call initConnection with **an expanded set of `customPermissions`**
* the **app is deleted & reinstalled.**
* **A permission that was not granted to use on release by Google has been requested by the app**
  {% endhint %}

{% hint style="info" %}

### **Apple Health Kit Permission Screen: WebViews** 🚧

* Apple HealthKit implements the permissions popup as a **WebView.**
* If your app is also based on a **WebView**, you will need to interrupt your **WebView**, call `initConnection`, then upon completion re-open your **WebView.**
  {% endhint %}

#### 2. Generate an Auth Token

To be able to call the `initConnection()` method, you need to pass a `token` as an argument.

This `token` is a **single-use token** created to ensure the authentication endpoint for creating a connection (and connecting the SDK to Terra's servers) does not get abused.

Generate the token with this endpoint <mark style="color:orange;">`POST`</mark>`https://api.tryterra.co/v2/auth/generateAuthToken` . Make sure to call it with your Terra `x-api-key` and `dev-id` in the headers from **your backend server.** After you generate the token, provide the response to your client side using your own logic.&#x20;

Go to the **SDK Reference** to find more details on the [Generate the Mobile SDK Auth Token **API Endpoint**](https://app.gitbook.com/s/eJJpVMsUARUJq9lYmL6t/health-and-fitness-api/sdk-references)**.**

{% hint style="warning" %}

* During the development phase, it it acceptable to place this call on the **client** side, exposing your API key in your mobile app.
* For a production implementation, **DO NOT** expose your API key this way, and make sure to **only** make this call from your **backend.**
  {% endhint %}

***

## 4. Validate the Connection

To ensure a connection is still valid on the client side, use the [`getUserId`](https://app.gitbook.com/s/eJJpVMsUARUJq9lYmL6t/health-and-fitness-api/sdk-references/react-native#getuserid) method. This function returns the `user_id` for the connection or null if none exists.

{% hint style="info" %}

## Always validate the connection before using the SDK

Check if a `user_id` exists right after **initializing the Terra SDK** to see if the connection still exists.

1. **Check if the User is Connected**&#x20;
   1. If the function returns a user ID, the user is still connected, 🎉 keep vibing along!
   2. If the function returns <mark style="color:red;">`nil`</mark>, the user needs to reconnect.
2. **Re-connect if Needed**\
   If the connection is lost, you can call `terra.initConnection()` again to re-establish the connection.&#x20;

Calling `terra.initConnection()` when the user is already connected or just needs a reconnection will not trigger any permission screens from Apple Health, and the user flow will remain uninterrupted. The connection will be re-established if necessary.
{% endhint %}

***

## 5. Background Delivery setup (iOS only)

For Apple apps, you can enable background delivery settings to allow data to be synced even when your app is not brought to the foreground.

{% tabs %}
{% tab title="Apple Health" %}

1. Go to your `/ios` folder in the **React** **Native** **project**
2. Call the function `setUpBackgroundDelivery` in your AppDelegate's `didFinishLaunchingWithOptions` function

This will ensure you get updates for the user's Apple Health data automatically sent to your destination.

<pre class="language-objectivec" data-title="AppDelegate.m" data-line-numbers><code class="lang-objectivec">#import "AppDelegate.h"

#import &#x3C;React/RCTBundleURLProvider.h>
#import &#x3C;TerraiOS/TerraiOS-Swift.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  self.moduleName = @"AwesomeProject";
  // You can add your custom initial props in the dictionary below.
  // They will be passed down to the ViewController used by React Native.
  self.initialProps = @{};
  [Terra setUpBackgroundDelivery];
  return [super application:application didFinishLaunchingWithOptions:launchOptions];
<strong>}
</strong></code></pre>

{% hint style="success" %}

## iOS Background Delivery Behaviour:

* Data will still be triggered if the **app** **is** **killed** (with much lower frequency)
* Data will only be triggered when **phone** **is** **unlocked**
* Data can only be triggered where there is **network connection**
* Only enabled **Data** **Types** from [the Terra Dashboard](https://dashboard.tryterra.co) will be triggered by background delivery.
* If you are using **CustomPermissions,** please ensure the following permissions are enabled for Background Delivery to work correctly:
  * For **Daily: CustomPermissions.STEPS**
  * For **Sleep: CustomPermissions.SLEEP\_ANALYSIS**
  * For **Body: CustomPermissions.BMI, CustomPermissions.HEART\_RATE**
  * For **Activity: CustomPermissions.WORKOUT\_TYPE**
  * For **Nutrition: CustomPermissions.NUTRITION\_CALORIES**
    {% endhint %}
    {% endtab %}
    {% endtabs %}

***

## 6. Filtering by source app (iOS, optional)

Apple Health aggregates data from every health app on the user's device. If a user has both a cloud-based Terra connection (e.g. WHOOP, Garmin) and the same provider's companion app syncing into Apple Health, you'll receive duplicate data — once from the cloud API and once from the Apple Health SDK.

Use `setIgnoredSources` to tell the SDK to skip data from specific apps in HealthKit. Call this **once on every app launch**, after `initTerra()` completes. It is not persisted across app restarts. On Android, this function is a no-op.

```typescript
import { setIgnoredSources } from 'terra-react';

// After initTerra() completes:
setIgnoredSources(["com.whoop.app", "com.garmin.connect.mobile"]);
```

Common bundle identifiers:

| App            | Bundle identifier           |
| -------------- | --------------------------- |
| WHOOP          | `com.whoop.app`             |
| Garmin Connect | `com.garmin.connect.mobile` |
| Fitbit         | `com.fitbit.FitbitMobile`   |
| Oura           | `com.ouraring.oura`         |

{% hint style="info" %}
To find a specific app's bundle identifier, have the user check **Settings → Health → Data Access & Devices** on their iPhone.
{% endhint %}

***

Now you'll start receiving health data events **automatically** to your Data Destination (e.g. webhook)!

You can also request historical data to backfill, to verify that data exists, or as a fallback.

Check out the [React Native SDK reference](https://docs.tryterra.co/health-and-fitness-api/mobile-only-sources/react-native) for details about all the functions in the SDK.

***

## Disconnecting a user

In order to disconnect an SDK user, you may use [the same endpoint as for Web API-based integrations](https://app.gitbook.com/s/eJJpVMsUARUJq9lYmL6t/health-and-fitness-api/readme#auth-deauthenticateuser), called from your backend.

***

## Historical Data retrieval

You can request for historical data using one of the [data retrieval functions.](https://app.gitbook.com/s/eJJpVMsUARUJq9lYmL6t/health-and-fitness-api/sdk-references/react-native#data-retrieval)

You may set `toWebhook` to false if you wish for the callback function to return the data payload on the client side.

{% code lineNumbers="true" %}

```tsx
import { Connections, getDaily } from 'terra-react';

const requestData = async () => {
  try {
    const connection = Connections.APPLE_HEALTH;
    const endDate = new Date();
    const startDate = new Date(endDate);
    startDate.setDate(startDate.getDate() - 1);

    const dataMessage = await getDaily(connection, startDate, endDate, false);
  
    if (dataMessage.error !== null) {
      throw new Error("Failed to get data for user");
    }
    if (dataMessage.success) {
      // process data here
      console.log('Daily data:', dataMessage.data);
    }
  
  } catch (error) {
    // Handle failure (network error, etc.)
    console.error('Failed to get daily data:', error);
  }
}
```

{% endcode %}

Check out the [React Native SDK reference](https://app.gitbook.com/s/eJJpVMsUARUJq9lYmL6t/health-and-fitness-api/sdk-references/react-native) for details about all the functions in the SDK

***

## Writing data

You may write data into Apple Health (Health Connect not yet supported) through one of the helper functions in the SDK

* [postActivity](https://app.gitbook.com/s/eJJpVMsUARUJq9lYmL6t/health-and-fitness-api/sdk-references/react-native)

{% tabs %}
{% tab title="postActivity" %}
{% hint style="warning" %}
`device_data` must be passed in for postActivity to succeed.
{% endhint %}

{% code lineNumbers="true" %}

```typescript
import { Activity, postActivity, Connections } from 'terra-react';

const postActivityToAppleHealth = async () => {
  const activityPayload: Activity = {
    metadata: {
      name: 'Morning Run',
      start_time: '2024-11-01T07:30:00.000000+00:00',
      end_time: '2024-11-01T08:30:00.000000+00:00',
      type: 8, // RUNNING — see ActivityType enum in terra-react for all values
    },
    device_data: {
      name: 'Terra',
    },
    distance_data: {
      summary: { distance_meters: 5000 },
    },
    calories_data: {
      total_burned_calories: 400,
    },
  };

  const resp = await postActivity(Connections.APPLE_HEALTH, activityPayload);
  if (resp.error !== null) {
    throw new Error('Failed to post activity to Apple Health');
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="warning" %}

## Data Sources requiring the Terra **Mobile-SDK**

The **Mobile SDK** is <mark style="color:red;">**ONLY**</mark> used to connect to the following integrations:

1. <img src="https://464213908-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FVGMJVuZnZyOtvV4b53cY%2Fuploads%2FDH2JWDtg632mUQlEdrLH%2F4p3k173m8ihe71872bi9r0292q-0af5626e815091005bacb793985c1870.png?alt=media&#x26;token=062c917e-02fe-4029-9809-fc881cf09de3" alt="" data-size="line">**Apple Health -** iOS
2. <img src="https://464213908-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FVGMJVuZnZyOtvV4b53cY%2Fuploads%2F0lTv9KpldVVjBdg3JJQs%2Fimgbin_samsung-galaxy-samsung-health-samsung-electronics-android-png.png?alt=media&#x26;token=b58f3118-a2e1-4b09-9d30-4f862253adb6" alt="" data-size="line"> **Samsung Health -** Android
3. <img src="https://464213908-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FVGMJVuZnZyOtvV4b53cY%2Fuploads%2FmotL0wnZKiEWOKt46zOU%2Fvecteezy_google-fit-icon-logo-symbol_22484515.png?alt=media&#x26;token=a2d0ae73-5116-49fd-8ce1-0f7b5e6f716b" alt="" data-size="line"> **Google Fit & Health Connect**- Android.&#x20;

Note: the [Health & Fitness API](https://docs.tryterra.co/health-and-fitness-api) is the preferred way to connect to Google Fit due to better reliability.

For **ALL** other integrations, please refer to Integration Setup the [Health & Fitness API](https://docs.tryterra.co/health-and-fitness-api).
{% endhint %}
