# iOS (Swift)

## SDK Installation

{% hint style="danger" %}
**RealTime streaming on iOS is only available to those registered on the** [**Apple Developer Program**](https://developer.apple.com/programs/enroll/)
{% endhint %}

{% embed url="<https://app.arcade.software/share/FYXtrn9eKX2WqnmrTmNU>" %}

#### Summary:

1. Add <https://github.com/tryterra/TerraRTiOS> as a package dependency
2. In your info.plist, add:
   1. `Privacy - Bluetooth Always Usage Description`: Justification for BLE usage (shown to the user when requesting permission)
   2. `Privacy - Motion Usage Description`: Justification for phone motion sensor usage (shown to the user when requesting permission - only add if using phone sensors for streaming)

When the app is launched for the first time, these permissions will be requested from the user.

***

## **Connection setup/management**

The SDK revolves around the `TerraRT` class, which manages Bluetooth connections and real-time data streaming.

### SDK Initialization

{% hint style="info" %}
Always initialize the `TerraRT` class to begin using the SDK.

Do so every time the app is opened or brought into the foreground.
{% endhint %}

```swift
import TerraRTiOS

let developerId = "yourDeveloperId"
let referenceId: String? = "yourReferenceId"

let terraRT = TerraRT(devId: developerId, referenceId: referenceId) { success in
    if success {
        print("TerraRT initialization successful!")
    } else {
        print("TerraRT initialization failed.")
    }
}
```

### **Initializing a Connection**

Register the [phone](/reference/streaming-api/core-concepts.md#phone) by calling [`initConnection`](/reference/streaming-api/reference/ios-swift.md#initconnection).

This connects the [phone](/reference/streaming-api/core-concepts.md#phone) to Terra, allows you to use other SDK functions, and allows it to be a [producer](/reference/streaming-api/core-concepts.md#producer) once a [wearable](/reference/streaming-api/core-concepts.md#device) is connected later on.

```swift
let token = "yourAuthToken"  // Generated from your backend

terraRT.initConnection(token: token) { success in
    if success {
        print("Connection initialized successfully!")
    } else {
        print("Failed to initialize connection.")
    }
}
```

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

### **Connecting a** [device](/reference/streaming-api/core-concepts.md#device)

iOS devices support connection via BLE or Apple Watch's WatchConnectivity protocol. For Apple Watch, refer to [the WatchOS integration guide below](#watchos-integration).

The [`startBluetoothScan`](/reference/streaming-api/reference/ios-swift.md#startbluetoothscan-with-built-in-ui) function returns a SwiftUI `TerraBLEWidget` view for device selection:

```swift
import SwiftUI
import TerraRTiOS

struct BluetoothScanView: View {
    @State private var scanWidget: TerraBLEWidget?
    @State private var connected = false

    var body: some View {
        VStack {
            if let widget = scanWidget {
                widget
            }

            if connected {
                Text("Device connected!")
                    .foregroundColor(.green)
            }

            Button("Start Bluetooth Scan") {
                scanWidget = terraRT.startBluetoothScan(type: .BLE) { success in
                    connected = success
                }
            }
        }
        .padding()
    }
}
```

***

## Streaming Real-Time Data

Once the [phone is registered](#initializing-a-connection) and you've [connected a wearable](#connecting-a-device), you can stream data from the wearable to your mobile app.

#### **Start Streaming**

Call [`startRealtime`](/reference/streaming-api/reference/ios-swift.md#startrealtime-local-only) to stream data to your app locally (without sending to Terra's server):

```swift
import TerraRTiOS

let connectionType: Connections = .BLE
let dataTypes: Set<DataTypes> = [.HEART_RATE, .STEPS]

terraRT.startRealtime(type: connectionType, dataType: dataTypes) { update in
    if let value = update.val {
        print("\(update.type ?? ""): \(value)")
    }
    if let dataArray = update.d {
        print("\(update.type ?? ""): \(dataArray)")
    }
}
```

To also send data to Terra's server, see the [Your App → Terra](/streaming-api/your-app-greater-than-terra/ios-swift.md) guide.

#### Stop streaming and disconnect

```swift
terraRT.stopRealtime(type: .BLE)
terraRT.disconnect(type: .BLE)
```

***

## WatchOS Integration

{% hint style="info" %}
To receive a data stream from an Apple Watch, the watch must be instructed to initiate a data stream to the iOS [phone](/reference/streaming-api/core-concepts.md#phone) it is paired with.

For that, you'll need to have a WatchOS companion app running on the watch, which runs [`startStream`](/reference/streaming-api/reference/ios-swift.md#startstream) or [`startExercise`](/reference/streaming-api/reference/ios-swift.md#startexercise)
{% endhint %}

#### Setup

1. Create a WatchOS target within your iOS project:

   File -> New -> Target -> Watch App for iOS App.
2. Enable **HealthKit** and **Background Modes** for the WatchOS app, and add the following privacy keys to your `Info.plist`:
   1. `Privacy - Health Share Usage Description`
   2. `Privacy - Health Update Usage Description`
   3. `Privacy - Health Records Usage Description`

### Start Streaming from WatchOS

{% hint style="info" %}
Outside of a workout session, data recording frequency may be reduced. In order to capture data at the highest possible frequency, you'll want to [start a workout session](#streaming-workouts-from-watchos)
{% endhint %}

On the iOS app, listen for updates from the WatchOS app using `startRealtime` with `.WATCH_OS`:

{% tabs %}
{% tab title="WatchOS app" %}

```swift
import WatchKit
import TerraRTiOS

class InterfaceController: WKInterfaceController {
    var terra: Terra?

    override func awake(withContext context: Any?) {
        super.awake(withContext: context)

        do {
            terra = try Terra()
            terra?.connect()
            print("Terra SDK initialized on watchOS")
            startStreamingData()
        } catch {
            print("Failed to initialize Terra SDK: \(error)")
        }
    }

    func startStreamingData() {
        let dataTypes: Set<ReadTypes> = [.HEART_RATE, .STEPS]
        terra?.startStream(forDataTypes: dataTypes) { success, error in
            if success {
                print("Streaming started")
            } else {
                print("Failed: \(error?.localizedDescription ?? "Unknown error")")
            }
        }
    }

    func stopStreamingData() {
        terra?.stopStream()
    }
}
```

{% endtab %}

{% tab title="iOS app" %}

```swift
import TerraRTiOS
import UIKit

class ViewController: UIViewController {
    var terraRT: TerraRT?

    override func viewDidLoad() {
        super.viewDidLoad()

        terraRT = TerraRT(devId: "your-dev-id", referenceId: "your-reference-id") { success in
            if success {
                print("Terra SDK initialized")
                self.setupWatchOSConnection()
            }
        }
    }

    func setupWatchOSConnection() {
        try? terraRT?.connectWithWatchOS()
        listenForDataFromWatch()
    }

    func listenForDataFromWatch() {
        let dataTypes: Set<DataTypes> = [.HEART_RATE, .STEPS]
        terraRT?.startRealtime(type: .WATCH_OS, dataType: dataTypes) { update in
            print("Watch update: \(update.type ?? ""): \(update.val ?? 0)")
        }
    }

    func stopRealtimeData() {
        terraRT?.stopRealtime(type: .WATCH_OS)
    }

    func disconnectWatchOS() {
        terraRT?.disconnect(type: .WATCH_OS)
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        stopRealtimeData()
        disconnectWatchOS()
    }
}
```

{% endtab %}
{% endtabs %}

***

### Streaming Workouts from WatchOS

The Apple Watch app can also manage a workout session, during which recording frequency is enhanced.

From the Watch: [`startExercise`](/reference/streaming-api/reference/ios-swift.md#startexercise), [`stopExercise`](/reference/streaming-api/reference/ios-swift.md#stopexercise), [`pauseExercise`](/reference/streaming-api/reference/ios-swift.md#pauseexercise), [`resumeExercise`](/reference/streaming-api/reference/ios-swift.md#resumeexercise)

From the iOS app: [`pauseWatchOSWorkout`](/reference/streaming-api/reference/ios-swift.md#pausewatchosworkout--resumewatchosworkout--stopwatchosworkout), [`resumeWatchOSWorkout`](/reference/streaming-api/reference/ios-swift.md#pausewatchosworkout--resumewatchosworkout--stopwatchosworkout), [`stopWatchOSWorkout`](/reference/streaming-api/reference/ios-swift.md#pausewatchosworkout--resumewatchosworkout--stopwatchosworkout)

```swift
import WatchKit
import TerraRTiOS

class InterfaceController: WKInterfaceController {
    var terra: Terra?

    override func awake(withContext context: Any?) {
        super.awake(withContext: context)

        do {
            terra = try Terra()
            terra?.connect()
        } catch {
            print("Failed to initialize: \(error)")
        }
    }

    @IBAction func startExerciseTapped() {
        terra?.startExercise(forType: .RUNNING) { success, error in
            if success {
                print("Running exercise started")
            } else {
                print("Failed: \(error?.localizedDescription ?? "Unknown")")
            }
        }
    }

    @IBAction func pauseExerciseTapped() {
        terra?.pauseExercise()
    }

    @IBAction func resumeExerciseTapped() {
        terra?.resumeExercise()
    }

    @IBAction func stopExerciseTapped() {
        terra?.stopExercise { success, error in
            if success {
                print("Exercise stopped")
            } else {
                print("Failed: \(error?.localizedDescription ?? "Unknown")")
            }
        }
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.tryterra.co/streaming-api/connect-wearable-to-sdk/ios-swift.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
