# Flutter

## Prerequisites

1. Add [`terra_flutter_rt`](https://pub.dev/packages/terra_flutter_rt) to your `pubspec.yaml`:

```yaml
dependencies:
  terra_flutter_rt: ^X.X.X
```

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 `Connection.apple`)
3. **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 %}

```dart
import 'package:terra_flutter_rt/terra_flutter_rt.dart';
import 'package:terra_flutter_rt/types.dart';

await TerraFlutterRt.init('YOUR_DEV_ID', 'YOUR_REFERENCE_ID');
```

## Initializing a Connection

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

```dart
final token = 'yourAuthToken'; // Generated from your backend

await TerraFlutterRt.initConnection(token);
```

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

Two approaches depending on your needs:

### Option 1: Built-in scan widget

On Android, this shows a native device picker. On iOS, use the `iOSScanView` widget.

```dart
import 'package:terra_flutter_rt/ios_controller.dart';

// Android: shows native picker
await TerraFlutterRt.startDeviceScan(
  Connection.ble,
  connectionCallback: (connected) {
    print('Device connected: $connected');
  },
);

// iOS: embed the native BLE scanner view in your widget tree
// (renders empty Container on Android)
iOSScanView()
```

### Option 2: Programmatic scan with callback

Discover devices one by one and connect manually:

```dart
await TerraFlutterRt.startDeviceScanToCallback(
  Connection.ble,
  (Device device) async {
    print('Found: ${device.deviceName}');
    // Connect to this device
    await TerraFlutterRt.connectDevice(device);
  },
  connectionCallback: (connected) {
    print('Connection status: $connected');
  },
);
```

## Real-Time Data Streaming

Once a device is connected, start streaming data to your app via a callback:

```dart
void onUpdate(Update data) {
  print('${data.type.datatypeString}: ${data.val}');
}

await TerraFlutterRt.startRealtimeToApp(
  Connection.ble,
  [DataType.heartRate, DataType.steps],
  onUpdate,
);
```

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

## Stop & Disconnect

```dart
await TerraFlutterRt.stopRealtime(Connection.ble);
await TerraFlutterRt.disconnect(Connection.ble);
```

## WatchOS Integration

To stream data from an Apple Watch:

```dart
// Connect to paired Apple Watch (iOS only — returns false on Android)
final connected = await TerraFlutterRt.connectWatchOS();

if (connected) {
  // Start receiving watch data
  await TerraFlutterRt.startRealtimeToApp(
    Connection.watchOs,
    [DataType.heartRate],
    onUpdate,
  );
}
```

{% 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 %}

You can also control workout sessions on the watch from your Flutter app:

```dart
await TerraFlutterRt.resumeWatchOSWorkout();
await TerraFlutterRt.pauseWatchOSWorkout();
await TerraFlutterRt.stopWatchOSWorkout();
```
