Skip to content

Synchronizing Tapkey NFC Transponders

This chapter describes how to synchronize Tapkey NFC Transponders using the Tapkey Mobile SDK for Android.

Only Tapkey NFC Transponders supported

Only NFC Transponder produced by Tapkey are supported. Empty NFC Transponder or those produced for a different purpose are not supported.

On Android, there are different modes in which the smartphone can work with NFC. For communication with NFC Transponder, the Reader/writer mode is used. The smartphone acts as an active NFC device to communicate with passive NFC Transponder.

This documentation explains how to use the Tapkey Mobile SDK for Android to synchronize Tapkey NFC Transponders, but does not discuss the basics of using NFC on Android.

For more details about NFC and Android, please refer to the Android NFC Documentation.

For more details about the Android NFC API, please refer to the Android NFC API Documentation.

General Concepts of Tapkey NFC Transponders

Tapkey NFC Transponders are individually encrypted and can only be read and written by the Tapkey Trust Service. Direct read/write access by smartphones or other parties is not possible. Therefore, in order to write data to a Tapkey NFC Transponder, an online connection between the server and the card is established. The mobile app acts as a relay between both by using the Tapkey Mobile SDK for Android.

sequenceDiagram participant CARD as Tapkey NFC Transponder participant APP as Client App participant TTS as Tapkey Trust Service APP -->> APP: Wait for Tapkey NFC Transponder CARD -->> APP: Tapkey NFC Transponder presented APP ->>+ TTS: Establish connection Note over TTS, CARD: Tapkey NFC Transponder is written by the Tapkey Trust Service loop Synchronization TTS -->> CARD: Send Data CARD -->> TTS: Receive Data end TTS ->>- APP: Connection Closed CARD -->> APP: Tapkey NFC Transponder removed

Managing Grants

Tapkey NFC Transponders are encrypted, and therefore grants cannot be directly written to Tapkey NFC Transponders using the SDK. Instead, grants are managed via the Tapkey Web API. After grants have been modified, affected Tapkey NFC Transponders need to be synchronized in order to apply the changes.

Setup Requisites

To use the NFC API of Android, it is required to declare the NFC feature and claim the NFC permission in the Android Manifest.

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.NFC" />
    <uses-feature android:name="android.hardware.nfc" android:required="false" />
    ...
</manifest>

Start Listening for Tapkey NFC Transponders

To start listening for Tapkey NFC Transponders, first retrieve the Android NfcAdapter.

NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(activity);

// Handle if the smartphone does not support NFC or NFC is disabled gracefully
if (nfcAdapter == null || !nfcAdapter.isEnabled()) {
    return;
}

The NFCAdapter will invoke the ReaderCallback on a Thread without a Looper. As synchronization requires a lot of asynchronous work, a Looper is required. Therefore, create a new Handler on which the work will be posted.

Handler handler = new Handler(Looper.getMainLooper());

To start listening for Tapkey NFC Transponders, call the enableReaderMode method on the NfcAdapter.

// Create a Bundle and apply any NFC workarounds if required
Bundle options = new Bundle();
NfcWorkarounds.applyNfcReaderModeOptions(this, options);

// Enable the reader mode and provide the callback, flags, and options
nfcAdapter.enableReaderMode(
    activity,
    tag -> handler.post(() -> handleNewTag(tag)),
    NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK,
    options
);

The handleNewTag method will be called for each new tag that is discovered.

Stop Listening for Tapkey NFC Transponders

To stop listening for Tapkey NFC Transponders, call the disableReaderMode method on the NfcAdapter.

if (nfcAdapter == null) {
    return; 
}

nfcAdapter.disableReaderMode(activity);

Begin NFC Session

Synchronizing a Tapkey NFC transponder can take several seconds. As it happens quite frequently that the connection between the smartphone and the NFC transponder is lost temporarily while the synchronization is ongoing due to factors like tag movement, the Tapkey Mobile SDK provides functionality to continue the process, as soon as the NFC connection is reestablished. This is achieved by using the RecoverableIsoDepConnection interface.

First, retrieve the CardManager from the Tapkey ServiceFactory. Then, create an IsoDepConnection from the detected NFC tag using the NfcUtils.getIsoDepConnectionForDesfire(tag) method. If the returned IsoDepConnection is null, it indicates that the NFC tag technology is not supported.

RecoverableIsoDepConnection recoverableIsoDepConnection;

public void handleNewTag(Tag tag) {
    // Retrieve the CardManager from Tapkey ServiceFactory
    CardManager cardManager = tapkeyServiceFactory.getCardManager();

    // Create an IsoDepConnection from the detected NFC Tag
    IsoDepConnection isoDep = NfcUtils.getIsoDepConnectionForDesfire(tag);

    // If the returned IsoDepConnection is null, the NFC Tag is not supported
    if (isoDep == null) {
        return;
    }

    if (recoverableIsoDepConnection == null) {
        // If no synchronization has been started yet,
        // create a new RecoverableIsoDepConnection.
        // This allows you to continue the synchronization if the tag was lost or the connection was interrupted.
        recoverableIsoDepConnection = NfcUtils.createRecoverableIsoDepConnection(tag.getId());

        // Subscribe to the State observable to guide the user through the synchronization process
        recoverableIsoDepConnection.getOnStateChanged().addObserver(state -> {
            switch (state) {
                case WaitingForTag:
                    // Indicate that the user should present the NFC Tag
                    break;
                case Normal:
                    // Indicate that synchronization is ongoing
                    break;
                case Completed:
                    // Indicate that synchronization is completed
                    break;
                case WrongTag:
                    // Indicate that the wrong NFC Tag was presented and the synchronization
                    // cannot be continued until the original NFC Tag is presented.
                    break;
            }
        });

        // Pass the RecoverableIsoDepConnection to the methods of `CardManager` to perform actions on the card
        cardManager.syncCardAsync(userId, tag.getId(), recoverableIsoDepConnection,  ....)
        ...;
    }

    // Whenever a Tag is discovered, pass it to the `RecoverableIsoDepConnection` to start or continue the connection.
    recoverableIsoDepConnection.replaceConnection(tag.getId(), isoDep);
}

In the code snippet above, tag represents the Tag object obtained from the operating system. The RecoverableIsoDepConnection instance, recoverableIsoDepConnection, is used to manage the NFC connection and handle potential interruptions. By subscribing to the state observable, you can provide appropriate user guidance based on the different states of the synchronization process.

Ensure that you pass the RecoverableIsoDepConnection to the relevant methods of the CardManager for performing actions on the Tapkey NFC Transponder. The synchronization process can be initiated by calling cardManager.syncCardAsync(userId, tag.getId(), recoverableIsoDepConnection, ...).

Synchronize Tapkey NFC Transponders

To synchronize a Tapkey NFC Transponder, you can use the syncCardAsync method of the CardManager and pass the previously created RecoverableIsoDepConnection instance. The syncCardAsync method returns a Promise that resolves when the synchronization is successfully completed or rejects if the synchronization fails.

// The RecoverableIsoDepConnection that was created earlier
RecoverableIsoDepConnection recoverableIsoDepConnection = ...;

cardManager.syncCardAsync(userId, tag.getId(), recoverableIsoDepConnection, progress -> {
    // Progress has changed
    displayProgress(progress);
}, CancellationTokens.None)
    .continueOnUi(aVoid -> {
        // Synchronization completed
        displaySuccess();
        return null;
    })
    .catchOnUi(e -> {
        // Synchronization failed
        displayError(e);
        return null;
    })
    .conclude();

You can monitor the progress of the synchronization by providing a callback function that receives the progress updates. In this example, the displayProgress(progress) function is called with the updated progress value.

Register a Tapkey NFC Transponder

Before a grant can be assigned to a Tapkey NFC Transponder, the card needs to be registered to the owner's account. To accomplish this, you can use the takeCardOwnershipAsync method of the CardManager class and provide the owner's account ID and the previously created RecoverableIsoDepConnection instance.

Transponder must be unassigned

Please note that the Tapkey NFC Transponder must either be unassigned or not have any grants assigned to it. If the card is already assigned to another owner's account and has grants, the grants must be removed by the current owner before this operation can succeed.

// The RecoverableIsoDepConnection that was created earlier
RecoverableIsoDepConnection recoverableIsoDepConnection = ...;

cardManager.takeCardOwnershipAsync(userId, ownerId, tag.getId(), recoverableIsoDepConnection, progress -> {
    displayProgress(progress);
}, CancellationTokens.None)
.continueOnUi(aVoid -> {
    // sync completed
    displaySuccess();
    return null;
})
.catchOnUi(e -> {
    // sync failed
    displayError(e);
    return null;
})
.conclude();