# React Native

## Prerequisites

1. Install the [`react-native-terra-rt-react`](https://www.npmjs.com/package/react-native-terra-rt-react) package:

```bash
npm install react-native-terra-rt-react
```

2. **iOS:** In your `Info.plist`, add:
   * `Privacy - Bluetooth Always Usage Description`: Justification for BLE usage
   * `Privacy - Motion Usage Description`: Justification for motion sensor usage (required if streaming accelerometer, gyroscope, or step data from the phone's built-in sensors via `Connections.APPLE`)
3. **iOS:** Run `pod install` in your `/ios` directory.
4. **Android:** Permissions are requested automatically by the SDK on initialization.

## SDK Initialization

{% hint style="info" %}
Initialize the SDK every time the app is opened or brought into the foreground.
{% endhint %}

Set up event emitters for receiving data, then initialize:

```tsx
import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
import {
  initTerra, initConnection, startDeviceScan, startRealtime,
  stopRealtime, disconnect, getUserId,
  Connections, DataTypes,
} from 'react-native-terra-rt-react';
import type { Update, Device, SuccessMessage } from 'react-native-terra-rt-react';

// Set up event listeners (do this once, e.g. in useEffect)
const updateEmitter = new NativeEventEmitter(NativeModules.UpdateHandler);
updateEmitter.addListener('Update', (update: Update) => {
  console.log(`${update.type}: ${update.val}`);
});

const deviceEmitter = new NativeEventEmitter(NativeModules.DeviceHandler);
deviceEmitter.addListener('Device', (device: Device) => {
  console.log(`Found device: ${device.name}`);
});

const connectionEmitter = new NativeEventEmitter(NativeModules.ConnectionHandler);
connectionEmitter.addListener('ConnectionUpdate', (connected: boolean) => {
  console.log(`Websocket connected: ${connected}`);
});

// Initialize the SDK
const result = await initTerra('YOUR_DEV_ID', 'YOUR_REFERENCE_ID');
if (!result.success) {
  console.error('Failed to initialize:', result.error);
}
```

## Initializing a Connection

Register the device with Terra using an authentication token generated **from your backend**:

```tsx
const token = 'yourAuthToken'; // Generated from your backend

const connResult = await initConnection(token);
if (connResult.success) {
  console.log('Connection initialized!');
}
```

To generate the **token**, make the below call **from your backend**:

{% openapi src="<https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/v5.yml>" path="/auth/generateAuthToken" method="post" %}
<https://raw.githubusercontent.com/tryterra/openapi/refs/heads/master/v5.yml>
{% endopenapi %}

## Device Scanning

BLE device scanning works differently on iOS and Android:

{% tabs %}
{% tab title="Android" %}
On Android, use `startDeviceScan` which shows a built-in device picker:

```tsx
const scanResult = await startDeviceScan(Connections.BLE);
if (scanResult.success) {
  console.log('Device connected!');
}
```

{% endtab %}

{% tab title="iOS" %}
On iOS, `startDeviceScan` is not supported. Instead, use the `BLWidget` native view component:

```tsx
import { requireNativeComponent } from 'react-native';

const BLWidget = requireNativeComponent('BLWidget');

// In your JSX:
<BLWidget
  style={{ flex: 1 }}
  withCache={false}
  onSuccessfulConnection={(event) => {
    console.log('Connected:', event.nativeEvent.success);
  }}
/>
```

Render this component when you want to show the BLE scanner. It displays a list of discovered devices and handles connection automatically.
{% endtab %}
{% endtabs %}

**Platform-conditional pattern:**

```tsx
const startScanning = () => {
  if (Platform.OS === 'android') {
    startDeviceScan(Connections.BLE).then((result) => {
      console.log('Connected:', result.success);
    });
  } else {
    // Show BLWidget in your UI (see iOS tab above)
  }
};
```

## Real-Time Data Streaming

Once a device is connected, start streaming data. Updates arrive via the `Update` event emitter you set up earlier.

```tsx
const dataTypes = [DataTypes.HEART_RATE, DataTypes.STEPS];

// Start streaming locally (no server)
await startRealtime(Connections.BLE, dataTypes);
```

To also stream to Terra's server, see [Your App → Terra](https://docs.tryterra.co/streaming-api/your-app-greater-than-terra/react-native).

## Stop & Disconnect

```tsx
await stopRealtime(Connections.BLE);
await disconnect(Connections.BLE);
```

## WatchOS Integration

To stream data from an Apple Watch, call `connectWithWatchOS()` on the iOS companion app side, then start streaming with `Connections.WATCH_OS`:

```tsx
import { connectWithWatchOS } from 'react-native-terra-rt-react';

// Connect to paired Apple Watch (iOS only — rejects on Android)
await connectWithWatchOS();

// Start receiving watch data
await startRealtime(Connections.WATCH_OS, [DataTypes.HEART_RATE]);
```

{% hint style="info" %}
The watchOS app itself must be written in native Swift using the `Terra` class from the `TerraRTiOS` framework. See the [iOS WatchOS guide](https://docs.tryterra.co/streaming-api/ios-swift#watchos-integration) for the watch-side setup.
{% endhint %}
