Integrate SDK

Integrate with Tyro Embedded Payments SDK to accept in-person payments using a compatible Android device. You will first need to implement Account Authorisation. An open-source example app is available at https://github.com/tyro/tyro-tap-to-pay-sdk-android.

Overview of Embedded Payments Android SDK Flow

Android Embedded Payments Flow

Integration

Github access

Tyro Embedded Payments SDK is distributed via Github Packages, so you will need a Github account. Follow these steps to create a Personal Access Token (PAT). A 'classic' token with (at least) public_repo scope is sufficient. Once you have created your PAT, you will need to reference it from your Android project. You can do this using environment variables, as in the example below.

In settings.gradle add the Tyro repository:

kotlingroovy
Copy
Copied
dependencyResolutionManagement {
    repositories {
        maven {
            url = uri("https://maven.pkg.github.com/tyro/tyro-tap-to-pay-sdk-android")
            credentials {
                username = System.getenv("GITHUB_PACKAGES_USER")
                password = System.getenv("GITHUB_PACKAGES_PASSWORD")
            }
        }
    }
}
Copy
Copied
dependencyResolutionManagement {
    repositories {
        maven {
            url 'https://maven.pkg.github.com/tyro/tyro-tap-to-pay-sdk-android'
            credentials {
                username System.getenv("GITHUB_PACKAGES_USER")
                password System.getenv("GITHUB_PACKAGES_PASSWORD")
            }
        }
    }
}

In build.gradle add the Tyro dependency:

kotlingroovy
Copy
Copied
val tyroSdkVersion by extra("<VERSION>")

dependencies {
    // ...
    debugImplementation("com.tyro:tyro-tap-to-pay-sdk-debug:$tyroSdkVersion")
    releaseImplementation("com.tyro:tyro-tap-to-pay-sdk-release:$tyroSdkVersion")
}
Copy
Copied
ext { set('tyroSdkVersion', '<VERSION>') }

dependencies {
    // ...
    debugImplementation "com.tyro:tyro-tap-to-pay-sdk-debug:${tyroSdkVersion}"
    releaseImplementation "com.tyro:tyro-tap-to-pay-sdk-release:${tyroSdkVersion}"
}

Accept tyroDebug build type

Tyro publishes two dependencies:

  • tyro-tap-to-pay-sdk-debug
  • tyro-tap-to-pay-sdk-release

The release dependency includes some additional security checks. Most notable of these is that it requires on-device developer mode to be disabled.

The debug build published by Tyro does not have this requirement, making testing easier. It is, however, obfuscated and non-debuggable. You will need to configure your debug build type to accept tyroDebug as a fallback.

kotlingroovy
Copy
Copied
android {
    ...
    buildTypes {
        ...
        debug {
            ...
            matchingFallbacks += listOf("tyroDebug")
        }
    }
}
Copy
Copied
android {
    ...
    buildTypes {
        ...
        debug {
            ...
            matchingFallbacks.add("tyroDebug")
        }
    }
}

R8 Support

Tyro Embedded Payments SDK does not currently support R8 full mode. You may need to include the following line in gradle.properties.

Copy
Copied
android.enableR8.fullMode=false

Demonstration App

The demo app has three build flavors:

  • stub
  • dev
  • prd

The app should run in stub flavor out of the box.

To run against the development environment:

  • Change the applicationId in build.gradle to com.tyro.taptopay.sdk.demo.
  • Use the sample app keystore and keystore password you have been provided during onboarding.
  • Implement authentication with Tyro on your own server.

To run in a production environment:

  • Change the applicationId in build.gradle to your own
  • Include your own keystore, and update the signingConfigs part of build.gradle with your keystore details
  • Export a public certificate from your keystore, and provide it to Tyro along with your applicationId

See below for more detail on these requirements.

Verification data

Tyro requires the following in order to verify the integrity of your app. These must be provided even to run the app against the Tyro test environment.

  • Your application ID
  • Your upload public certificate

Application ID

This is the applicationId as defined in your build.gradle file.

Copy
Copied
android {
    // ...
    defaultConfig {
        // ...
        applicationId = "com.example.my.app" // <-
    }
}

Public certificate

The public certificate is derived from the upload keystore specified in build.gradle:

Copy
Copied
android {
    // ...
    signingConfigs {
        create("my_signing_config") {
            keyAlias = "my_key"
            keyPassword = "p@ssw0rd"
            storeFile = file("my.keystore")
            storePassword = "p@ssw0rd"
        }
    }
}

Follow these instructions to create your own upload keystore if required. You can export the public certificate from the keystore using keytool:

Copy
Copied
keytool -export -keystore tyro.keystore -alias my_alias -rfc -file public.pem

Your server — add an endpoint to create a connection

When the Android App is first initialised, a request must be sent to your server to establish a Tyro Embedded Payments connection. Upon receiving the client request, authenticate your user and send the request to Tyro with the readerId in the request body (obtained from Account Authorisation). The Embedded Payments connection response will return a connectionSecret, this should be returned to your App.

Copy
Copied
// Node sample code
const express = require("express");
const app = express();
const axios = require('axios');

// ...

app.post("/create-connection", async (req, res) => {
  const { userIdOrDeviceId } = req.body; // You can associate a user or device to the reader.
  // You will manage the authentication between your server and App.

  const readerId = await this.findReaderIdForUser(userIdOrDeviceId);

  // Create a Embedded Payments connection by providing the location Id
  const connectionResponse = await axios.post('https://api.tyro.com/connect/tap-to-pay/connections',
  {
    "readerId": readerId // e.g. 2688fcf2-44dd-4c72-88ac-79d0910f2933
  },
  {
    headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer exampleJwt'
    }
  });

  res.send({
    connectionSecret: connectionResponse.connectionSecret
  });
});

Implement ConnectionProvider

The ConnectionProvider is responsible for fetching the Tyro connection secret from your server. The following example uses a Ktor client and kotlinx serialisation.

Copy
Copied
class MyConnectionProvider: ConnectionProvider {

    @Serializable
    private data class MyResponse(
        val connectionSecret: String
    )

    private val client = HttpClient(CIO) {
        install(ContentNegotiation) { json() }
    }

    override suspend fun createConnection(): String {
        val url = "https://<YOUR-API-DOMAIN>/create-connection"
        val response: MyResponse = client.get(url).body()
        return response.connectionSecret
    }
}

Create an instance of TapToPaySdk

Define the sdk as a variable in your Application class and create an instance inside the onCreate() method.

Copy
Copied
class SdkDemoApplication : Application() {
    lateinit var tapToPaySDK: TapToPaySdk

    override fun onCreate() {
        super.onCreate()
        tapToPaySDK = createTapToPaySdk()
    }

    @Suppress("KotlinConstantConditions")
    private fun createTapToPaySdk(): TapToPaySdk {
        val tyroEnv: TyroEnv =
            when (BuildConfig.FLAVOR) {
                "stub" -> TyroEnvStub()
                "dev" ->
                    TyroEnvDev(
                        connectionProvider = SdkDemoConnectionProvider(),
                    )
                else ->
                    TyroEnvProd(
                        connectionProvider = SdkDemoConnectionProvider(),
                    )
            }
        return createInstance(tyroEnv, applicationContext, TyroOptions(TyroScreenOrientation.PORTRAIT)).apply {
            setPosInfo(
                PosInfo(
                    posName = "Demo",
                    posVendor = "Tyro Payments",
                    posVersion = "1.0",
                    siteReference = "Sydney",
                ),
            )
        }
    }
}

There are three environments available:

  • stub (TyroEnvStub)
  • development (TyroEnvDev)
  • production (TyroEnvProd)

The stub environment does not interact with the Tyro backend at all, so does not require a ConnectionProvider. It may be useful for UI development etc. Return values and delays can be customised to help with testing.

In the onCreate method of your activity

Important: your Activity will need to be a ComponentActivity (or one of its subclasses)

Copy
Copied
private lateinit var transactionLauncher: ActivityResultLauncher<TransactionRequest>
// ...

override fun onCreate(savedInstanceState: Bundle?) {
    // ...

    // register a handler for transaction results
    tapToPaySdk.registerTransactionResultHandler(this) { transactionResult ->
        when (transactionResult.status) {
            TransactionStatus.TXN_SUCCESS -> handleTransactionSuccess(transactionResult)
            else -> handleTransactionFailure(transactionResult)
        }
    }

    // initialise the Tyro Embedded Payments SDK
    // this could take some time - you will need to show a loading screen or similar
    showLoadingScreen()
    tapToPaySdk.init(this) { initResult ->
        hideLoadingScreen()
        when (initResult.status) {
            InitStatus.INIT_SUCCESS -> handleInitSuccess(initResult)
            else -> handleInitFailure(initResult)
        }
    }
}

Admin Settings

Create a button in your screen, use updateAdminSettings method to start the admin settings activity. This screen allows your POS administrators to set a mandatory refund password and additional settings in the future.

Copy
Copied
tapToPaySdk.updateAdminSettings(activity)

Making Payments

Start a new transaction

Copy
Copied
val transactionRequest = TransactionRequest(
    type = TransactionType.TRANSACTION,
    amountInCents = amountInCents,
    reference = "my-unique-transaction-reference",
)
tapToPaySdk.startTransaction(activity, transactionRequest)

Start a new refund

Copy
Copied
val transactionRequest = TransactionRequest(
    type = TransactionType.REFUND,
    amountInCents = amountInCents,
    reference = "my-unique-transaction-reference"
)
tapToPaySdk.startTransaction(activity, transactionRequest)

Register Webhooks

Webhook events are sent once a payment has occurred. Your server should listen to these events and handle them as required, for example to send a payment receipt email.

Tyro UI

A Tyro UI will be visible from when a transaction is initiated until it is complete. Please note final designs are still pending.

Android UI verifying Android UI Embedded Payments Android UI authorising

Copyright © Tyro Payments 2019-2024. All right reserved.