Enable Tap to Phone Android SDK

Enable Tap to Phone payments on your platform's Android application

❗️

The Tap to Phone Android SDK is currently in Beta.

Rainforest reserves the right to introduce breaking changes during this period. You will be notified of any updates prior to the release.

Please contact Rainforest support or your Platform Success Manager for more information on this feature.

✔️

Feature requirements

🔐 Rainforest must enable the platform to access this feature

💲 Billing fees associated to this feature

Implement Tap to Phone Android SDK into your platform's Android application with five steps:

  • Provide Rainforest your application information for Tap to Phone onboarding
  • Install SDK dependencies
  • Set up your application to use the SDK

Tap to phone onboarding


❗️

Android Tap to Phone onboarding may take up to 2 weeks

Please provide the following onboarding requirements as soon as possible. Onboarding is required to take Sandbox and Production payments.

In order to take Android Tap to Phone payments, Rainforest must perform Android Tap to Phone onboarding on your behalf. Rainforest will need you to provide the following information for onboarding:

  • App package name
  • App signing key fingerprint
  • App Google Play integrity keys

Package name

Your application's package name (example: com.rainforestpay.mobilepay)

Signing key fingerprint

You must generate a signing key and give us the fingerprint for the key. We only need the fingerprint, not the key itself.

# generate a new key
keytool -genkey -v -keystore my-signing-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-signing-key-alias
[provide keystore and key password when prompted]

# get fingerprint of key
keytool -exportcert -alias my-signing-key-alias -keystore my-signing-keystore.jks -storepass [password provided above] | \
    openssl sha256 -binary | \
    openssl base64

Google Play integrity keys

In order to verify your application and owner identity, we need to decrypt verification information from the Google Play Store.

Your app needs Play Integrity enabled:

  1. Go to app dashboard in the Play console
  2. Go to Test and release > App Integrity
  3. Select Link cloud project
  4. Follow prompts to link your project

Rainforest will need your Google Play Integrity keys to decrypt the Integrity Verification response:

  1. Go to app dashboard in the Play console
  2. Go to Test and release > App Integrity
  3. Play Integrity API Settings > Classic requests
  4. Choose option to "Manage and download my response encryption keys"
  5. Follow directions to download the decryption and verifications
  6. Provide Rainforest with the DECRYPTION_KEY and VERIFICATION_KEY values

Device Requirements

Certain features and criteria must be met to accept Tap to Phone payments on a device:

  • Android 11.0 (API level 30) or higher operating system.
  • Has NFC capabilities.
  • Has location permissions enabled for host application.
  • Has bluetooth permissions enabled for host application.
  • Has identity security enabled on the device via face recognition, fingerprint or passcode.

Import SDK dependencies


Use our maven repos

Rainforest hosts its SDK in a Gitlab-provided Maven repository. Configure your application with the maven repo URL

# settings.gradle.kts

repositories {
    google()
    mavenCentral()
    # CloudCommerce AAR
    maven { url = uri("https://gitlab.com/api/v4/projects/77749278/packages/maven") }
    # Rainforest SDK AAR
    maven { url = uri("https://gitlab.com/api/v4/projects/77784047/packages/maven") }
}

Install Rainforest SDK dependencies

The Rainforest Tap UI utilizes the Jetpack Compose library. The dependency should be configured and enabled.

  1. Add Compose at the project level
    # build.gradle.kts
    
    plugins {
        alias(libs.plugins.android.application) apply false
        alias(libs.plugins.kotlin.android) apply false
        alias(libs.plugins.kotlin.compose) apply false
    }
  2. Apply and enable Compose at the module level
    # app/build.gradle.kts
    
    plugins {
        alias(libs.plugins.android.application)
        alias(libs.plugins.kotlin.android)
        alias(libs.plugins.kotlin.compose)
    }
    
    ...
    
    android {
        buildFeatures {
            compose = true
        }
    }
    
    ...
    
    dependencies {
        implementation(platform(libs.androidx.compose.bom))
        implementation(libs.androidx.compose.ui)
        implementation(libs.androidx.compose.ui.graphics)
        implementation(libs.androidx.compose.ui.tooling.preview)
        implementation(libs.androidx.compose.material3)
    
        debugImplementation(libs.androidx.compose.ui.tooling)
    }

Add permissions

Add required permissions to app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.NFC" />

Application setup


Application inheritance

Your application must inherit from TapToPhoneApplication. Inheriting from TapToPhoneApplication will require implementing the getPaymentsEnvironment function.

package com.rainforestpay.capyshopandroid

import android.util.Log
import com.rainforestpay.sdk.Environment
import com.rainforestpay.sdk.tap.TapToPhoneApplication

class ExampleApplication : TapToPhoneApplication() {
    override fun getPaymentsEnvironment(): Environment {
        return Environment.SANDBOX
    }
}

Session permissions

Create a session to grant the SDK permissions to process a payin with the permission group payment_sdk and pass the session_key into the Rainforest SDK.

"statements": [
  {
    "permissions": ["group#payment_sdk"],
    "constraints": {
      "merchant": {
        "merchant_id": "REPLACE_ME"
      }
    }
  }
]

Device registration

Each device with your platform's application must be registered as a Rainforest device registration.

Devices must be registered to a merchant in order to process payments, which is completed via the create device registration endpoint. You'll need to pass:

  • registration_code: set to ANDROID_SDK
  • merchant_id: the merchant to process payments on with the device
  • device_name: the friendly name of the device, this will only appear in the Rainforest API and not in any Tap to Phone flows
{
    "registration_code": "ANDROID_SDK",
    "merchant_id": "sbx_mid_example",
    "device_name": "Example device"
}

The Device Registration ID will be utilized when presenting a payin and initiating the Tap to Phone payment flow through the Rainforest SDK. You should create a Rainforest Device Registration when your application is downloaded to the Android device and represents that specific Android device.

Each device that will utilize the Rainforest SDK for Tap to Phone must have it's own unique Rainforest Device Registration ID and cannot be shared across devices. Only one payin can be presented at a time on a Rainforest Device Registration.

Implementing the payment flow

1. Create a TapToPhone instance

To do this you will need:

  • a session key with the correct permissions

  • a device registration ID

    You will create this instance early in the application lifecycle. It will also need to be created when you have a new session key.

    val tapToPhone = RainforestPay.tapToPhone(context, environment, deviceRegistrationId, sessionKey)
    
    // where context is an instance of `android.app.Activity`

2. Prepare the device to take a tap payment

You will prepare the SDK at the start of your checkout flow

val prepareResult = tapToPhone.prepare()

3. Present payin using TapDialog

Presenting a payin requires:

  • an initialized and prepared instance of the TapToPhone class
  • a payin config ID

Render the payin when you're ready to start the tap transaction

TapCardDialog(
    activity = activity,
    ttp = ttp,
    payinConfigId = payinConfigId,
    deviceRegistrationId = deviceRegistrationId,
    onSuccess = { paymentResponse ->
        Log.d("TapUiDialog", "TapUiDialog onSuccess: $paymentResponse")

    },
    onError = { errMsg ->
        Log.d("TapUiDialog", "TapUiDialog onError: $errMsg")
    },
    onCancel = {
        Log.d("TapUiDialog", "TapUiDialog onCancel")
    }
)

SDK Reference


RainforestPay

MethodReturnsDescription
tapToPhone(ctx: Context, env: Environment, deviceRegistrationId: String, sessionKey: String)TapToPhoneInterfaceCreates the TTP instance; call when you have a new session

Environment (enum)

SANDBOX · PRODUCTION


TapToPhoneInterface

Properties

PropertyTypeDescription
isPreparedStateFlow<Boolean>true after a successful prepare() call
eventsFlow<TtpEvent>Stream of lifecycle events; collect to drive custom UI

Methods (all suspend unless noted)

MethodReturnsDescription
checkPermissions()CheckPermissionsResultChecks device permissions (biometrics, Bluetooth, Location); returns result showing which permission the device has.
setup()SetupResultChecks device permissions; runs prepare() on first call
prepare()PrepareSessionFetches auth token + merchant data; initializes Mastercard SDK
presentPayin(activity, payinConfigId)PaymentResponseLoads PayinConfig, captures NFC tap, polls until terminal status. This is called by the TapDialog
cancelPresented()UnitCancels an in-progress ta

TapUI (Composable)

Built-in Compose dialog. Requires ttp.isPrepared == true.

TapUI(
    activity: Activity,
    ttp: TapToPhoneInterface,
    payinConfigId: String,
    deviceRegistrationId: String,
    onSuccess: (PaymentResponse) -> Unit,
    onError: (Exception) -> Unit,
    onCancel: () -> Unit,
    autoDismissOnComplete: Boolean = false,   // skips post-tap result screens and returns control by to host app to display results
)

TtpEvent (sealed interface)

Events emitted in order during a normal transaction:

EventPayloadDescription
Preparingmessage: Stringprepare() started
Preparedsession: PrepareSessionDevice ready to accept a tap
PayinConfigLoadedcfg: PayinConfigResponseDataPayinConfig fetched
PresentingStartedmessage: StringNFC reader active
TapStartedmessage: StringCard detected
TapCompletemessage: StringTap data captured
Approvedmessage: StringPayin approved
Declinedreason: StringPayin declined
Canceledmessage: StringFlow canceled
Errormessage: StringError during flow
Infomessage: StringInformational/debug event

Collect from ttp.events to drive custom UI state.


PaymentResponse

data class PaymentResponse(
    val status: PaymentResponseStatus,  // SUCCESS | FAILURE
    val payin: PayinData,
)
// Convenience:
val isSuccess: Boolean
val isFailure: Boolean
data class PayinData(
    val payinId: String,
    val status: String,   // "PROCESSING" | "FAILED" | "CANCELED"
    val amount: Int,      // in cents
)

RainforestException

Thrown by TTP methods on failure.

class RainforestException(
    val code: RainforestErrorCode,
    message: String,
    cause: Throwable? = null,
)
CodeMessage
APIAPI request failed
APP_CONFIGURATIONDevice verification failed. Please try re-installing the app. If that does not work, contact support.
AUTHORIZATIONPreparation has expired. Please prepare again.
CARD_READERThere a failure when trying to read the card. Often because the card is not held in place long enough to full read the card.
CARD_READER_SESSIONCard reader session error
DATAThere was an issue loading required data. Please try again. If this continues to happen, please contact support.
DEVICE_IN_USEThe device registration is already presenting. Cancel the presented payin to continue.
DEVICE_INSECUREA security issue has been found with the device. See error message for details.
DEVICE_INSECURE_ENVIRONMENTThe device runtime environment has insecure setup.
DEVICE_INSECURE_IDENTITYThe device requires passcode, fingerprint, or face recognition security to accept Tap to Phone payments.
INVALID_PAYIN_CONFIGInvalid payin config
LOCATIONCannot determine location. Location is required to accept Tap to Phone payments.
MERCHANTMerchant is invalid. Contact support.
MISSING_PERMISSION_BLUETOOTHThe device does not have bluetooth permissions enabled.
MISSING_PERMISSION_LOCATIONThe device does not have location permissions enabled.
NOT_READYSDK not prepared
NOT_SUPPORTEDTap to Phone payments are not supported on this device.
NOT_SUPPORTED_NFCNFC is not supported on this device.
PAYIN_CANCELEDPayin canceled
SERVICESomething went wrong on our end. Please try again. If this continues to happen, please contact support.
TIMEOUTAn operation timed out. Please try again or contact customer support.
UNKNOWNUnknown error

TapToPhoneApplication (abstract)

Your Application class must extend this class and implement the getPaymentsEnvironment() method.

class MyApp : TapToPhoneApplication() {
    override fun getPaymentsEnvironment(): Environment = Environment.SANDBOX
}


Did this page help you?