Integrating the Tapkey Mobile SDK for Android¶
Latest Version
The latest version of the Tapkey Mobile SDK for Android is 2.44.0.0
Warning
This documentation refers to version 2.44.0
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.44.0
has been tested and compiled against Android SDK versions as follows:
API Level | Notice | |
---|---|---|
Compile SDK Version | 35 (Android 15) | 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 15, then the Tapkey Mobile SDK for Android is tested against Android Version 13.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.44.0.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.
- Let the Application implement
TapkeyAppContext
. - Use
TapkeyServiceFactoryBuilder
to build an instance ofTapkeyServiceFactory
inApplication.onCreate()
. - Implement
getTapkeyServiceFactory()
which returns theTapkeyServiceFactory
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;
}
}
<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.
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();
...
}