Your app, Powered by EXI Exercise Intelligence

Our personalised physical activity prescription, your app.

Get up and running with SDKs, API keys and integration tools.

Android EXI® SDK Setup Guide

Add EXI® to your applications

Learn how to create an EXI® powered Android application and integrate the EXI® SDK into your products and platforms.

1. Add the EXI® SDK as a dependency

In order to gain access to EXI® SDK’s offering, you must have an access token that references the package with at least read:packages scope.

  • Create a new Android application, choosing your own specifications
  • Create a github.properties file in the project root and add your Github credentials:
gpr.user=YOUR_GITHUB_USER_ID
gpr.key=YOUR_SELF_GENERATED_PERSONAL_ACCESS_TOKEN
  • Navigate to the settings.gradle, add the GitHub packages maven repository dependency
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)

    def githubProperties = new Properties()
    githubProperties.load(new FileInputStream(file("github.properties")))

    repositories {
        google()
        mavenLocal()
        mavenCentral()
        maven {
            url "https://jitpack.io"
            credentials { username authToken }
        }
    }
}
include ':app'

2. Project Setup

Set your API Key

Open your app-level build.gradle , and add the following:

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'maven-publish'
}

apply {
    plugin 'maven-publish'
}
buildTypes {
        debug {
            minifyEnabled false
            buildConfigField "String", "HEADER_X_API_KEY", "\"YOUR_API_KEY_PROVIDED_BY_EXI\""
            buildConfigField "String", "domain", "\"YOUR_ORGANISATION_DOMAIN_PROVIDED_BY_EXI\""
            buildConfigField "String", "clientId", "\"YOUR_CLIENT_ID_PROVIDED_BY_EXI\""
            debuggable true
        }
}  
  • Still inside your app-level build.gradle , and add the following:
android {
    // ...

    buildFeatures {
        buildConfig = true
    }
    
    // ...
}   
  • Add the EXI® SDK dependency package (latest version at time of writing: 0.0.61-ALPHA-SNAPSHOT.
dependencies {
  // ...
  implementation 'com.exisdk.life:sdk:0.0.61-ALPHA-SNAPSHOT'
}
  • Create a YourAppNameApplication class extending Application (remember to declare name in the AndroidManifest). Call Initialise on the static EXISDK object, passing an Android context and your API key, received from EXI. An additional boolean value can be passed as a third parameter to indicate if the SDK user wants a mockResponse. When enableMockResponse is enabled, a sample hardcoded response is returned by the SDK, which can be helpful during development, when in offline mode.
class YourAppNameApplication : Application(){
    override fun onCreate() {
        super.onCreate()
        // Initialize SDK
        EXISDK.initialize(this,BuildConfig.HEADER_X_API_KEY)
    }
}

3. Set your JWS Token

Create your JWT token

Using the following links: Online JWS key generator & JWT.IO .

Generate JWS credentials: Online JWS key generator

  1. Choose the RS256 algorithm
  2. Save all credentials somewhere safe
  3. Open JWT.IO and paste your credentials to verify signature
  4. You can use this website and credentials to easily change the payload and get a new token quickly

You must encrypt the details provided to you by EXI®. These include:

  • organisationId (your organisation ID)
  • userId (your userId)
  • email (the email you provided)
  • exp (a token expiry value)

4. Start your development journey with EXI®

Please note: The EXI Android SDK uses Kotlin Coroutines for its threading model, and so all functions are suspend functions. Coroutines give the developer the ability to start light-weight threads that may suspend the execution of a block of code from any given thread, and run asynchronously away from the UI thread. They can block either the main thread or another thread, or they can run concurrently, in parallel.

Sample request for fetching prescriptions

fun loadPrescription() {
        viewModelScope.launch {
            loading.value = true
            // Fetch prescription
            val prescriptionResult = EXISDK.getPrescription()
            loading.value = false
            when (prescriptionResult) {
                is Result.Success -> {
                    hasError.value = false
                    prescription.value = prescriptionResult.data

                    val start =
                        SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH).apply {
                            timeZone = TimeZone.getTimeZone("UTC")
                        }.parse(prescription.value!!.startedAt.dateTime)

                    val currentDate = Calendar.getInstance().time
                    currentWeek.value = weeksBetween(start!!, currentDate) + 1
                    selectedWeek.value = prescription.value!!.week.first { it.week == currentWeek.value }
                    getActivityData()
                    currentWeek.value = weeksBetween(start, currentDate) + 1
                    exiPreferences.putCurrentWeek(currentWeek.value)
                    selectedWeek.value = prescription.value!!.week.first {
                        it.week == currentWeek.value
                    }
                    prescriptionResult.data.week.sortedBy { currentWeek.value }.forEach { weeksList ->
                        weekList.add(weeksList)
                        if (currentWeek.value.toString() == weeksList.week.toString()) {
                            activityListTabs.clear()
                            weeksList.setsOfLow?.let {
                                activityListTabs.add("Low")
                            }
                            weeksList.setsOfMed?.let {
                                activityListTabs.add("Moderate")
                            }
                            weeksList.setsOfHigh?.let {
                                activityListTabs.add("High")
                            }
                        }
                    }
                    prescriptionResult.data.week
                    getActivityData()
                }
                is Result.Error -> {
                    hasError.value = true
                    errorMessage.value = prescriptionResult.error.message
                }
            }
        }
    }

Result

RESPONSE: 200 OK
METHOD: HttpMethod(value=GET)
FROM: https://api.integration.exi.life/sdk/v1/prescriptions/weeks-stream
COMMON HEADERS
...
...
...
BODY Content-Type: application/json; charset=utf-8
BODY START
{"userId":"593e1d4f-0bb3-45b2-87e9-d12ca6623409","streamId":"fibro_2_v2","includeHighIntensity":false,"startedAt":{"dateTime":"2023-09-28T10:55:47.053Z","timezone":"Europe/London"},"weekStartDay":"2023-09-25T00:00:00+01:00","currentWeek":5,"weeks":[{"week":1,"lowMinutes":10,"setsOfLow":3,"steps":1000,"setsOfSteps":3},{"week":2,"lowMinutes":10,"setsOfLow":4,"steps":1000,"setsOfSteps":4},{"week":3,"lowMinutes":10,"setsOfLow":5,"steps":1000,"setsOfSteps":5},{"week":4,"lowMinutes":10,"setsOfLow":5,"steps":1000,"setsOfSteps":5},{"week":5,"lowMinutes":15,"setsOfLow":5,"steps":1500,"setsOfSteps":5},{"week":6,"lowMinutes":20,"setsOfLow":5,"steps":2000,"setsOfSteps":5},{"week":7,"medMinutes":15,"setsOfMed":5,"steps":1500,"setsOfSteps":5},{"week":8,"medMinutes":15,"setsOfMed":5,"steps":1500,"setsOfSteps":5},{"week":9,"medMinutes":20,"setsOfMed":5,"steps":2000,"setsOfSteps":5},{"week":10,"medMinutes":20,"setsOfMed":5,"steps":2000,"setsOfSteps":5},{"week":11,"medMinutes":25,"setsOfMed":5,"steps":2500,"setsOfSteps":5},{"week":12,"medMinutes":30,"setsOfMed":5,"steps":3000,"setsOfSteps":5}],"week":[{"week":1,"lowMinutes":10,"setsOfLow":3,"steps":1000,"setsOfSteps":3},{"week":2,"lowMinutes":10,"setsOfLow":4,"steps":1000,"setsOfSteps":4},{"week":3,"lowMinutes":10,"setsOfLow":5,"steps":1000,"setsOfSteps":5},{"week":4,"lowMinutes":10,"setsOfLow":5,"steps":1000,"setsOfSteps":5},{"week":5,"lowMinutes":15,"setsOfLow":5,"steps":1500,"setsOfSteps":5},{"week":6,"lowMinutes":20,"setsOfLow":5,"steps":2000,"setsOfSteps":5},{"week":7,"medMinutes":15,"setsOfMed":5,"steps":1500,"setsOfSteps":5},{"week":8,"medMinutes":15,"setsOfMed":5,"steps":1500,"setsOfSteps":5},{"week":9,"medMinutes":20,"setsOfMed":5,"steps":2000,"setsOfSteps":5},{"week":10,"medMinutes":20,"setsOfMed":5,"steps":2000,"setsOfSteps":5},{"week":11,"medMinutes":25,"setsOfMed":5,"steps":2500,"setsOfSteps":5},{"week":12,"medMinutes":30,"setsOfMed":5,"steps":3000,"setsOfSteps":5}]}
BODY END

Sample SDK call for fetching all activities of high intensity

GlobalScope.launch {
            when(val allActivities = EXISDK().getAllActivities("HIGH")) {
                is Result.Success -> {
                    Log.d(javaClass.simpleName, allActivities.data.toString())
                }
                is Result.Error -> {
                    Log.d(javaClass.simpleName, allActivities.error.message)
                }
            }

        }
}

Result

[EXIActivity(
id=21e9f3f1-fab1-4440-8d81-eb6f3face177, name=Bodyweight workout), 
EXIActivity(id=217f5fe0-d922-4092-afaa-0350c52b88a2, name=Cardio blast), 
EXIActivity(id=d7b977ad-703e-4c91-b632-472eead1b6e9, name=Aerobics with Hayley), 
EXIActivity(id=de59f557-766f-4b36-9add-2a1791dad893, name=Power and strength), 
EXIActivity(id=abb14514-24e2-4389-9e5f-eeca15fb72ad, name=HIIT), 
EXIActivity(id=4f814dcb-aabb-4b9b-9cc1-4ea7b592ea76, name=Power and core), 
EXIActivity(id=05720979-6f59-4c39-972a-c2ee0dcc1efb, name=Circulation boost), 
EXIActivity(id=09b660b9-1ee4-4586-9e44-f664073b1b52, name=Other exercise), 
EXIActivity(id=137efb32-197d-4496-b040-52f4d506947f, name=Swimming), 
EXIActivity(id=47239873-949f-48a9-b525-12d91bd94297, name=Step machine), 
EXIActivity(id=7393b3ce-958c-401d-a5ef-ba9602ba59be, name=Outdoor cycle), 
EXIActivity(id=7773fa77-c136-4aa3-b1f4-0e7fdb8e5388, name=Outdoor run), 
EXIActivity(id=926365dc-5201-4040-b2f4-dde1844bf884, name=Treadmill run), 
EXIActivity(id=95a3cf02-2ae4-4acd-9544-9ed2174ae938, name=Treadmill walk), 
EXIActivity(id=d6169d39-e1e8-4232-aaea-e69028dc7e6d, name=Rowing machine), 
EXIActivity(id=de648095-edf4-4ae5-8953-920df55a6715, name=Indoor cycle), 
EXIActivity(id=7f7e80bd-a5df-42f7-a1d7-60f6bdcdf782, name=Andy Test High Activity
)]

You are now ready to build your customer health journeys!

Please consult our Android developer code docs and our UML Diagram repository to discover what is possible with EXI® SDK.