Android

Add the Trustly UI to native Android apps
View as Markdown

The Trustly Lightbox SDK for Android allows you to quickly build a bank authorization workflow in your Android app. Integrate the Select Bank Widget or the Trustly Lightbox to retrieve bank authorization data that can be used with other Trustly APIs.

To use an example project for testing and learning, see the Android Example in GitHub.

If you need help with your integration, contact your Trustly representative or send your request to us.integrations@trustly.com.

PayWithMyBank references are deprecated. If your app is using PayWithMyBank, you must change it to Trustly.

Prerequisites

Android 15: Edge-to-edge display mode is the default behavior for Android 15 (API level 35) and later. If your app wasn’t designed for edge-to-edge display mode, critical elements of your app can be obscured. To ensure your app remains functional, you may need to use Window Insets to apply padding or margins to your layouts.

Authentication flow

The following diagram illustrates how the Trustly SDK manages the secure transition between your application, the SDK, and the banking institution.

StepDescription
AAuthentication launch
The SDK launches a secure browser overlay (Chrome Custom Tabs) or performs a direct App-to-App switch if the user has the target bank app installed.
BDeep Link return
The bank redirects the user back to your application using the App Link defined in metadata.deepLinkUrl. Android verifies the domain via Digital Asset Links and brings your LightboxActivity to the foreground.
CSDK resumption
Your onRestart override calls proceedToChooseAccount, prompting the SDK to verify the transaction status and trigger the onReturn callback.

Configure Gradle and Android dependencies

  1. To add the Trustly SDK and the AndroidX Browser Library with Chrome Custom Tabs to your project, open your build.gradle file and add the following dependencies:

    1// build.gradle
    2dependencies {
    3 implementation 'net.trustly:trustly-android-sdk:4.2.0'
    4 implementation 'androidx.browser:browser:1.8.0'
    5 implementation 'com.google.code.gson:gson:2.13.1'
    6 // ...
    7}
  2. Sync your project to enable the dependency changes.

  3. If your app does not have internet permissions enabled, open the AndroidManifest.xml file and add the INTERNET permission:

    1<uses-permission android:name="android.permission.INTERNET" />
  4. Configure an App Link for your app. Pass your App Link URL in metadata.deepLinkUrl when building establishData. Without it, customers are not automatically returned to your app after authenticating with their bank. See Set up App Links below.

Define Establish Data with a Request Signature

To ensure communications between the Trustly Lightbox SDK and the Trustly API are secure, use a requestSignature. You must generate a signature on your server using your access key and pass it to the Android app before rendering the Select Bank Widget or Trustly Lightbox.

Create a helper object in a new file named EstablishData.kt to hold your configuration:

1package com.myapp
2
3object EstablishData {
4
5 fun getEstablishDataValues(): Map<String, String> {
6 val establishDataValues: MutableMap<String, String> = HashMap()
7 establishDataValues["accessId"] = "YOUR_ACCESS_ID"
8 establishDataValues["merchantId"] = "YOUR_MERCHANT_ID"
9 establishDataValues["requestSignature"] = "GENERATED_HASH"
10 establishDataValues["description"] = "transaction description"
11 establishDataValues["merchantReference"] = "ABCDREF"
12 establishDataValues["currency"] = "USD"
13 establishDataValues["amount"] = "0.00"
14 establishDataValues["paymentType"] = "Deferred"
15 establishDataValues["metadata.deepLinkUrl"] = "intent://yourdomain.com#Intent;scheme=https;end"
16
17 // establishDataValues["env"] = "sandbox"
18 return establishDataValues
19 }
20}

When testing in the sandbox environment, set the env property to sandbox. You must remove the env property before publishing your production application.

To generate a requestSignature, see Generate request signatures. For a full list of parameters, see About OAuth authentication.

Display the Select Bank Widget

Trustly recommends rendering the Select Bank Widget for an optimal customer experience.

  1. In your activity’s layout XML (for example, activity_main.xml), add the TrustlyView:

    1<androidx.constraintlayout.widget.ConstraintLayout>
    2 <net.trustly.android.sdk.views.TrustlyView
    3 android:id="@+id/trustlyWidgetView"
    4 android:layout_width="match_parent"
    5 android:layout_height="match_parent"
    6 app:layout_constraintEnd_toEndOf="parent"
    7 app:layout_constraintStart_toStartOf="parent"
    8 app:layout_constraintTop_toTopOf="parent" />
    9
    10</androidx.constraintlayout.widget.ConstraintLayout>
  2. In your activity’s onCreate method, initialize the widget and handle the bank selection event. Use onBankSelected to update your establishData with the customer’s choice:

    1// MainActivity.kt
    2val establishData = EstablishData.getEstablishDataValues().toMutableMap()
    3
    4val trustlyWidget = findViewById<TrustlyView>(R.id.trustlyWidgetView)
    5
    6trustlyWidget.selectBankWidget(establishData).onBankSelected { callback, data ->
    7 establishData["paymentProviderId"] = data["paymentProviderId"].toString()
    8}

Launch the Lightbox

  1. Add a button to your activity’s layout XML (for example., activity_main.xml) to launch the payment flow:

    1<androidx.appcompat.widget.AppCompatButton
    2 android:id="@+id/btnConnectWithMyBank"
    3 android:layout_width="match_parent"
    4 android:layout_height="wrap_content"
    5 android:text="@string/connect_my_bank"
    6 app:layout_constraintBottom_toBottomOf="parent"
    7 app:layout_constraintEnd_toEndOf="parent"
    8 app:layout_constraintStart_toStartOf="parent" />
  2. Configure the button listener to launch a new activity. For example, LightboxActivity and pass the establishData:

    1// MainActivity.kt
    2val connectTrustlyButton = findViewById<AppCompatButton>(R.id.btnConnectWithMyBank)
    3
    4connectTrustlyButton.setOnClickListener {
    5 val intent = Intent(this@MainActivity, LightboxActivity::class.java)
    6 intent.putExtra(LightboxActivity.ESTABLISH_DATA, establishData as Serializable)
    7 startActivity(intent)
    8}
  3. In your LightboxActivity, call establish to open the Lightbox:

    1class LightboxActivity : AppCompatActivity() {
    2
    3 private lateinit var lightboxView: TrustlyView
    4
    5 companion object {
    6 const val ESTABLISH_DATA = "establish_data"
    7 }
    8
    9 override fun onCreate(savedInstanceState: Bundle?) {
    10 super.onCreate(savedInstanceState)
    11 setContentView(R.layout.activity_light_box)
    12
    13 val establishData = intent.getSerializableExtra(ESTABLISH_DATA) as Map<String, String>
    14 lightboxView = findViewById(R.id.lightBoxWidget)
    15 lightboxView.establish(establishData)
    16 }
    17}
  4. Optional. If your application doesn’t specify a screen orientation, add the android:configChanges attribute to your AndroidManifest.xml to handle rotation gracefully. For example:

    1<activity android:name=".LightboxActivity"
    2 android:configChanges="screenSize|orientation" />

    For more information about handling configuration changes in Android apps, see Handle configuration changes.

Add callback functions

The Trustly Lightbox provides two callback functions to handle transaction results:

  • onReturn: Called when the customer successfully authorizes the transaction.
  • onCancel: Called if the customer exits the process or the authorization fails.

Chain these callbacks to the establish method to handle the transaction result.

In the following example, a redirectToScreen helper function is used to prompt the customer when their transaction is successfully or unsuccessfully authorized:

1lightboxView.establish(establishData)
2 .onReturn(
3 TrustlyCallback { lightboxView: Trustly?, returnData: Map<String, String> ->
4 // TODO: Handle success (for example, navigate to a success screen).
5 // redirectToScreen(Callback.RETURN)
6 Log.d("Trustly", "Transaction successful: $returnData")
7 }
8 ).onCancel(
9 TrustlyCallback { lightboxView: Trustly?, cancelData: Map<String, String> ->
10 // TODO: Handle cancellation (for example, show a toast or stay on current screen).
11 // redirectToScreen(Callback.CANCEL)
12 Log.d("Trustly", "Transaction cancelled")
13 }
14 )

Your application should retrieve data provided in the onReturn callback (such as the transaction ID) and pass it to your server for validation.

Add an OAuth transition handler

To support the transition from an external OAuth login (such as a bank app) back to the Lightbox, add an onRestart override to your LightboxActivity. This ensures the Lightbox resumes correctly after the user returns to your app from a bank login.

1// LightboxActivity.kt
2
3override fun onRestart() {
4 super.onRestart()
5
6 lightboxView.proceedToChooseAccount()
7}

If your app does not already have an App Link configured, you must set one up. Without it, users will not be automatically redirected to your app after logging in on a mobile banking app.

Android App Links use standard HTTPS URLs to return users directly to your app after bank authentication. Pass your App Link URL as metadata.deepLinkUrl in establishData. Unlike custom URL schemes, App Links are verified against your domain via Digital Asset Links, preventing other apps from intercepting them, and fall back to your website if the app isn’t installed.

Create a JSON file named assetlinks.json and host it at: https://yourdomain.com/.well-known/assetlinks.json

Server requirements:

  • Served over HTTPS.
  • Content-Type header set to application/json.
1[
2 {
3 "relation": [
4 "delegate_permission/common.handle_all_urls"
5 ],
6 "target": {
7 "namespace": "android_app",
8 "package_name": "com.yourcompany.yourapp",
9 "sha256_cert_fingerprints": [
10 "4A:34:B4:72:DE:F7:..."
11 ]
12 }
13 }
14]
KeyDescription
relationPermissions being granted. Use delegate_permission/common.handle_all_urls for deep links.
namespaceThe namespace of your application. Typically android_app.
package_nameThe unique application ID defined in your build.gradle file.
sha256_cert_fingerprintsThe SHA-256 fingerprint of your app’s signing certificate. Retrieve it with keytool or via the signingReport Gradle task in Android Studio.

Verify your server returns the correct Content-Type:

$curl -I https://yourdomain.com/.well-known/assetlinks.json

Configure the manifest

Add an intent filter with autoVerify="true" to your AndroidManifest.xml. Android uses the following attributes to handle App Links:

  • android:exported="true" — Required to allow your activity to be started by external app links.
  • android:autoVerify="true" — Instructs Android to verify your domain ownership by checking assetlinks.json at install time.
  • <data> elements — Define the HTTPS scheme, domain, and path that trigger your activity.
1<!-- Overriding the SDK's default redirect activity allows you to handle the redirect in your own way. -->
2<activity
3 android:name="net.trustly.android.sdk.views.TrustlyRedirectActivity"
4 android:exported="true">
5
6 <intent-filter android:autoVerify="true">
7 <action android:name="android.intent.action.VIEW" />
8 <category android:name="android.intent.category.DEFAULT" />
9 <category android:name="android.intent.category.BROWSABLE" />
10
11 <data android:scheme="https" />
12 <data android:host="yourdomain.com" />
13 <data android:pathPrefix="/trustly-return" />
14 </intent-filter>
15
16</activity>

Update onCreate in your LightboxActivity to detect whether it was started by a normal launch or by an App Link. Also add onNewIntent so the same handler runs when the activity is already in the back stack. Add the following methods to your existing LightboxActivity class:

1// LightboxActivity.kt
2
3override fun onCreate(savedInstanceState: Bundle?) {
4 super.onCreate(savedInstanceState)
5 setContentView(R.layout.activity_light_box)
6
7 if (intent?.action == Intent.ACTION_VIEW) {
8 // Launched from an App Link — handle the deep link instead of establish().
9 handleIntent(intent)
10 } else {
11 // Normal launch — read establishData and open the Lightbox.
12 val establishData = intent.getSerializableExtra(ESTABLISH_DATA) as Map<String, String>
13 lightboxView = findViewById(R.id.lightBoxWidget)
14 lightboxView.establish(establishData)
15 }
16}
17
18override fun onNewIntent(intent: Intent?) {
19 super.onNewIntent(intent)
20 handleIntent(intent)
21 setIntent(intent)
22}
23
24private fun handleIntent(intent: Intent?) {
25 if (intent?.action == Intent.ACTION_VIEW) {
26 intent.data?.let { uri -> handleAppLink(uri) }
27 }
28}
29
30private fun handleAppLink(uri: Uri) {
31 val transactionId = uri.getQueryParameter("transactionId")
32 // Route the user and resume the Lightbox as needed.
33}

For apps that support both App Links and legacy custom URL schemes during a migration period, see Migrate from custom schemes (Android) for a unified router pattern that handles both link types through a single navigation flow.

App Links function without a fallback. However, Trustly recommends having a default deep link strategy configured for your merchant account. This ensures your application has a consistent fallback behavior if a strategy isn’t explicitly provided within the metadata.deepLinkUrl object in your code.

Any settings passed to the establishData object in your code override the default configurations stored in your Trustly account profile.

Because this setup requires internal configuration, you’ll need to contact your Customer Success Manager (CSM) or Trustly Support to enable this fallback for your account.

When you submit your request, you must provide the following information:

  • Deep link strategy: Specify deeplink-url.
  • App Link: Provide your fully qualified domain (for example, https://yourdomain.com/).