Mobile SDK: Android

This page will show you how to install and use the FuturaeKit SDK for Android.

Prerequisites

Before reading the rest of this guide, please make sure that you first read the Mobile SDK: Introduction page.

Release Information

You can find information about the Android FuturaeKit SDK release history and changes here.

Installation

We are going to assume that you are using Android Studio for your development. You can install FuturaeKit into your project using:

Maven

The preferred way to get the FuturaeKit SDK fro Android is through maven and the Futurae private repository.

To do so add the following lines to your build.gradle file:

repositories {
  maven {
    url 'https://artifactory.futurae.com/artifactory/futurae-mobile'
    credentials {
      username = 'anonymous'
      password = ''
    }
  }
}

dependencies {
  implementation('com.futurae.sdk:futuraekit:x.x.x')
}

Of course, make sure to specify the desired version number, in place of x.x.x.

Manual Installation

You can download the latest SDK from the SDK repository, or clone the repository directly. The repository also contains a simple demo app to show how the SDK can be integrated.

To integrate the FuturaeKit SDK into your project, copy futuraekit.aar into the src/main/libs folder of your app. Then, in your modules build.gradle (the one under “app”), add the following dependencies:

implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-moshi:2.4.0'
implementation 'com.squareup.moshi:moshi-adapters:1.6.0'
implementation 'com.squareup.okhttp3:okhttp:3.11.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0'
implementation 'com.github.nisrulz:easydeviceinfo-base:2.4.1'
implementation 'com.google.code.gson:gson:2.8.6'
implementation files('src/main/libs/futuraekit.aar')

android_sdk_gradle_app

And in the projects build.gradle adjust the repositories to include the libs folder:

allprojects {
  repositories {
    google()
    jcenter()
    flatDir {
      dirs 'src/main/libs'
    }
  }
}

android_sdk_gradle_project

Configuration and Initialization

To configure and initialize the SDK, take the following steps:

Add Permissions

Please add the following permissions, which the FuturaeKit SDK needs, if they are not already present in your AndroidManifest.xml file:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />

<meta-data
    android:name="com.google.android.gms.vision.DEPENDENCIES"
    android:value="barcode"/>

Initialize the SDK

We recommend using an android Application class to initialize the SDK. If you already have one in your app already, follow these steps:

Firstly, in your Application class find or create the onCreate method and add the following code to initialize the FuturaeKit SDK:

import com.futurae.sdk.FuturaeClient;

public class AppMain extends Application {

  // overrides
  @Override
  public final void onCreate() {
    super.onCreate();

    FuturaeClient.launch(this);
  }
}

Secondly, in your res/values folder make sure to create a file futurae.xml with the following contents:

<?xml version="1.0" encoding="utf-8"?>
<resources>

  <string name="ftr_sdk_id">{FuturaeSdkId}</string>
  <string name="ftr_sdk_key">{FuturaeSdkKey}</string>
  <string name="ftr_base_url">https://api.futurae.com:443</string>

</resources>

You can get your SDK credentials from Futurae Admin:

  • First you need to choose or determine that Futurae Service which is configured in your backend application.
  • Assuming you can access the particular Service on Futurae Admin, you can go to Settings -> Mobile SDK in order to get your SDK credentials
  • If Mobile SDK is not enabled for the particular Service, please contact Futurae Support in order to enable it.

Build your App

Build and run your app. If it is successful, you should be able to see the SDK logs in the console.

Configure R8 and ProGuard

If you are using R8 or ProGuard to obfuscate your app, you need to include the proguard rules of the futurae.pro file. See the build.gradle file of the FuturaeDemo app, as an example on how to do this.

Demo App

The SDK’s repository contains a stripped-down demo app which showcases examples of how some of the SDK’s core features can be integrated.

Features

The FuturaeKit SDK for Android provides the following features and functionality:

Callbacks

The SDK methods that perform API calls to the Futurae backend use callbacks as the feedback mechanism. These calls expect an object of the FuturaeCallback interface as an argument:

public interface FuturaeCallback {
  void success();
  void failure(Throwable throwable);
}

Push Notifications

Your app must be set up to receive Firebase Cloud Messaging (FCM) push notifications from the Futurae backend. You can choose to receive and handle these notifications yourself, or alternatively you can use the existing infrastructure provided in the SDK. You can find more information on how to setup FCM push notifications for your app in the Firebase Cloud Messaging Developer Guide.

In order to be able to receive FCM notifications, you need to specify the Firebase Messaging service inside the application section of your Manifest:

<service android:name="com.futurae.sdk.messaging.FTRFcmMessagingService">
  <intent-filter>
    <action android:name="com.google.firebase.MESSAGING_EVENT" />
  </intent-filter>
</service>

For this purpose, you can either use the one included in the SDK (com.futurae.sdk.messaging.FTRFcmMessagingService), or write your own. This service overrides two important methods:

@Override
public void onNewToken(String token);

@Override
public void onMessageReceived(RemoteMessage message);

The first one is invoked whenever a new FCM push token has been generated for the app; it is important to register this token with the Futurae backend in order to continue receiving push notifications. The FTRFcmMessagingService implements this functionality.

The second one is invoked whenever a new push notification (or cloud message) is received by the app. The FTRFcmMessagingService then processes this message and invokes the SDK accordingly.

FCM Token Registration

The FTRFcmMessagingService is responsible for registering the app’s FCM token to the Futurae server. This is important for the server to be able to issue FCM notifications for your app. The provided service handles this, however if you need to, you can write your own or extend the existing one.

If you are implementing your own FCM notification handling, you should register the FCM token to the Futurae server every time it changes. The call that registers the FCM token to the Futurae server is registerPushToken(), and it is necessary every time the FCM token is generated or is changed by FCM.

For example, once the app receives a new FCM token (e.g. via an onNewToken() callback in your own FirebaseMessagingService subclass), the token needs to be obtained and registered to the Futurae server using the following code:

FuturaeClient.sharedClient().registerPushToken(fcmToken, new FuturaeCallback() {
  @Override
  public void success() {

  }

  @Override
  public void failure(Throwable t) {

  }
});

FCM Listener Service

The FTRFcmMessagingService receives FCM push notifications and handles them, according to the actions dictated by the Futurae server. You can use or extend the service provided by the SDK, or write your own. There are two distinct push notification types issued by the Futurae server: Aprove or Unenroll.

In case you want to process and handle the FCM notifications without using FTRFcmMessagingService, you must use the following code in order to process and handle the notifications sent by the Futurae server, inside the implementation of your own FirebaseMessagingService subclass:

@Override
public void onMessageReceived(RemoteMessage message) {

  // Create and handle a Futurae notification, containing a Bundle with any data from message.getData()
  FTRNotification notification = FTRNotificationFactory.createNotification(service, data);
  notification.handle();
}

Local Intents

Once a Futurae FCM notification has been handled, the SDK will notify the host app using local broadcasts. The app should register a broadcast receiver for these intents and react accordingly. There are three distinct Intents that the notification handlers might send in a local broadcast:

  • INTENT_GENERIC_NOTIFICATION_ERROR: Indicates that an error was encountered during the processing or handling of a FCM notification.
  • INTENT_APPROVE_AUTH_MESSAGE: Indicates that a Push Notification Authentication has been initiated.
  • INTENT_ACCOUNT_UNENROLL_MESSAGE: Indicates that a user account has been logged out remotely.

The following example shows how to register for these intents:

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Shared.INTENT_GENERIC_NOTIFICATION_ERROR);  // General notification error intent
intentFilter.addAction(Shared.INTENT_APPROVE_AUTH_MESSAGE);        // Approve Authentication notification intent
intentFilter.addAction(Shared.INTENT_ACCOUNT_UNENROLL_MESSAGE);    // Logout user notification intent

LocalBroadcastManager.getInstance(getContext()).registerReceiver(new BroadcastReceiver() {

  @Override
  public void onReceive(Context context, Intent intent) {

    switch(intent.getAction()) {
      case Shared.INTENT_ACCOUNT_UNENROLL_MESSAGE:
        // Handle unenroll notification (e.g. refresh lists)
        break;

      case Shared.INTENT_APPROVE_AUTH_MESSAGE:
        // Handle approve notification (e.g. show approve view)
        break;

      case Shared.INTENT_GENERIC_NOTIFICATION_ERROR:
        // Handle FCM notification error
        break;
    }
  }
}, intentFilter);

QR Codes

The Futurae Authentication Platform, uses QR Codes for different operations:

  • Enroll a device for a user (online)
  • Authenticate a user or transaction (online)
  • Authenticate a user or transaction (offline)

The Futurae SDK supports all these functionalities. The business App can have different flows for supporting the needed functionality, or condense all QR Code operations in one. The Futurae SDK provides a handy method to identify on the fly which type of QR Code the user has scanned:

Barcode qrcode = data.getParcelableExtra(FTRQRCodeActivity.PARAM_BARCODE);
switch (FuturaeClient.getQRCodeType(qrcode.rawValue)) {
  case FuturaeClient.QR_ENROLL:
    // handle Enroll QR Code
    break;
  case FuturaeClient.QR_ONLINE:
    // handle Online QR Code Factor
    break;
  case FuturaeClient.QR_OFFLINE:
    // handle Offline QR Code Factor
    break;
}

Enroll

To enroll this SDK as a device for a Futurae User, call the enroll() method using a valid activation code, for example obtained by scanning an enrollment QR Code. For example, you can use a QR Code Reader Activity to scan a code and obtain the result:

startActivityForResult(FTRQRCodeActivity.getIntent(this), FTRQRCodeActivity.RESULT_BARCODE);

If a QR Code is successfully scanned then onActivityResult will be called, with the scanned code:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

  if (resultCode == RESULT_OK && requestCode == FTRQRCodeActivity.RESULT_BARCODE) {
    Barcode qrcode = data.getParcelableExtra(FTRQRCodeActivity.PARAM_BARCODE);

    FuturaeClient.sharedClient().enroll(qrcode.rawValue, new FuturaeCallback() {
      @Override
      public void success() {

      }

      @Override
      public void failure(Throwable throwable) {

      }
    });
  }

}

Please make sure to call enroll, inside the onActivityResult method to complete the user enrollment.

Logout (Unenroll)

To remove an account from this SDK (ie unenroll this user device), call the logout() method:

FuturaeClient.sharedClient().logout(userId, new FuturaeCallback() {
  @Override
  public void success() {

  }

  @Override
  public void failure(Throwable throwable) {

  }
});

Typically this should happen either when the user removes the account manually from the app, or when a user has been logged out remotely by the server. In the former case, calling the logout() method is enough, as it notifies the server of the logout and deletes the account from the SDK too. In the latter case, the server will send a FCM notification to the app, and the default handler of the notification will delete the account from the SDK as well. In this case, the notification handler will also send a local broadcast to the app (see INTENT_ACCOUNT_UNENROLL_MESSAGE above, so that the app can also perform any further action required (e.g. refresh the list of active accounts in an account view).

The intent contains the Futurae user_id, as well as the device_id, as an extra:

String userId = intent.getStringExtra(NotificationUtils.PARAM_USER_ID);
String deviceId = intent.getStringExtra(NotificationUtils.PARAM_DEVICE_ID);

Account Status

To get a list of all enrolled accounts in this SDK, call the following method:

List<Account> accounts = FuturaeClient.sharedClient().getAccounts();

To fetch the status and pending authentication Authentication Session Information for these accounts, you can use the following method (where userIds is a list of the corresponding user IDs):

FuturaeClient.sharedClient().getAccountsStatus(userIds, new FuturaeResultCallback<AccountsStatus>() {
  @Override
  public void success(AccountsStatus accountsStatus) {
    // Handle the pending sessions
  }

  @Override
  public void failure(Throwable throwable) {
    // Handle the error
  }
});

Authenticate User

One-Touch

With One-Touch (aka Approve), the server will send a push notification to the app, where the user should approve or reject the authentication session. The notification is received and handled by the SDK, which in turn will send a local broadcast (see INTENT_APPROVE_AUTH_MESSAGE above), so that the app can perform any required actions. For example, the app might want to display a prompt to the user so that they can approve or reject the session.

The intent contains an object that describes the authentication session as an extra. This object contains the user ID and the session ID, which are required for sending the authentication outcome to the server:

ApproveSession authSession = intent.getParcelableExtra(FTRApproveNotification.PARAM_APPROVE_SESSION);
String userId = authSession.getUserId();
String sessionId = authSession.getSessionId();

Once the outcome of the authentication has been decided by the app, it should be sent to the server for the authentication session to complete.

Approve Authentication

To approve the authentication session, when no extra_info is supplied in Authenticate with One-Touch, use the following method:

FuturaeClient.sharedClient().approveAuth(userId, sessionId, new FuturaeCallback() {
  @Override
  public void success() {

  }

  @Override
  public void failure(Throwable t) {

  }
});
Reject Authentication

The user might choose to reject the authentication session. Additionally, in case the session has not been initiated by the user, they might also choose to report a fraudulent authentication attempt back to the server. In this case, and when no extra_info is supplied in Authenticate with One-Touch, use the following method:

boolean reportFraud = false; // Set to true to report a fraudulent attempt
FuturaeClient.sharedClient().rejectAuth(userId, sessionId, reportFraud, new FuturaeCallback() {
  @Override
  public void success() {

  }

  @Override
  public void failure(Throwable t) {

  }
});

Online QR Code

To authenticate the user using online QR Code, scan the QR Code provided by the server and pass its contents to the following method:

FuturaeClient.sharedClient().approveAuth(qrCodeString, new FuturaeCallback() {
  @Override
  public void success() {

  }

  @Override
  public void failure(Throwable throwable) {

  }
});

Offline QR Code

The Offline QR Code Factor does not require any internet connection on the user’s phone, to function.

To authenticate with the offline QR Code Factor, scan the QR Code provided by the server and display the relevant information to the user. If the user approves the authentication or transaction request, generate the 6-digit confirmation number that the user needs to enter in the browser:

String verificationCode = FuturaeClient.sharedClient().computeVerificationCodeFromQrcode(qrCodeString);

IMPORTANT: In case the backend API Authenticate with Offline QR code (or Authenticate Transaction with Offline QR code) is invoked with supplying the extra_info input parameter (for example, when contextual information for logins, or transaction details for transaction authentication), which includes information that must be displayed to the user before they can approve/reject the request, then you can retrieve this information from the QR code itself, as shown below:

ApproveInfo[] extraInformation = FuturaeClient.getExtraInfoFromOfflineQrcode(qrCode);

Authentication Session Information

For a given authentication session, either identified via a session ID (e.g. received by a push notification) or a session Token (e.g. received by a QRCode scan), you can ask the server for more information about the session:

// if you have a session ID
FuturaeClient.sharedClient().sessionInfoById(userId, sessionId, new FuturaeResultCallback<SessionInfo>() {
  @Override
  public void success(SessionInfo sessionInfo) {
    // Handle the session
  }

  @Override
  public void failure(Throwable throwable) {
    // Handle the error
  }
});

// if you have a session Token
FuturaeClient.sharedClient().sessionInfoByToken(userId, sessionToken, new FuturaeResultCallback<SessionInfo>() {
  @Override
  public void success(SessionInfo sessionInfo) {
    // Handle the session
  }

  @Override
  public void failure(Throwable throwable) {
    // Handle the error
  }
});

If there is extra information to be displayed to the user (supplied when calling Autnethicate User or Autnethicate Transaction in the backend API), for example when confirming a transaction, this will be indicated with a list of key-value pairs in the extra_info part of the response.

In order to query the server for the authentication session information, you need the user ID and the session ID or session token. You can use the following helper methods to obtain these from either a URI or a QR Code:

public class FuturaeClient {
  public static String getUserIdFromQrcode(String qrCode);
  public static String getSessionTokenFromQrcode(String qrCode);
  public static String getUserIdFromUri(String uri);
  public static String getSessionTokenFromUri(String uri);
}
Authentication with extra information

In case it exists, you can retrieve the extra information that the user needs to review while authenticating by calling the following method on the SessionInfo object:

public ApproveInfo[] getApproveInfo();

Each ApproveInfo object is a key-value pair that describes a single piece of information; call the following methods to retrieve the key and value of the object respectively.

public String getKey();
public String getValue();

IMPORTANT: In case the authentication contains extra_info, it is mandatory that the information is fetched from the server, displayed to the user, and included in the authentication response in order for it to be included in the response signature. Otherwise, the server will reject the authentication response. Use the following methods to send an authentication response including the authentication information:

class FuturaeClient {
  public void approveAuth(String qrCode, final FuturaeCallback callback, ApproveInfo[] extraInfo);
  public void approveAuth(String userId, String sessionId, final FuturaeCallback callback, ApproveInfo[] extraInfo);
  public void rejectAuth(String userId, String sessionId, boolean reportFraud, final FuturaeCallback callback, ApproveInfo[] extraInfo);
}

TOTP

TOTP authentication can be used for offline authentication, as there is no requirement for an internet connection in the app. To get the current TOTP generated by the SDK for a specific user account, call the following method:

CurrentTotp totp = FuturaeClient.sharedClient().nextTotp(userId);
String passcode = totp.getPasscode();            // The TOTP that the user should use to authenticate
int remainingSeconds = totp.getRemainingSecs();  // The remaining seconds of validity of this TOTP

As seen in this example, the nextTotp() method returns an object that contains the TOTP itself, but also the remaining seconds that this TOTP will be still valid for. After this time, a new TOTP must be obtained by the SDK.

URI Schemes

The SDK is able to handle URI scheme calls, which can be used to either enroll or authenticate users. Once your activity has been set up to handle the URI scheme call intents, get the intent data in the onCreate() method of your activity, which contains the URI that should be passed in the SDK, using the handleUri() method:

FuturaeClient.sharedClient().handleUri(uriString, new FuturaeCallback() {
  @Override
  public void success() {

  }

  @Override
  public void failure(Throwable throwable) {

  }
});

IMPORTANT: In case you perform authentication using with a URI scheme call (using the mobile_auth_uri value which is returned by the Futurae backend when calling Authenticate User or Authenticate Transaction), and this authentication includes extra information to be displayed to the user, you must retrieve this information from the server and include it in the authentication response. See section Authentication Session Information for details on how to do that.

Account Migration

Account migration allows the user to migrate the Futurae account(s) currently enrolled in an existing Futurae Android SDK installation to a different device, or to the same one after erasing and reinstalling an app. This mechanism migrates the accounts using data which were backed up by the Android OS when the previous app installation had enrolled account(s).

On the fresh app installation, the SDK is able to identify if account migration is possible and return the number of accounts which can be migrated. In order to do so, invoke the following method:

FuturaeClient.sharedClient().checkAccountMigrationPossible(new FuturaeResultCallback<Integer>() {
  @Override
  public void success(Integer numAccounts) {
    // Account migration is possible - unsigned integer indicates the number of accounts to be migrated to this device
  }

  @Override
  public void failure(Throwable throwable) {
    // Checking for account migration eligibility failed. Handle the error
  }
});

To execute account migration invoke the following method. The migrated accounts (i.e., Futurae user ids) will be returned, if successful:

FuturaeClient.sharedClient().executeAccountMigration(
  new FuturaeResultCallback<AccountsMigrationResource.MigrationAccount[]>() {
    @Override
    public void success(AccountsMigrationResource.MigrationAccount[] result) {
      // Account migration finished successfully - array of all Futurae user_ids which were migrated successfully
    }

    @Override
    public void failure(Throwable throwable) {
      // Account migration failed. Handle the error
    }
  }
);

IMPORTANT: In order for account migration to be feasible on the new device, the following are required:

  • The migration data of the SDK in the previous app installation must have been previously backed up, so that the SDK in the fresh app installation can retrieve them. See Enabling SDK Backup and Restore for instructions on how to achieve this.
  • The SDK in the new app installation must have no other accounts currently or previously enrolled.

You may catch exceptions thrown by the checkAccountMigrationPossible() and executeAccountMigration() methods by catching com.futurae.sdk.AccountsMigrationException or for specific cases the following exceptions that inherit from it:

  • com.futurae.sdk.AccountsMigrationAccountsExistException: Indicates that account migration is not possible due to at least one account currently existing on the device.
  • com.futurae.sdk.AccountsMigrationAccountsPreviouslyEnrolledException: Indicates that account migration is not possible due to at least one account having previously been enrolled on the device.
  • com.futurae.sdk.AccountMigrationNoMigrationInfoException: Indicates that account migration is not possible due to no account migration data availability.
  • com.futurae.sdk.AccountsMigrationUnexpectedException: Indicates that a an unexpected error occurred during checking or executing account migration.

Enabling SDK Backup and Restore

In order for the Futurae Android SDK to be able to include the necessary data in the Android backup, as well as retrieve them, you need to create a BackupAgent class (extending android.app.backup.BackupAgent) and declare it in your AndroidManifest.xml file as follows:

<application
  android:allowBackup="true"
  android:backupAgent="<PATH_TO_BACKUPAGENT_CLASS>">

In your BackupAgent class make sure to override onBackup(...) and onRestore(...) like in the following example. If you want to backup and restore only Futurae related data, invoke the onBackupAccounts() inside onBackup(...) and onRestoreAccounts() inside onRestore(...). On the other hand, if you have your own data to backup and restore, then during onRestore(...) iterate the keys inside BackupDataInput and pass the entity data to the SDK’s onRestoreAccountsData(...):

@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) {
  try {
    // App-specific backup logic, if you have any, goes here...

    BackupAgent.onBackupAccounts(this, oldState, data, newState);
  } catch (IOException e) {
    // Handle exception
  }
}

@Override
public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) {
  try {
    // If your app backs up data that you want to restore in your own code by iterating data keys/values,
    // then all the data your app code doesn't handle must be passed to BackupAgent.onRestoreAccountsData(Context,BackupDataInput).
    // For a detailed implementation example, check our public demo app.
    //
    // Otherwise let the SDK handle the migration entirely by calling BackupAgent.onRestoreAccounts().
    BackupAgent.onRestoreAccounts(this, data, appVersionCode, newState);
  } catch (IOException e) {
    // Handle exception
  }
}

The signatures of the two methods are the following:

public static void onBackupAccounts(Context context, ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) throws IOException
public static void onRestoreAccounts(Context context, BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException