Handle Tap and Pay transactions
A customer initiates a transaction when he or she taps their device on an NFC payment terminal. Open Fabric’s NFC SDK will intercept this transaction request and begin its interactions with your App. The App should then:
- Present initial transaction experience
- Perform user authentication, if needed
- Provide final confirmation to our SDK to hand over a payment token
- Present transaction in-progress experience
- Present transaction with terminal complete experience
Additionally, this document also covers ways by which your App can ensure that it is set up optimally to initiate transactions when the consumer tries to tap and pay - like for instance, set up as the default tap and pay provider, and your app is configured with appropriate foreground priority, etc.
The diagram below provides an overview of all the interactions between all the key systems/components during the interaction stage.
Handle Tap and Pay transactions
Present initial transaction experience
Whenever a user taps their phone at an NFC payment terminal, our SDK will intercept the transaction request, and will then call the onTransactionStart() callback on the NfcTransactionListener. The application will need to present the initial transaction experience to the user.
class TransactionListener: NfcTransactionListener {
override fun onTransactionStart(context: Context) {
PaymentActivity.displayPaymentStep(context, null)
}
...
}
Please refer to the integration sample app for a complete example.
Also note that the call to your NfcTransactionListener will only happen in either of the following cases:
- The user has set up your app as the default contactless payment app
- The foreground priority is enabled, your app's activities are in the foreground and they have the implementation for foreground priority
if (!HceHelper.isDefaultNfcPaymentApp(this)) {
if (HceHelper.isForegroundPriorityEnabled(this)) {
HceHelper.requestForegroundPaymentPriority(this)
}
}
Perform user authentication, if needed
Now, you are required to perform any user authentication as needed. Depending on the wallet settings, this may be triggered in the following scenarios:
- When it exceeds a certain threshold (authentication duration, number of transactions) since the last authentication.
- When payment terminals classify transactions as high value and require additional authentication.
When such authentication is required, the onCredentialsRequired() callback on the NfcTransactionListener will be called.
class TransactionListener: NfcTransactionListener {
...
override fun onCredentialsRequired(context: Context) {
ScreenUnlockAuthenticationPromptBuilder()
.setTitle("TITLE")
.setSubtitle("SUBTITLE")
.build(context)
}
...
}
Provide final confirmation to our SDK to hand over a payment token
After user authentication is provided or if authentication is not required, the transaction will proceed to the finalization stage. At this stage, you can perform any additional validation/confirmation before you can confirm the transaction (like amount/currency check, account validity, transit eligibility, location based checks, etc.). This can be performed upon receiving the onTransactionFinalization() callback on the NfcTransactionListener.
Please note that this callback is part of the transaction-critical processing thread, thus its implementation must be light and not blocking (e.g. synchronous network exchanges or UI interactions must not be implemented here).
Following is the signature of the callback:
class TransactionListener: NfcTransactionListener {
...
override fun onTransactionFinalization(context: Context, transaction: NfcTransaction): TransactionDecision {
if (notAllowed(transaction)) {
return TransactionDecision(TransactionOutcome.DECLINE)
}
return TransactionDecision(TransactionOutcome.PROCEED)
}
...
}
The callback is called with the following parameters:
| Name | Type | Description |
|---|---|---|
| context | Context | The current Context (Activity) |
| transaction | NfcTransaction | The current ongoing transaction |
Present In-progress experience
While the transaction is ongoing, the following callback might be called by the SDK, to provide the payment app with updates regarding the current transaction. You should use the onTransactionProgress() callback on the NfcTransactionListener to update the UI and provide feedback to users.
onTransactionProgress() callback function indicates that the initiated NFC transaction has successfully initiated transfer of the payment token with the terminal.
class TransactionListener: NfcTransactionListener {
...
override fun onTransactionProgress(context: Context, step: HceTransactionStep, apdu: String) {
// Optional: update the screen showing the current step
}
...
}
The callback is called with the following parameters:
| Name | Type | Description |
|---|---|---|
| context | Context | The current Context (Activity) |
| step | HceTransactionStep | The HceTransactionStep that has been completed, not null |
| apdu | String | The current APDU (Application Protocol Data Unit) value |
Present transaction with terminal complete experience
Once the NFC exchange between the SDK and the payment terminal is completed for the transaction, the onTransactionDone() callback on the NfcTransactionListener will be called.
After this step the payment terminal may perform proprietary checks and in most cases it proceeds to an online authorization request to the network. The SDK simply considers the NFC exchange with the payment terminal is complete and will not be aware of decisions taken afterwards.
class TransactionListener: NfcTransactionListener {
...
override fun onTransactionDone(context: Context, result: TransactionResult) {
// Presents Transaction with terminal complete experience
}
}
The callback is called with the following parameters:
| Name | Type | Description |
|---|---|---|
| context | Context | The current Context (Activity) |
| result | TransactionResult | The final NFC exchange result of the transaction |
If there is any error happening during the NFC exchange, for example if the customer chooses to cancel it or there is a connection issue with the terminal, the onTransactionError() callback on the NfcTransactionListener will also be called. The signature of the callback is as follows:
class TransactionListener: NfcTransactionListener {
...
override fun onTransactionError(context: Context, errorCode: string, exception: OpenFabricError?) {
// Display the error to user
}
}
App configuration for optimal payment initiation outcome
While the basic integration with the Android platform has been covered in the Getting Started section, our NFC SDK provides additional helpers, to help you build further integration with the Android platform to optimize the customer experience thereby resulting in an optimal payment initiation outcome.
Check and request to be the default payment provider app
The SDK provides the following methods to check whether the current app is set as the default payment app and to quickly launch the setting page for users to select it as the default payment app.
Your application can use the method HceHelper#isDefaultNfcPaymentApp() to check if the app is set as the default payment app on the customer’s device. The method returns a boolean value true/false, indicating the status.
The Android Platform does not allow an application to set itself as the default payment app without customer consent. However, we provide HceHelper#launchNfcPaymentSettings() and HceHelper#launchNfcPaymentSettingsForResult() convenience methods that the app can call to open the Android Settings page for Contactless Payment App.
Payment application selection menu
Multiple payment apps can be installed on the same device and Android OS setting menu allows the customer to select a default payment app for NFC/Contactless payments. The default payment app is the app the NFC transactions are redirected to by Android system when device is tapped on an active terminal.
This settings menu presents every payment app installed on the phone, with a description and a banner, so that users can select the one to set as the default payment app.
To provide your own app name and payment banner, add the following resource override in your application strings.xml:
<resources>
...
<string name="tapandpayNfcDescription">Open Fabric NFC Tap and Pay Sample</string>
<drawable name="tapandpayApduBanner">@drawable/my_payment_banner</drawable>
</resources>
The keys (tapandpayNfcDescription and tapandpayApduBanner) must be kept exactly as they are, but you can provide your own text/image as the values.
Handle transaction as non-default foreground contactless payment application
if (!HceHelper.isDefaultNfcPaymentApp(this)) {
if (HceHelper.isForegroundPriorityEnabled(this)) {
HceHelper.requestForegroundPaymentPriority(this)
}
}
Disable/Enable contactless payment feature
// Disable contactless payment feature
HceHelper.disableHceService()
// Enable contactless payment feature
HceHelper.enableHceService()