Android (Kotlin)

How to use the TerraAndroid SDK to connect mobile-based integrations?

Overview

This guide will walk you through the necessary steps to use the Terra SDK with Android-based integrations in your Android app. It covers everything from SDK initialization, user connection, permission handling, and background data updates.

The TerraAndroid SDK supports the following integrations:

  • Samsung Health

  • Health Connect

1. Install the SDK

1. Install Terra in build.gradle

  • Inside the dependencies section of your build.gradle file, add the following line of code.

build.gradle
implementation 'co.tryterra:terra-android:{VERSION_NUMBER}'

2. Sync your project with build.gradle

Sync your project with Gradle by clicking on the "Sync Project with Gradle Files" button in the toolbar. This will download the TerraAndroid SDK and make it available to your project.

Requirements

  • Your app build config must be for Android 28 (minSDK 28) and above.

  • The device must have the required app installed, e.g. Health Connect or Samsung Health

3. Configure Health Permissions

Terra API provides direct access to the Samsung Health SDK via our privileged partnership with Samsung.

If you'd like to apply for Samsung Health access, please reach out to us by submitting a ticket on the Terra Support page. You can find this in your Terra Dashboard!


2. Initialize the SDK

The initialization only needs to be done once on app start, (e.g. in your MainActivity file or equivalent), and every time the app is brought into the foreground. This ensures that the SDK is properly set up and ready to be used.

Step 1: Import Terra and TerraManager

In your Android Studio project, you should now be able to import classes from the Terra SDK.

MainActivity.kt
import co.tryterra.terra.Terra
import co.tryterra.terra.TerraManager

Step 2: Get a TerraManager Instance

To do this, run the Terra manager initialization function as below:

MainActivity.kt
import co.tryterra.terra.Terra
import co.tryterra.terra.TerraManager

import java.lang.IllegalStateException

class MainActivity : Activity() {
    private lateinit var terra: TerraManager

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        Terra.instance("YOUR DEV ID", "REFERENCE ID", this) { manager, error ->
            error?.let{it ->  
                throw IllegalStateException("🤯: Error initialising terra ${it.message}")
            }
            terra = manager
        }
    }
}

(N.B This call is asynchronous, please ensure this is complete before using the manager).


3. Connect to a User

Once Terra is initialized, you can create a connection (e.g. Samsung Health or Health Connect).

Call terra.initConnection from the TerraManager instance you've created above to have the corresponding permission screen pop up.

This method triggers the a permission popup and establishes the connection.

From the TerraManager instance, call initConnection() with the following arguments:

  • type: Specify the connection type (e.g. Connections.SAMSUNG or Connections.HEALTH_CONNECT)

  • token: A one-time authentication token generated from your backend server using Terra API. 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 the Android SDKs (e.g., heart rate, steps). If empty, it defaults to all available permissions.

  • schedulerOn: To allow Terra to make scheduled requests whenever the app is in the foreground.

To learn more about these parameters and their different options, check the Android SDK Reference.

MainActivity.kt
import android.app.Activity
import android.os.Bundle
import android.util.Log

import co.tryterra.terra.Terra
import co.tryterra.terra.TerraManager
import co.tryterra.terra.enums.Connections

import java.lang.IllegalStateException

class MainActivity : Activity() {
    private lateinit var terra: TerraManager
        
    override fun onCreate(savedInstanceState: Bundle?) {
        // Creation of Terra Manager as in Step 2!
    }

    fun initialiseUserConnection() {
        if (!this::terra.isInitialized){
            throw IllegalStateException("🤯: Terra Manager not initialised yet")
        }
        // Example token received from your backend
        val token = "your_generated_token_from_backend"
        
        // Initialize the connection to Samsung Health
        terra.initConnection(
            connection = Connections.SAMSUNG,   // Connecting to Samsung Health
            token = token,                      // Token passed from backend
            context = this,                  // The activity context
            customPermissions = setOf(),  // Custom permissions set (empty set defaults to all permissions)
            schedulerOn = true,                 // Background scheduler on
            startIntent = null                  // Deprecated - always set to null
        ) { success, error ->
            error?.let {
                throw IllegalStateException("🤯: ${it.message}")
            }
            // Connection successful!
            Log.i("MainActivity", "Auth Success status: $success")
        }
    }
}

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:

a. you call initConnection with an expanded set of customPermissions

b. the app is deleted & reinstalled.

c. a permission that was not granted to use on release by Google has been requested by the app

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 POSThttps://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.


4. Validate the Connection

To ensure a connection is still valid on the client side, use the terra.getUserId() method. This function is synchronous and returns the user_id right away or null 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.

  1. Check if the User is Connected

    1. If the function returns a user ID, the user is still connected, 🎉 keep vibing along!

    2. If the function returns nil, the user needs to reconnect.

  2. 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.


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 Android SDK reference for details about all the functions in the SDK.


📱 App Example

MainActivity.kt
import android.app.Activity
import android.os.Bundle
import android.util.Log

import co.tryterra.terra.Terra
import co.tryterra.terra.TerraManager
import co.tryterra.terra.enums.Connections

import java.lang.IllegalStateException

class MainActivity : Activity() {
    private lateinit var terra: TerraManager

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        Terra.instance("YOUR DEV ID", "REFERENCE ID", this) { manager, error ->
            error?.let{it -> 
                throw IllegalStateException("🤯: Error initialising terra ${it.message}")
            }
            terra = manager
            this.initialiseUserConnection()
        }
    }

    fun initialiseUserConnection() {
        if (!this::terra.isInitialized){
            throw IllegalStateException("🤯: Terra Manager not initialised yet")
        }
        
        if (terra.getUserId(Connections.SAMSUNG) != null){
            // User already connected
            return
        }
        
        // Initialize the connection to Samsung Health
        terra.initConnection(
            connection = Connections.SAMSUNG,   // Connecting to Samsung Health
            token = "AUTH TOKEN",                      // Token passed from backend
            context = this,                  // The activity context
            customPermissions = setOf(),  // Custom permissions set (empty set defaults to all permissions)
            schedulerOn = true,                 // Background scheduler on
            startIntent = null                  // Deprecated - always set to null
        ) { success, error ->
            error?.let {
                throw IllegalStateException("🤯: ${it.message}")
            }
            // Connection successful!
            Log.i("MainActivity", "Auth Success status: $success")
        }
    }
}

Disconnecting a user

In order to disconnect an SDK user, you may use the same endpoint as for Web API-based integrations, called from your backend.


MainActivity.kt
import co.tryterra.terra.enums.Connections
import java.time.Instant
import java.time.temporal.ChronoUnit
import java.util.*

fun requestData() {
    val startDate = Date.from(Instant.now().minus(1, ChronoUnit.DAYS))
    val endDate = Date()
    
    // Request for yesterday and today's data
    terra.getDaily(
        type = Connections.SAMUNG,
        startDate = startDate,
        endDate = endDate,
        toWebhook = false 
    ) { success, payload, error ->
        error?.let{
            throw IllegalStateException("🤯: Error requesting data ${it.message}")    
        }
        // Process payload here
    }
}

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:

a. you call initConnection with an expanded set of customPermissions

b. the app is deleted & reinstalled.

c. a permission that was not granted to use on release by Google has been requested by the app

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 POSThttps://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.


Historical Data retrieval

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.

MainActivity.kt
import co.tryterra.terra.enums.Connections
import java.time.Instant
import java.time.temporal.ChronoUnit
import java.util.*

fun requestData() {
    val startDate = Date.from(Instant.now().minus(1, ChronoUnit.DAYS))
    val endDate = Date()
    
    // Request for yesterday and today's data
    terra.getDaily(
        type = Connections.SAMUNG,
        startDate = startDate,
        endDate = endDate,
        toWebhook = false 
    ) { success, payload, error ->
        error?.let{
            throw IllegalStateException("🤯: Error requesting data ${it.message}")    
        }
        // Process payload here
    }
}

Data Sources requiring the Terra Mobile-SDK

Data Sources requiring the Terra Mobile-SDK

Last updated

Was this helpful?