iOS (Swift)
The iOS SDK allows you to seamlessly send data from iOS to your backend or to your app directly!
Overview
This guide will walk you through the necessary steps to integrate the Terra Mobile SDK with Apple Health in your iOS app. It covers everything from SDK initialization, user connection, permission handling, and background data updates.
The TerraiOS
SDK supports the following integrations:
Apple Health
1. Install the SDK
Add
https://github.com/tryterra/TerraiOS
as a package dependency to your Xcode project.Add Capabilities:
Healthkit > Healthkit Background Delivery
Background Modes > Background processing
Background modes > Background fetch
In your info.plist, add the following:
Privacy - Health Share Usage Description
Description of how Health data is used
(Min 3 words)
Privacy - Health Records Usage Description
Description of how Health data is used
(Min 3 words)
Privacy - Health Update Usage Description
Description of how Health data is used
(Min 3 words)
Permitted background task scheduler
co.tryterra.data.post.request
2. Initialize the SDK
The first step is to initialize the Terra SDK. This is done by creating a TerraManager
instance which allows you to interact with the Terra SDK.
The initialization only needs to be done once on app start, (e.g. in your ContentView.swift
or an equivalent file), and ideally, whenever the app is brought into the foreground. This ensures that the SDK is properly set up and ready to be used.
Step 1: Import TerraiOS
In your Xcode project, you should now be able to import Terra SDK
import TerraiOS
Step 2: Get a TerraManager
Instance
TerraManager
InstanceIn order to interact with the SDK, you need a TerraManager
instance.
Call Terra.instance()
with the following arguments:
devId
: Your Developer ID provided by Terra.referenceId
: An ID of your choice to identify your app user.completion
: Callback with aTerraManager
or an instanceTerraError
Find more details in the SDK Reference: Terra manager initialization function
import TerraiOS
var terra: TerraManager
Terra.instance(devId: "<YOUR_DEV_ID>", referenceId: "<REFERENCE_ID>", completion: { manager, error in
guard error == nil else {
fatalError("🤯: \(error?.localizedDescription)")
}
// TerraManager instance to access the SDK functions
terra = manager
})
The TerraManager
instance is thereafter ready to be used to call SDK functions!
(N.B This call is asynchronous, please ensure this is complete before using the manager).
3. Connect an Apple Health user
Once you’ve initialized the SDK, you can connect the Apple Health user. This is done by calling the initConnection()
method provided by the TerraManager
instance that you created above.
1. Call initConnection()
initConnection()
This method triggers the Apple Health permission popup and establishes the connection.
From TerraManager
, call initConnection()
with the following arguments:
type
: Specify the connection type as.APPLE_HEALTH
to connect the Apple Health account.token
: A one-time authentication token generated from your backend server using the /auth/generateAuthToken endpoint. This ensures secure communication between your app and the Terra servers.customReadTypes
: A set of permissions that define what data you want to request from Apple Health (e.g., heart rate, steps). If empty, it defaults to all available permissions.schedulerOn
: Defaults the Background Delivery option to true. This will make Terra send new data from the provider to your data destination (e.g. webhook) automatically.
To learn more about these parameters and their different options, check the iOS SDK Reference.
// Prepare the arguments
let token = "<AUTH_TOKEN>" // replace with the token generated from your backend with Terra
let customPermissions: Set<CustomPermissions> = [] // customize permissions if needed
let schedulerOn = true // enables background delivery
// Start a connection to Apple Health
terra.initConnection(
type: .APPLE_HEALTH,
token: token,
customReadTypes: customPermissions,
schedulerOn: schedulerOn
) { success, error in
guard error == nil && !success else {
// Handle error correctly
fatalError("🤯: \(error?.localizedDescription)")
}
}
After a successful call of initConnection()
with a valid token, an Apple Permission screen will pop up!
Apple Health Kit Permission Screen: initConnection()
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.
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.
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 POST
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.
Go to the SDK Reference to find more details on the Generate the Mobile SDK Auth Token API Endpoint.
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.
4. Validate the Connection
To ensure a connection is still valid on the client side, make sure to use the getUserid()
from TerraManager
every time you reinitialize the SDK. This function is synchronous and returns a user_id
right away if a user is connected or nil if none exists.
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.
Check if the User is Connected
If the function returns a user ID, the user is still connected, 🎉 keep vibing along!
If the function returns
nil
, the user needs to reconnect.
Re-connect if Needed If the connection is lost, you can call
terra.initConnection()
again to re-establish the connection.
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.
5. Enable Background Delivery
Go to your AppDelegate's
didFinishLaunchingWithOptions
function.
This will ensure you get updates for the user's Apple Health data automatically sent to your destination.
import UIKit
import TerraiOS
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
Terra.setUpBackgroundDelivery()
return true
}
}
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 will be triggered by background delivery.
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 iOS SDK reference for details about all the functions in the SDK.
📱 App Example
Go to the main entry point of your app, and initialize the TerraiOS SDK.
import SwiftUI
import TerraiOS
// Main entry point for the app
struct ContentView: View {
@State private var terra: TerraManager?
// Function to initialise the Terra SDK once here for the whole project (async)
private func initializeTerraSDK(_ completion: @escaping () -> Void) {
Terra.instance(devId: "YOUR_DEV_ID", referenceId: "<YOUR REFERENCE ID>") { manager, error in
guard let manager = manager, error == nil else {
fatalError("Error initialising Terra SDK: \(error?.localizedDescription)")
}
terra = manager // TerraManager initialised!
completion()
}
}
// Function to ensure the user is connected to Apple Health or restablish it.
private func ensureUserConnection() {
guard let terra = terra else { return }
connectUser(terra, "AUTH TOKEN") {
// User connection ensured!
// Continue here if more processing needed...
}
}
var body: some View {
Text("Welcome to my App!")
.onAppear {
// initialise SDK and ensure user is connected
initializeTerraSDK(ensureUserConnection)
}
}
}
Define the core functions of the SDK that you need to use, e.g.
getUserId()
,intiConnection()
import TerraiOS
// connect the user to Apple Health (triggers permission popup if not already connected)
func connectUser(_ terra: TerraManager, _ token: String, _ completion: @escaping () -> Void) {
// check if the user is already connected (synchronous)
guard terra.getUserId(type: .APPLE_HEALTH) == nil else {
// User is connected, we can move forward
completion()
return
}
// trigger the permission screen if user is not connected (asynchronous)
terra.initConnection(type: .APPLE_HEALTH, token: token) {success, error in
guard success && error == nil else {
fatalError("🤯: \(error?.localizedDescription)")
}
// Apple Health user connected!
completion()
}
}
Disconnecting a user
In order to disconnect an Apple Health user, you may use the same endpoint as for Web API-based integrations, called from your backend.
You can request for historical data using one of the data retrieval functions. You may set toWebhook
to false if you wish for the callback function to return the data payload on the client side.
terra.getDaily(type: Connections.APPLE_HEALTH, startDate: startDate, endDate: endDate, toWebhook: false) {
success, payload, err in
guard err == nil && success else {
fatalError("🤯: \(err.localizedDescription)")
}
// Data is stored in `payload`
print(payload)
}
The getter functions are asynchronous, so include a callback as in the example above.
Writing Data
postActivity: allows you to write a completed activity to a user's Apple Health
postNutrition: allows you to write a nutrition log to a user's Apple Health
postBody: allows you to write a body measurement to a user's Apple Health
postPlannedWorkout: allows you to write a workout plan to a user's Apple Health
In order to write a completed activity to a user's Apple Health, use the postActivity function as below, with the instance of terra you created above.
device_data
must be passed in for postActivity to succeed.
import TerraiOS
// Function to post an activity to Terra
func postActivityData(terraManager: TerraManager, _ completion: @escaping () -> Void) {
// Create a sample TerraActivityData payload
let activityData = TerraActivityData(
metadata: TerraActivityMetaData(
name: "Morning Run",
start_time: Date().addingTimeInterval(-3600).terraString, // 1 hour ago
end_time: Date().terraString, // Now
type: TerraActivityType.RUNNING.rawValue
),
calories_data: TerraCaloriesData(total_burned_calories: 600.0),
heart_rate_data: TerraHeartRateData(
summary: TerraHeartRateSummaryData(
avg_hr_bpm: 140.0,
max_hr_bpm: 180.0
)
),
device_data: TerraDeviceData(
name: "Terra"
),
distance_data: TerraActivityDistanceData(
summary: TerraDistanceSummaryData(distance_meters: 5000.0) // 5 km
)
)
// Post the activity data using the `postActivity` function
terraManager.postActivity(type: .APPLE_HEALTH, payload: activityData) { success, error in
guard success && error == nil else {
fatalError("🤯: \(error.localizedDescription)")
}
// Activity posted!
print("Activity posted successfully!")
completion()
}
}
Data Sources requiring the Terra Mobile-SDK
The Mobile SDK is ONLY used to connect to the following integrations:
Apple Health - iOS
Samsung Health - Android
Google Fit & Health Connect- Android.
Note: the Health & Fitness API is the preferred way to connect to Google Fit until its sunsetting on June 30, 2025 due to better reliability.
For ALL other integrations, please refer to Integration Setup the Health & Fitness API.
Last updated
Was this helpful?