Using the Android/Java SDK

About the Project

This is the Android/Java SDK of Data4Life. The SDK encapsulates the backend functionality of the Data4Life Personal Health Data Platform (PHDP) and enables end-to-end encryption of health data. It allows users to store and access sensitive data on the secure platform and share it to authorized users and applications.

For more information about the Data4Life platform, visit our website.

Features

  • Authorization/Authentication

  • End-to-End encryption

  • API client for PHDP

  • Data types support for custom, FHIR 3 and FHIR 4

Build with

Notes:

  • The SDK ships with BouncyCastle and will replace the BouncyCastle version provided by the Android system. Ensure that if you’re using or depend on BouncyCastle CryptoProvider, you’re still compatible.

Before you start

To use the SDK, you must have a Data4Life partner ID. To obtain a partner ID, get in touch with us at we@data4life.care.

Getting started

Once you have a partner ID, follow these steps to start working with the SDK:

Software requirements

Installation

Consume GitHub Packages

We use GitHub Packages to distribute the SDK. In order to consume our dependencies you need to generate a GitHub Personal Access Token. Please follow the how to authenticate to GitHub Packages.

NOTICE

You need to have read access to this repository and generate a personal access token with repo and read:packages scope.

GitHub Token

The token needs to be made available.

  1. Add gpr.user = {GitHub username} and gpr.key = {GitHub Personal Access Token} to your global Gradle properties ~/.gradle/gradle.properties

    gpr.user=github-username
    gpr.key=github-token
  2. Or add following environment variables PACKAGE_REGISTRY_USERNAME={GitHub username} and PACKAGE_REGISTRY_TOKEN={GitHub Personal Access Token}

Setup Maven Repository

Add the following maven repository configuration to your root build.gradle/build.gradle.kts:

Gradle KTS
allprojects {
    repositories {
        ...
        maven {
            url = uri("https://maven.pkg.github.com/d4l-data4life/hc-sdk-kmp")
            credentials {
                username = project.findProperty("gpr.user") as String? ?: System.getenv("PACKAGE_REGISTRY_USERNAME")
                password = project.findProperty("gpr.key") as String? ?: System.getenv("PACKAGE_REGISTRY_TOKEN")
            }
        }
    }
}
Gradle Groovy
allprojects {
    repositories {
        ...
        maven {
            url = uri("https://maven.pkg.github.com/d4l-data4life/hc-sdk-kmp")
            credentials {
                username = project.findProperty("gpr.user") as ?: System.getenv("PACKAGE_REGISTRY_USERNAME")
                password = project.findProperty("gpr.key") as ?: System.getenv("PACKAGE_REGISTRY_TOKEN")
            }
        }
    }
}

Android SDK dependency

dependencies {
    implementation("care.data4life.hc-sdk-kmp:sdk-android:LATEST_VERSION")
}

The SDK ships with ThreeTenBP a Java 8 Time backport. For Android, its loading mechanism of time zone information is inefficient. So we recommend providing your favorite Android ThreeTen library here, for example ThreeTenABP.

dependencies {
    implementation("care.data4life.hc-sdk-kmp:sdk-android:LATEST_VERSION") {
        ...
        // exclude the threetenbp dependency from the `sdk`
        exclude group: "org.threeten", module: "threetenbp"
    }
    // provide your favorite ThreeTen library here
    implementation "com.jakewharton.threetenabp:threetenabp:1.4.0"
}

Configuration

The SDK is only published as release variant. So you need to add a matchingFallbacks config to all of your buildTypes and flavors. See variant awareness for more details.

android {
    buildTypes {
        debug {
            matchingFallbacks = ["release", "debug"]
        }
    }
}

To ensure Java 8 compatibility, add compile options to app build.gradle/build.gradle.kts:

android {
    compileOptions {
        sourceCompatibility = "1.8"
        targetCompatibility = "1.8"
    }

    kotlinOptions {
        jvmTarget = "1.8"
    }
}

Java SDK dependency

Add the following dependencies to your app build.gradle/build.gradle.kts file.

dependencies {
    implementation("care.data4life.hc-sdk-kmp:sdk-jvm:LATEST_VERSION")
}

Configuration

To ensure Java 8 compatibility, add compile options to app build.gradle/build.gradle.kts:

java {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
}

tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

Usage

Android

On Android manifest placeholders are used to pass the configuration to the SDK.

  1. Add the manifestPlaceholders property with the platform, environment, clientId, clientSecret, and redirectScheme keys to your build.gradle/build.gradle.kts file.

    Gradle KTS
    android {
        defaultConfig {
            manifestPlaceholders(mapOf(
                    "platform" to "D4L",
                    "environment" to "production",
                    "clientId" to "clientId",
                    "clientSecret" to "clientSecret",
                    "redirectScheme" to "com.example",
                    "debug" to "true"
            ))
        }
    }
    Gradle Groovy
    android {
        defaultConfig {
            manifestPlaceholders = [
                platform      : "D4L",
                environment   : "production",
                clientId      : "clientId",
                clientSecret  : "clientSecret",
                redirectScheme: "com.example",
                debug         : "false"
            ]
        }
    }
    The debug flag is set to false if your app is not debuggable.
  2. To log in, use the startActivityForResult method with login intent.

    Intent loginIntent = Data4LifeClient.getLoginIntent(context, null);

    or with custom scopes

    Intent loginIntent = Data4LifeClient.getLoginIntent(
        context,
        new String[] {"scope:r", "scope:w"}
    );

    and then

    startActivityForResult(loginIntent, Data4LifeClient.D4L_AUTH);
  3. Handle the login result in your onActivityResult method.

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == D4L_AUTH){
            if (resultCode == RESULT_OK){
                // you are now logged in
            }
        }
    }
  4. Get the Data4Life client instance inside Activity or Fragment.

    Data4LifeClient client = Data4LifeClient.getInstance();
  5. Now you can use the available API for the 3 supported data types which will return results on background thread.

Java

The Java SDK only supports a single-user use case. For every individual user, the SDK must be instantiated with the user alias.

  1. Instantiate the client with alias, platform, environment, clientId, clientSecret, and redirectUrl properties:

    Data4LifeClient client = Data4LifeClient.init(
        "alias",
        "clientId",
        "clientSecret",
        Environment.PRODUCTION,
        "redirectUrl",
        "platform"
    );
    The alias is used to namespace the session that is bound to a client instance. This allows multiple instances of the client running with different sessions in parallel. Could be used to bind a client instance to a user in a multiuser environment.
  2. To log in, you need start the OAuth 2.0 authorization flow by generating the authorization url and hand it over to a browser and let the user authorize.

    String authorizationUrl = client.getAuthorizationUrl();
  3. After the browser auth session calls the previously registered redirectUrl, pass the received OAuth callback URL to the client instance

    String callbackUrl = "https://.../oauth/callback?code=12345&state=abcde"
    boolean authorized = client.finishLogin(callbackUrl);
  4. If you’re in a multiuser setup with multiple SDK instances, you could extract the alias from the callbackUrl

    UserIdExtractor extractor = new UserIdExtractor();
    String userId = extractor.extract(callbackUrl);
    Multiple instance management is not handled by the SDK and needs to be done by you, e.g. with a Map<String,Data4LifeClient> or better suitable solution
  5. Now you can use the available API for the 3 supported data types which will return results on background thread.