Skip to content

Integrating the Tapkey Mobile SDK for Android

Latest Version

The latest version of the Tapkey Mobile SDK for Android is 2.39.3.0

Warning

This documentation refers to version 2.39.3 and later. This documentation may not be appropriate for older versions. Take a look at the upgrade section for upgrading to the latest version of the Tapkey Mobile SDK.

Sample App

A Tapkey Mobile SDK sample app for Android is available on GitHub.

Requirements

The Tapkey Mobile SDK 2.39.3 has been tested and compiled against Android SDK versions as follows:

API Level Notice
Target SDK Version 34 (Android 14) The value configured as targetSdkVersion.
Compile SDK Version 34 (Android 14) The value configured as compileSdkVersion.
Minimum SDK Version 19 (Android 4.4) The minimum Android API Level currently supported by the Tapkey Mobile SDK and configured as minSdkVersion.
Kotlin - The Tapkey Mobile SDK for Android is written in Java therefore isn't dependent on any Kotlin APIs.

Minimum Version Policy

The Tapkey Mobile SDK for Android officially supports and is tested against the three latest major versions of Android. E.g. if the current version of Android is 14, then the Tapkey Mobile SDK for Android is tested against Android Version 12.0 and newer. Usually much older versions are supported on best effort as well, but this could be discontinued at any time, should technical restrictions make this necessary.

Adding Dependencies

The Tapkey Mobile SDK is published in a private Maven repository. To tell Gradle where to find the artifacts, add https://maven.tapkey.com as repository and add the latest version of com.tapkey.android:Tapkey.MobileLib as dependency to the project's build.gradle file.

repositories {
    maven { url "https://maven.tapkey.com" }
}

dependencies {
    implementation 'com.tapkey.android:Tapkey.MobileLib:2.39.3.0'
}

android {
    
}


Bootstrapping the SDK

The Tapkey Mobile SDK expects the Application class of the target App to implement the TapkeyAppContext interface, which returns a singleton instance of the AndroidTapkeyServiceFactory. The singleton should be created in the Application.onCreate() method using the TapkeyServiceFactoryBuilder. As the Tapkey Mobile SDK needs to communicate with the Tapkey Trust Service, the android.permission.INTERNET permission has to be added to the App Manifest.

  1. Let the Application implement TapkeyAppContext.
  2. Use TapkeyServiceFactoryBuilder to build an instance of TapkeyServiceFactory in Application.onCreate().
  3. Implement getTapkeyServiceFactory() which returns the TapkeyServiceFactory singleton.

public class App extends Application implements TapkeyAppContext {

    /*
     * The TapkeyServiceFactory holds all required services.
     */
    private TapkeyServiceFactory tapkeyServiceFactory;

    @Override
    public void onCreate() {
        super.onCreate();

        /*
         * Create an instance of TapkeyServiceFactory. Tapkey expects that a single instance of
         * TapkeyServiceFactory exists inside an application that can be retrieved via the
         * Application instance's getTapkeyServiceFactory() method.
         */
        TapkeyServiceFactoryBuilder b = new TapkeyServiceFactoryBuilder(this);
        this.tapkeyServiceFactory = b.build();
    }

    @Override
    public TapkeyServiceFactory getTapkeyServiceFactory() {
        return tapkeyServiceFactory;
    }
}
4. Add <uses-permission android:name="android.permission.INTERNET"/> to AndroidManifest.xml.

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

Logging In Users

The SDK takes a Tapkey access token to log in a user. Retrieving such an access token is part of the implementing application. Usually, either the Token Exchange or Authentication Code with PKCE grant type will be used. For more information about authenticating against Tapkey, take a look at the authentication section.

Once an access token has been obtained, it can be used to log in a user as outlined below:

UserManager userManager = tapkeyServiceFactory.getUserManager();
userManager.logInAsync("eyJhbGciOiJSUz…O-YbBq8F7086rQi-kEbERp4dA3r0WonpHnmYcXEnA", ct)
    .continueOnUi(userId -> {
        // User logged in, use user's ID here.
    });

Subsequent calls to userManager.getUsers() will yield a list of IDs of all logged-in users. In most applications, only one user will be logged in at a time.

String userId = userManager.getUsers().get(0);
// Fetch information about the user using the ID

Note that a token refresh handler must be registered with the TapkeyServiceFactory prior to logging in any users. This can be done using the TapkeyServiceFactoryBuilder's setTokenRefreshHandler(TokenRefreshHandler tokenRefreshHandler) method.

// In Application.onCreate():
TapkeyServiceFactoryBuilder b = new TapkeyServiceFactoryBuilder();
b.setTokenRefreshHandler(new TokenRefreshHandler() {
    @Override
    public Promise<String> refreshAuthenticationAsync(String userId, CancellationToken ct) {
        PromiseSource res = new PromiseSource();

        asynchronouslyUpdateTheAccessTokenViaCustomAppLogic(
            newAccessToken -> res.setResult(newAccessToken),
            exception -> {
                if (isPersistentError(exception))
                    throw new TkException (AuthenticationHandlerErrorCodes.TokenRefreshFailed);
                else
                    res.setException(exception);
            }
        );

        return res.getPromise();
    }

    @Override
    public void onRefreshFailed(String userId) {
        /*
         * Will be called if re-authentication failed and a manual call to
         * updateAccessToken() is required.
         */
    }
});
this.tapkeyServiceFactory = b.build(this);

Searching for Nearby Locks

Searching for nearby locks can be done with the SDK's BleLockScanner. For more details or custom implementation please read the BLE Scanning section of the Documentation.

An instance of BleLockScanner can be obtained from the TapkeyServiceFactory.

Android Permissions required

Depending on the Android version the app is running on, different permissions are required to scan for and communicate with BLE devices. If case the reqired permissions haven't been granted, scanning does not fail but rather returns an empty list of nearby devices. So if you're sure that you have devices nearby but they don't show up, please check whether your app has been granted all the required permissions.

Read More

BleLockScanner scanner = tapkeyServiceFactory.getBleLockScanner();

// request permissions e.g. via ContextCompat.checkSelfPermission(...)

// Returns an observer registration to stop scanning once finished.
bleScanObserverRegistration = scanner.startForegroundScan();

To observe locks entering and leaving the range of this device, the BleLockScanner's getLocksChangedObservable() method can be used.

// Listen for Tapkey locks coming into or leaving range.
nearbyLocksObserverRegistration = bleLockScanner.getLocksChangedObservable()
    .addObserver(locks -> {
        // Handle nearby locks here, e.g. present them to the user.
    });

// Alternatively, getLocks() can be used to get a list of nearby locks in this moment.
nearbyLocks = bleLockScanner.getLocks();

Triggering a Lock

After a nearby lock was found with the BleLockScanner, it can be opened using the trigger lock command, which is available from the CommandExecutionFacade. Any command inside the command execution facade, requires a TLCP connection to a lock. The following example uses BleLockCommunicator to establish a TCLP connection via BLE.

// The BLE lock manager establishes a connection to the lock which is passed to the
// CommandExecutionFacade to execute a trigger lock command.
return bleLockCommunicator.executeCommandAsync(
    bluetoothAddress, physicalLockId, tlcpConnection -> {

    // With the TlcpConnection to the lock established, the CommandExecutionFacade
    // asynchronously executes the trigger lock command.
    return commandExecutionFacade.triggerLockAsync(
        tlcpConnection,
        ct);
}, ct)
.continueOnUi(commandResult -> {
    switch (commandResult.getCommandResultCode()) {
        case Ok:
            return true;

        // Other cases must be handled here.
        
    }

    // Let the user know, something went wrong.
    
    return false;
})
.catchOnUi(e -> {
    Log.e(TAG, "Could not execute trigger lock command.", e);

    if (!ct.isCancellationRequested()) {
        // Handle any exceptions and let the user know, something went wrong.
        
    }
    return false;
});

Logging

By default the Tapkey Mobile Lib writes its logs to android.util.Log so they end up in Android LogCat. To be able to collect logs within the app, a custom logger can be used instead.

Info

A custom logger replaces the Tapkey default logger, therefore logs won't be written to LogCat anymore in such cases.

Create a custom implementation of the com.tapkey.mobile.utils.Logger.

public class CustomLogger implements com.tapkey.mobile.utils.Logger {
    @Override
    public void println(int priority, String tag, String msg, Throwable tr) {
        // Custom logging implementation
    }
}

The priority is divided in following static priority levels:

com.tapkey.mobile.utils.Logs.VERBOSE
com.tapkey.mobile.utils.Logs.DEBUG
com.tapkey.mobile.utils.Logs.INFO
com.tapkey.mobile.utils.Logs.WARN
com.tapkey.mobile.utils.Logs.ERROR

Add a instance of the custom implementation to com.tapkey.mobile.utils.Logs. This should be done preferably before creating the TapkeyServiceFactoryBuilder to avoid lost logs during bootraping.

    @Override
    public void onCreate() {
        super.onCreate();

        com.tapkey.mobile.utils.Logs.setLogger(new CustomLogger());

        TapkeyServiceFactory tapkeyServiceFactory = new TapkeyServiceFactoryBuilder(this)
            ...
            .build();

        ...
    }