Flutter
type
: Specify the connection type (e.g.Connections.APPLE_HEALTH
,Connections.SAMSUNG
,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.customPermissions
: 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
:iOS: Defaults the Background Delivery option to true. This will make Terra send new data from the provider to your webhook automatically.
Android: To allow Terra to make scheduled requests whenever the app is in the foreground.
Overview
This guide will walk you through the necessary steps to use the Terra Flutter Plugin with Android and Apple-based integrations. It covers everything from SDK initialization, user connection, permission handling, and background data updates.
The Terra Flutter Plugin supports the following integrations:
Samsung Health (Android)
Health Connect (Android)
Apple Health (iOS)
1. Install and Setup Terra Flutter
Install the terra flutter package using
flutter pub get terra_flutter_bridge
Complete the following iOS and/or Android Setup
In your terminal, cd to your
/ios
folder, and runpod install
to install all the dependencies.Add Capabilities:
Healthkit > Healthkit Background Delivery
Background Modes > Background processing
Background modes > Background fetch
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:
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
Method 2: Directly editing info.plist in your React Native project
1) In your RN app project, go to your
/ios
folder2) Go to info.plist, and add the following tags:
<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>
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 every time the app is brought into the foreground. This ensures that the SDK is properly set up and ready to be used.
The SDK should be initialized every time your app is opened.
This is a necessary prerequisite for other SDK functions to run as expected.
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:
import 'package:terra_flutter_bridge/terra_flutter_bridge.dart';
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.
Hereis an example:
import 'package:flutter/material.dart';
import 'package:terra_flutter_bridge/terra_flutter_bridge.dart';
import 'package:terra_flutter_bridge/models/enums.dart';
import 'package:terra_flutter_bridge/models/responses.dart';
void main() async {
// Ensure that Flutter bindings are initialized
WidgetsFlutterBinding.ensureInitialized();
// Initialize Terra once when the app starts
await _initializeTerra();
// Launch your app thereafter
runApp(Container()); // Empty container or basic widget if needed
}
Future<void> _initializeTerra() async {
String devID = 'YOUR_DEV_ID';
String referenceID = 'YOUR_REFERENCE_ID';
SuccessMessage? result = await TerraFlutter.initTerra(devID, referenceID);
if (result?.error != null) {
throw Exception('Failed to initialise Terra ${result?.error}');
}
// Successfully initialised Terra!
}
(N.B This call is asynchronous, please ensure this is complete before using other SDK functions).
3. Connect a User
1. Call initConnection()
initConnection()
Import initConnection
and call the function with the following arguments:
type
: Specify the connection type (e.g.Connections.APPLE_HEALTH
,Connections.SAMSUNG
,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.customPermissions
: 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
:iOS: Defaults the Background Delivery option to true. This will make Terra send new data from the provider to your webhook automatically.
Android: To allow Terra to make scheduled requests whenever the app is in the foreground.
import 'package:terra_flutter_bridge/terra_flutter_bridge.dart';
import 'package:terra_flutter_bridge/models/enums.dart';
import 'package:terra_flutter_bridge/models/responses.dart';
Future<void> _initialiseConnection() async {
// Example token received from your backend
String token = 'example_token';
// Define connection type and custom permissions
Connection connection = Connection.appleHealth;
List<CustomPermission> customPermissions = []; // Leave empty to default to all permissions
bool schedulerOn = true; // Enables background delivery
// Initialize the connection
SuccessMessage? result = await TerraFlutter.initConnection(
connection, // The type of connection (e.g., Apple Health)
token, // Token received from backend
schedulerOn, // Enables background delivery
customPermissions // Empty list for custom permissions
);
if (result?.error != null) {
throw Exception('Failed to initialise connection ${result?.error}');
}
// Connection successful!
}
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.
initConnection
only needs to be called a single time.
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
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
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. 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.
Go to your
/ios
folder in the Flutter projectCall the function
setUpBackgroundDelivery
in your AppDelegate'sdidFinishLaunchingWithOptions
function
This will ensure you get updates for the user's Apple Health data automatically sent to your destination.
import UIKit
import Flutter
import TerraiOS
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
Terra.setUpBackgroundDelivery()
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
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 Flutter SDK reference for details about all the functions in the SDK.
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.
import 'package:terra_flutter_bridge/terra_flutter_bridge.dart';
import 'package:terra_flutter_bridge/models/enums.dart';
import 'package:terra_flutter_bridge/models/responses.dart';
Future<void> getData() async {
// Example connection type and dates
Connection connection = Connection.appleHealth; // Assuming Connection is an enum with APPLE
DateTime startDate = DateTime.now().subtract(Duration(days: 1)); // Replace with actual start date
DateTime endDate = DateTime.now(); // Replace with actual end date
// Optionally, send data to webhook or not
bool toWebhook = false; // Set to false to receive the data in the response
// Call the getDaily function
DataMessage? dataMessage = await TerraFlutter.getDaily(connection, startDate, endDate, toWebhook: toWebhook);
// Handle the response based on the structure of DataMessage
if (dataMessage?.error != null) {
throw Exception("Error getting data ${dataMessage?.error}")
}
// Process data here: `dataMessage?.data`
}
Check out the Flutter SDK reference 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.
In order to write a workout for the user to follow on their Apple Watch, use the postPlannedWorkout function as below, with the instance of terra you created above.
Planned Workouts are only supported for APPLE, and on iOS 17 and above.
import 'package:terra_flutter_bridge/terra_flutter_bridge.dart';
import 'package:terra_flutter_bridge/models/enums.dart';
import 'package:terra_flutter_bridge/models/responses.dart';
import 'package:terra_flutter_bridge/models/planned_workout.dart';
void sendPlannedWorkout() async {
// Create a planned workout payload
TerraPlannedWorkout plannedWorkout = TerraPlannedWorkout(
metadata: TerraPlannedWorkoutMetaData(
id: "unique-workout-id",
name: "Morning Run",
type: TerraActivityType.RUNNING,
planned_date: DateTime.now().toIso8601String(),
estimated_duration_seconds: 3600, // Estimated 1 hour workout
),
steps: [
PlannedWorkoutStep(
order: 1,
type: PlannedWorkoutStepType.STEP,
name: "Warm-up",
durations: [PlannedWorkoutStepDuration.Time(
TimePlannedWorkoutStepDuration(seconds: 600)
)], // 10-minute warm-up
targets: [PlannedWorkoutStepTarget.HeartRate(
HRPlannedWorkoutStepTarget(hr_bpm_low: 120, hr_bpm_high: 140)
)]
),
PlannedWorkoutStep(
order: 2,
type: PlannedWorkoutStepType.STEP,
name: "Run",
durations: [PlannedWorkoutStepDuration.Time(
TimePlannedWorkoutStepDuration(seconds: 3000)
)], // 50-minute run
targets: [PlannedWorkoutStepTarget.Speed(
SpeedPlannedWorkoutStepTarget(speed_meters_per_second: 3.0)
)]
)
],
);
// Send the workout to Apple Health
SuccessMessage? response = await TerraFlutter.postPlannedWorkout(
Connection.appleHealth,
plannedWorkout
);
if (response?.error != null) {
throw Exception("Error getting data ${response?.error}")
}
// Workout posted!
}
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?