Skip to main content

Android SDK

Installation

Add the following repository to the project settings.gradle file inside dependencyResolutionManagement repositories:

maven {
url "https://nexus.i.unit.co/repository/maven/"
}

Add the un-components dependency to your project:

dependencies {
implementation 'co.unit:un-components:0.14.0'
}

Usage

Initialize Unit SDK

Call UnitSdk.init with your requested environment and your theme. It is recommended to call it in onCreate method of your main activity. You may use the data class UNEnviorment:

enum UNEnvironment {
sandbox,
production
}

function inputs:

NameTypeRequiredDescription
envUNEnvironmentYESUnit environment.
themeStringNOA URL that specifies the UI configuration.
languageStringNOA URL that specifies the language configuration.
fontsUNFontsNOUNFonts object that specifies your custom fonts.
webVersioningStrategyUNWebVersioningStrategyNOWeb SDK version management strategy.
securitySettingsUNSecuritySettingsNOSecurity

Example:

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import co.unit.un_components.common.models.UNEnvironment
import co.unit.un_components.api.UnitSdk

const val THEME = "<your json styles url>"
const val LANGUAGE = "<your json language settings url>"

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
UnitSdk.init(UNEnvironment.Sandbox, THEME, LANGUAGE)
}
}

Fonts

Add the Font File to Your Project
  1. Locate the .ttf or .otf font file you wish to add.
  2. Add them to your res/font folder in your Android Studio project. Create the font folder if it doesn't exist. In order to create the assets resource folder: right click on 'res' -> new -> folder -> Assets Folder
  3. Add them to your assets/fonts folder.
Note: Android supports only alphanumeric characters and underscores in file names. Therefore, your custom font file name should adhere to this convention and may look like arial_regular.ttf.
Now, You can configure custom fonts in your application by utilizing the typealias UNFonts as shown below:
typealias UNFonts = Map<UNFontFamilyName, Array<UNFontData>>
typealias UNFontFamilyName = String

In this map, the keys typically represent the font family names. Corresponding to each font family name, there is an array containing various fonts from that particular family.

UNFontData Properties

NameTypeDescription
fontResIdIntThe resource id of the font
fontWeightFontWeightEnum that defines the weight of the font.
sources[UNFontSource]An array of UNFontSource objects. An array is used to provide fallback options.

Note:

It is imperative to recognize that the fontResId should be designated as the primary font to be utilized by our SDK. The array of font sources primarily serves to offer fallback options in scenarios involving WebView usage.

UNFontSource Properties

NameTypeDescription
fileRelativePathStringThe custom font file relative path from the project assets directory.
formatString?(Optional) Font file format. Useful for specifying fallback behavior.

Kotlin Code Example

private val fonts: UNFonts = mapOf(
"Lugrasimo" to arrayOf(
UNFontData(
fontResId = R.font.lugrasimo_regular,
sources = listOf(UNFontSource(fileRelativePath = "fonts/lugrasimo/lugrasimo_regular.ttf")),
fontWeight = FontWeight.Regular,
),
UNFontData(
fontResId = R.font.lugrasimo_bold,
sources = listOf(UNFontSource(fileRelativePath = "fonts/lugrasimo/lugrasimo_bold.ttf")),
fontWeight = FontWeight.Bold,
),
),
"Arial" to arrayOf(
UNFontData(
fontResId = R.font.arial_regular,
sources = listOf(UNFontSource(fileRelativePath = "fonts/arial/arial_regular.ttf")),
fontWeight = FontWeight.Regular,
)
)
)

Web SDK Versioning Strategy Guide

It's essential to understand that this SDK utilizes the web SDK views for certain components.

To give you optimal flexibility in managing the Web SDK versions, we've devised a strategy that allows you to either keep your SDK up-to-date or fixate on a particular version. To set your preferred versioning approach, utilize the sealed class UNWebVersioningStrategy. Below are the options you can select from:

  1. Exact Versioning - data class Exact(val major: Int, val minor: Int, val patch: Int)

    • This method allows you to lock onto a specific version that suits your needs.
  2. Up to Next Minor - data class UpToNextMinor(val major: Int, val minor: Int)

    • This is the default and recommended approach. While it keeps your SDK updated with minor patches, a manual update is needed for minor version changes.
  3. Up to Next Major -data class UpToNextMajor(val major: Int)

    • With this strategy, your SDK will automatically update until there's a major version change.
  4. Latest - object Latest

    • This strategy will always keep your SDK updated with the latest version.

For a comprehensive understanding, refer to our Web SDK - Versioning Guide.

val myWebVersioningStrategy = UNWebVersioningStrategy.UpToNextMinor(1, 2)

For the latest SDK, the latest webVersioningStrategy is upToNextMinor(major: 1, minor: 8).

Components

To use a component you may call it constructor with your current context: SomeUNComponent(context). Then, configure the component parameters.

Card View

Component name: UNCardView
configure parameters:
NameTypeRequiredDescription
cardIdStringYESUnit card id.
customerTokenStringYESA Unit Customer token.
themeStringNOA URL that specifies the UI configuration.
languageStringNOA URL that specifies the language configuration.
menuItemsList<UNCardMenuItem>NOA list of actions, The menu dynamically adjusts based on the provided list [.Freeze, .AddToWallet, .ManagePin, .Replace, .Report, .Close].
hideActionsMenuButtonBooleanNOHide menu button in case value is true.
hideCardTitleBooleanNOHide card title in case value is true.
hideSensitiveDataButtonBooleanNOHide sensitive data button in case value is true.
learnMoreUrlStringNOA “Learn more” URL on the report lost/close card info note.
onLoad(onLoadResult: Result<UNCardData>) => VoidNOCallback Occurs after a component is loaded.
onStatusChanged(card: UNCardData) => VoidNOCallback for card status changes.
onCardActivated(card: UNCardData) => VoidNOCallback for card activated.
enablePushProvisioningBooleanNOEnables Push Provisioning in case value is true.

Example:

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.fragment.app.Fragment
import co.unit.un_components.components.UNCardView
import co.unit.un_components.common.models.UNCardData

class CardFragment : Fragment(){
override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

val unCardView = this.context?.let { UNCardView(it) }
unCardView?.configure(
YOUR_CARD_ID,
YOUR_CUSTOMER_TOKEN,
THEME,
onStatusChanged = ::onStatusChanged,
onLoad = ::cardUnitOnLoad,
onCardActivated = ::onCardActivated
)

yourView.addView(unCardView)

// ...
}

private fun onStatusChanged(card: UNCardData) {
println("Card Status is changed. New card data: $card")
}

private fun cardUnitOnLoad(onLoadResult: Result<UNCardData>) {
if(onLoadResult.isSuccess) {
println(onLoadResult.getOrNull())
} else {
when (val exception = onLoadResult.exceptionOrNull()) {
is UNError.OnLoad -> {
println(exception)
}
}
}
}

private fun onCardActivated(card: UNCardData) {
println("Card is activated. Card-data: $card")
}
}

Incoming Events:

In some cases, the default menu button won't fit into the design of an application. By using the openActionsMenu() method, it's possible to open the card actions bottom sheet from a custom button.

Important Note: one can use the openActionsMenu() only after UNCardView is loaded. (can be verified by onLoad callback)

Example:

unCardView.openActionsMenu()

It's also possible to create your own menu and call card actions from it. Use openAction(action: UNCardMenuAction) method and send inside an action you want to perform. Use API Docs in order to understand which actions could be applied for any particular card statuses.

Example:

import co.unit.un_components.common.models.UNCardMenuAction

// .......

unCardView.openAction(UNCardMenuAction.Freeze)
You can choose to implement your own show / hide card sensitive data button.
In this case use 'showSensitiveData()' method to show sensitive data and 'hideSensitiveData()' method to hide it.

#### Example:
```kotlin
unCardView.showSensitiveData()
unCardView.hideSensitiveData()

Adding a card to Google Wallet (Optional)

Start by following the Add card to wallet instructions to use this capability. After that, Pass the enablePushProvisioning parameter To the Card Component with the value of true. Then, you can add a card to Google Wallet using the "Manage Google Wallet" tab in the Card Components's native menu or using an UNCardMenuAction.AddToWallet Incoming event.

Book Payment View

Component name: UNBookPaymentView
configure parameters:
NameTypeRequiredDescription
accountIdStringNOUnit account id. The account from which money is being sent.
customerTokenStringYESA Unit Customer token.
counterPartyAccountIdStringNOUnit account id. The account which will receive money.
counterPartyNameStringNOName of the counterparty. This is the name that will be displayed in the Book Payment UI during the transfer.
isSameCustomerBooleanNOStating whether both accounts belong to the same customer. Allows fetching additional information about the counterparty account. Default false
isAutoFocusBooleanNOAuto-focus the money input field once the component is mounted. Default false
initialStageBackButtonBooleanNOAn action button at the first stage of the payment flow. Default false
finalStageDoneButtonBooleanNOAn action button at the final stage of the payment flow. Default false
themeStringNOA URL that specifies the UI configuration.
languageStringNOA URL that specifies the language configuration.
onInitialStageBackButtonClicked() => VoidNOOccurs when the initial stage back button is clicked.
onFinalStageDoneButtonClicked() => VoidNOOccurs when the final stage done button is clicked.
onPaymentCreated(data: UNBookPaymentData) => VoidNOCallback for the created bookPayment.
onLoad(onLoadResult: Result<List<UNAccountData>>) => VoidNOCallback Occurs after a component is loaded.

Example:

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import co.unit.un_components.components.UNBookPaymentView

class BookPaymentFragment : Fragment() {
override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

val unBookPaymentView = this.context?.let { UNBookPaymentView(it) }
unBookPaymentView?.configure(
ACCOUNT_ID,
CUSTOMER_TOKEN,
COUNTER_PARTY_ACCOUNT_ID,
COUNTER_PARTY_NAME,
IS_SAME_CUSTOMER,
THEME,
onPaymentCreated = ::onPaymentCreated,
onLoad = ::bookPaymentUnitOnLoad

)

yourView.addView(unBookPaymentView)

// ...
}
private fun onPaymentCreated(data: UNBookPaymentData) {
println("[Book Payment Component] paymentCreatedResponse: $data")
}

private fun bookPaymentUnitOnLoad(onLoadResult: Result<[UNAccountData]>) {
if(onLoadResult.isSuccess) {
println(onLoadResult.getOrNull())
} else {
when (val exception = onLoadResult.exceptionOrNull()) {
is UNError.OnLoad -> {
println(exception)
}
}
}
}

Activity View

Component name: UNActivityView
configure parameters:
NameTypeRequiredDescription
accountIdStringNOUnit account id. The account from which money is being sent.
customerTokenStringYESA Unit Customer token.
themeStringNOA URL that specifies the UI configuration.
languageStringNOA URL that specifies the language configuration.
queryFilterStringNOQuery for filtering transactions and authorizations: Transactions, Authorizations
paginationTypeUNActivityComponentPaginationTypeNODefines the method by which additional content is loaded. Possible values: .InfiniteScroll (default), .Pagination
transactionsPerPageIntNONumber of transactions to fetch on each page or scroll to bottom. Also acts as initial number of transactions to fetch. The default is 8 for pagination and 15 for infinite scroll
hideFilterButtonBooleanNOHide filter button in case value is true.
hideBackToTopBooleanNOHide back to top button in case value is true. Possible values: true / false (default)
hideTitleBooleanNOHide title in case value is true
onLoad(onLoadResult: Result<UNActivityOnLoadResponse>) => VoidNOCallback Occurs after a component is loaded.

Example:

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import co.unit.un_components.components.UNActivityView

class ActivityFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

val unActivityView = this.context?.let { UNActivityView(it) }
unActivityView?.configure(
ACCOUNT_ID,
CUSTOMER_TOKEN,
THEME,
onLoad = ::activityUnitOnLoad
)

yourView.addView(unActivityView)

// ...
}

private fun activityUnitOnLoad(onLoadResult: Result<UNActivityOnLoadResponse>) {
if (onLoadResult.isSuccess) {
println(onLoadResult.getOrNull())
} else {
when (val exception = onLoadResult.exceptionOrNull()) {
is UNError.OnLoad -> {
println(exception)
}
}
}
}

Incoming Events:

By using the refresh() method, it's possible to to refresh the component data from a custom button. Important Note: one can use the refresh() only after unActivityView is loaded.

// .......

unActivityView?.refresh()

Account View

Component name: UNAccountView
configure parameters:
NameTypeRequiredDescription
accountIdStringNOUnit account id. The account to show, when not provided, one of the customer's accounts will be shown.
customerTokenStringYESA Unit Customer token.
themeStringNOA URL that specifies the UI configuration.
languageStringNOA URL that specifies the language configuration.
menuItemsList<UNAccountMenuItem>NOA list of actions, The menu dynamically adjusts based on the provided list [.Details, .Statements, . BankVerification].
hideActionsMenuButtonBooleanNOHide actions menu button in case value is true.
hideSelectionMenuButtonBooleanNOHide selection menu button in case value is true.
showLeftToSpendBooleanNOShow amount left to spend in case value is true, only relevant for credit accounts.
onRequestLeftToSpendDetails(account: UNAccountData) => VoidNOCallback for left to spend details request.
onLoad(onLoadResult: Result<List<UNAccountData>>) => VoidNOCallback Occurs after a component is loaded.
onAccountChanged(account: UNAccountData) => VoidNoCallback for account changes.

Example:

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import co.unit.un_components.components.UNAccountView
import co.unit.un_components.common.models.UNAccountData

class AccountFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

val unAccountView = this.context?.let { UNAccountView(it) }
unAccountView?.configure(
ACCOUNT_ID,
CUSTOMER_TOKEN,
THEME,
onLoad = ::accountUnitOnLoad,
onAccountChanged =:: handleAccountChange

)

yourView.addView(unAccountView)

// ...
}

private fun accountUnitOnLoad(onLoadResult: Result<List<UNAccountData>>) {
if(onLoadResult.isSuccess) {
println(onLoadResult.getOrNull())
} else {
when (val exception = onLoadResult.exceptionOrNull()) {
is UNError.OnLoad -> {
println(exception)
}
}
}
}

private fun handleAccountChange(account: UNAccountData) {
print("Account Change: $account")
}
}

Incoming Events:

In some cases, the default menu button won't fit into the design of an application. By using the openActionsMenu() method, it's possible to open the account menu bottom-sheet from a custom button.

Important Note: one can use the openActionsMenu() only after unAccountView is loaded.

Example:

unAccountView?.openActionsMenu()

It's also possible to create your own menu and call account actions from it. Use openAction(action: UNAccountMenuAction) method and send inside an action you want to perform. Use Unit's API Docs in order to understand which actions could be applied.

Example:

import co.unit.un_components.common.models.Account.UNAccountMenuAction

// .......

unAccountView?.openAction(UNAccountMenuAction.OpenAccountDetails)

By using the refresh() method, it's possible to to refresh the component data from a custom button. Important Note: one can use the refresh() only after UNAccountComponent is loaded.

import co.unit.un_components.common.models.Account.UNAccountMenuAction

// .......

unAccountView?.refresh()

Check Deposit View

Component name: UNCheckDepositView
Prerequirements:

To enable check scanning with our SDK, please request the camera permissions in your application manifest.

    <uses-permission android:name="android.permission.CAMERA" />
configure parameters:
NameTypeRequiredDescription
accountIdStringYESUnit account id. The account from which money is being sent.
customerTokenStringYESA Unit Customer token.
feeDoubleNOFee changed for making the check deposit, will be presented to the user.
themeStringNOA URL that specifies the UI configuration.
languageStringNOA URL that specifies the language configuration.
initialStageBackButtonBooleanNOAn action button at the first stage of the payment flow. Default false
finalStageDoneButtonBooleanNOAn action button at the final stage of the payment flow. Default false
onInitialStageBackButtonClicked() => VoidNOOccurs when the initial stage back button is clicked.
onFinalStageDoneButtonClicked() => VoidNOOccurs when the final stage done button is clicked.
onDepositCreated(checkDepositData: UNCheckDepositData) => VoidNOOccurs when a check deposit is successfully created
onRestartRequest(checkDepositData: UNCheckDepositData) => VoidNOOccurs when "Deposit another check" is clicked
onLoad(onLoadResult: Result<UNAccountData>) => VoidNOCallback Occurs after a component is loaded.

Example:

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import co.unit.un_components.components.UNCheckDepositView


class CheckDepositFragment : Fragment() {

private var unCheckDepositView: UNCheckDepositView? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {

unCheckDepositView = this.context?.let { UNCheckDepositView(it) }
unCheckDepositView?.configure(
accountId = "424242",
fee = 1.5,
customerToken = "<Your customer token>",
onDepositCreated = { checkData: UNCheckDepositData -> println("Check Deposit Created. Check ID: ${checkData.id}") },
onRestartRequest = { checkData: UNCheckDepositData -> println("Check Deposit Restart Request. Check ID: ${checkData.id}") },
onLoad = { onLoadResult: Result<UNAccountData> -> handleUnitOnLoad(onLoadResult) }
)

val fragmentLayout = inflater.inflate(R.layout.fragment_check_deposit, container, false)
fragmentLayout.findViewById<FrameLayout>(R.id.check_deposit_container).addView(unCheckDepositView)

return fragmentLayout
}
}

ACH Debit Payment View

Prerequirements

This component is using the Plaid API to connect your users' financial accounts using the Plaid integration. You must have a Plaid account and provide your Plaid credentials in the Unit Sandbox Dashboard and Unit Production Dashboard.

Enable camera support (for apps using Identity Verification only)

If your app uses Identity Verification please follow these instructions

Register your app id in Plaid's dashboard

By doing this Plaid will be able to redirect the user back to your app.

  1. Sign in to the Plaid Dashboard and go to the Team Settings -> API page.
  2. Next to Allowed Android Package Names click Configure then Add New Android Package Name.
  3. Enter your package name, for example com.plaid.example.
  4. Click Save Changes.
Using plaid in your app
  • declare a variable to act as your activity result launcher.
private var linkAccountToPlaid: ActivityResultLauncher<LinkTokenConfiguration>? = null
  • Implement the configure parameter openPlaid, which is required. When you attempt to add a new account, it will be triggered, opening the Plaid Link Activity.
private fun openPlaid(linkTokenConfiguration: LinkTokenConfiguration) {
linkAccountToPlaid?.launch(linkTokenConfiguration)
}
  • You need to sign up for the OpenPlaidLink() contract in your onCreate method. Once you have a result, you should submit it to the onPlaidLink(result: LinkResult) method located inside the UNACHDebitView.

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
linkAccountToPlaid = registerForActivityResult(OpenPlaidLink()) {
unACHDebitView?.onPlaidLink(it)
}
}

Component name: UNACHDebitView
configure parameters:
NameTypeRequiredDescription
accountIdStringNOUnit account id. The account from which money is being sent.
customerTokenStringYESA Unit Customer token.
themeStringNOA URL that specifies the UI configuration.
languageStringNOA URL that specifies the language configuration.
plaidLinkCustomizationNameStringNOThe name of the Link customization from the Plaid Dashboard to be applied to Link. If not specified, the default customization will be used. When using a Link customization, the language in the customization must match the language selected via the language parameter.
plaidAccountFiltersList<UNPlaidAccount>NOAccount subtypes to display in Link based on the provided list [.Checking, .Savings]. If not specified, only checking subtype will be shown.
feeDoubleNOBill your counterparty for his activity.
isAutoFocusBooleanNOAuto-focus the 'add new recipient' button once the component is mounted. Default false
sameDayBooleanNOEnables Same Day ACH
initialStageBackButtonBooleanNOAn action button at the first stage of the payment flow. Default false
finalStageDoneButtonBooleanNOAn action button at the final stage of the payment flow. Default false
onInitialStageBackButtonClicked() => VoidNOOccurs when the initial stage back button is clicked.
onFinalStageDoneButtonClicked() => VoidNOOccurs when the final stage done button is clicked.
onPaymentCreated(data: UNACHData) => VoidNOCallback for the created ACH payment.
openPlaid(linkTokenConfiguration: LinkTokenConfiguration) => VoidYESCallback Occurs when the Plaid Activity should open
onLoad(onLoadResult: Result<UNACHDebitOnLoadResponse>) => VoidNOCallback Occurs after a component is loaded.

Example:

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import co.unit.un_components.common.models.UNACHData
import co.unit.un_components.components.UNACHDebitView
import constants.*
import com.plaid.link.OpenPlaidLink
import com.plaid.link.configuration.LinkTokenConfiguration


class ACHDebitFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

val unACHDebitView = this.context?.let { UNACHDebitView(it) }
private var linkAccountToPlaid: ActivityResultLauncher<LinkTokenConfiguration>? = null

unACHDebitView?.configure(
ACCOUNT_ID,
CUSTOMER_TOKEN,
FEE,
IS_AUTO_FOCUS,
onPaymentCreated = ::onPaymentCreated,
openPlaid = ::openPlaid,
onLoad = ::achDebitUnitOnLoad
)

yourView.addView(unACHDebitView)

// ...
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
linkAccountToPlaid =
registerForActivityResult(OpenPlaidLink()) {
unACHDebitView?.onPlaidLink(it)
}
}

private fun openPlaid(linkTokenConfiguration: LinkTokenConfiguration) {
linkAccountToPlaid?.launch(linkTokenConfiguration)
}

private fun onPaymentCreated(data: UNACHData) {
println("[ACH Debit Component] paymentCreatedResponse: $data")
}

private fun achDebitUnitOnLoad(onLoadResult: Result<UNACHDebitOnLoadResponse>) {
if(onLoadResult.isSuccess) {
println(onLoadResult.getOrNull())
} else {
when (val exception = onLoadResult.exceptionOrNull()) {
is UNError.OnLoad -> {
println(exception)
}
}
}
}
}

ACH Credit Payment View

Prerequirements:

If you wish to use plaid in this component, please follow the pre-requisites of [ACHDebitComponent]{/android-sdk#ach-debit-component}.

Component name: UNACHCreditView
configure parameters:
NameTypeRequiredDescription
accountIdStringNOUnit account id. The account from which money is being sent.
customerTokenStringYESA Unit Customer token.
themeStringNOA URL that specifies the UI configuration.
languageStringNOA URL that specifies the language configuration.
plaidLinkCustomizationNameStringNOThe name of the Link customization from the Plaid Dashboard to be applied to Link. If not specified, the default customization will be used. When using a Link customization, the language in the customization must match the language selected via the language parameter.
plaidAccountFiltersList<UNPlaidAccountFilter>NOAccount subtypes to display in Link based on the provided list [.Checking, .Savings]. If not specified, only checking subtype will be shown.
feeDoubleNOBill your counterparty for his activity.
isAutoFocusBooleanNOAuto-focus the 'add new recipient' button once the component is mounted. Default "false"
sameDayBooleanNOEnables Same Day ACH
initialStageBackButtonBooleanNOAn action button at the first stage of the payment flow. Default false
finalStageDoneButtonBooleanNOAn action button at the final stage of the payment flow. Default false
onInitialStageBackButtonClicked() => VoidNOOccurs when the initial stage back button is clicked.
onFinalStageDoneButtonClicked() => VoidNOOccurs when the final stage done button is clicked.
onPaymentCreated(data: UNACHData) => VoidNOCallback for the created ACH payment.
openPlaid(linkTokenConfiguration: LinkTokenConfiguration) => VoidNOCallback Occurs when the Plaid Activity should open
onLoad(onLoadResult: Result<UNACHCreditOnLoadResponse>) => VoidNOCallback Occurs after a component is loaded.

Example:

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import co.unit.un_components.common.models.UNACHData
import co.unit.un_components.components.UNACHCreditView
import constants.*

class ACHCreditFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

val unACHCreditView = this.context?.let { UNACHCreditView(it) }
unACHCreditView?.configure(
ACCOUNT_ID,
CUSTOMER_TOKEN,
FEE,
IS_AUTO_FOCUS,
onPaymentCreated = ::onPaymentCreated,
onLoad = ::achCreditUnitOnLoad

)

yourView.addView(unACHCreditView)

// ...
}

private fun onPaymentCreated(data: UNACHData) {
println("[ACH Credit Component] paymentCreatedResponse: $data")
}

private fun achCreditUnitOnLoad(onLoadResult: Result<UNACHCreditOnLoadResponse>) {
if(onLoadResult.isSuccess) {
println(onLoadResult.getOrNull())
} else {
when (val exception = onLoadResult.exceptionOrNull()) {
is UNError.OnLoad -> {
println(exception)
}
}
}
}
}

Multiple Cards View

Component name: UNMultipleCardsView
configure parameters:
NameTypeRequiredDescription
customerTokenStringYESA Unit Customer token.
languageStringNOA URL that specifies the language configuration.
themeStringNOA URL that specifies the UI configuration.
paginationTypeUNMultipleCardsComponentPaginationTypeNODefines how more content is loaded. Possible values: .InfiniteScroll (default), .Pagination
cardsPerPageIntNONumber of cards to fetch on each page or scroll to bottom. Also acts as initial number of cards to fetch. The default is 8 for pagination and 15 for infinite scroll
disableCardClickBooleanNOWhen true, will not publish a unitMultipleCardsCardClicked event when a row is clicked. Possible values: true / false (default)
queryFilterStringNOQuery for filtering cards: Cards
hideTitleBooleanNOHide the component title in case value is 'true'. Possible values: true / false (default)
hideBackToTopBooleanNOHide back to top button in case value is true. Possible values: true / false (default)
onLoad(onLoadResult: Result<List<UNCardData>>) => VoidNOCallback Occurs after a component is loaded.
onCardClicked(card: UNCardData) => VoidNOCallback Occurs when a card row is clicked

Example:


import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import co.unit.un_components.common.models.UNError
import co.unit.un_components.common.models.multipleCards.UNMultipleCardsComponentPaginationType
import co.unit.un_components.components.UNMultipleCardsView

class MultipleCardsFragment : Fragment() {
private var unMultipleCardsView: UNMultipleCardsView? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
unMultipleCardsView = this.context?.let { UNMultipleCardsView(it) }
unMultipleCardsView?.configure(
customerToken = CUSTOMER_TOKEN,
onLoad = ::multipleCardsUnitOnLoad,
paginationType = UNMultipleCardsComponentPaginationType.Pagination,
)

yourView.addView(unMultipleCardsView)

// ...
}

private fun multipleCardsUnitOnLoad(onLoadResult: Result<List<UNCardData>>) {
if (onLoadResult.isSuccess) {
println(onLoadResult.getOrNull())
} else {
when (val exception = onLoadResult.exceptionOrNull()) {
is UNError.OnLoad -> {
println(exception)
}
}
}
}
}

Program Details View

Component name: UNProgramDetailsView
configure parameters:
NameTypeRequiredDescription
accountIdStringYESUnit account id. The account from which money is being sent.
customerTokenStringYESA Unit Customer token.
languageStringNOA URL that specifies the language configuration.
themeStringNOA URL that specifies the UI configuration.
hideTitleBooleanNOHide the component title in case value is 'true'. Possible values: true / false (default)
onLoad(onLoadResult: Result<UNAccountData>) => VoidNOCallback Occurs after a component is loaded.

Example:


import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import co.unit.un_components.common.models.UNError
import co.unit.un_components.components.UNProgramDetailsView

class ProgramDetailsFragment : Fragment() {

private var unProgramDetailsComponent: UNProgramDetailsView? = null

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
unProgramDetailsComponent = this.context?.let { UNProgramDetailsView(it) }

unProgramDetailsComponent?.configure(
accountId = ACCOUNT_ID,
customerToken = CUSTOMER_TOKEN,
hideTitle = false,
onLoad = ::programDetailsUnitOnLoad
)

yourView.addView(unProgramDetailsComponent)

// ....
}

private fun programDetailsUnitOnLoad(onLoadResult: Result<UNAccountData>) {
if (onLoadResult.isSuccess) {
println(onLoadResult.getOrNull())
} else {
when (val exception = onLoadResult.exceptionOrNull()) {
is UNError.OnLoad -> {
println(exception)
}
}
}
}
}

Wire Payment View

note

Wire payments are not enabled by default, and are subject to a minimum payment amount that is determined by the partner bank. See docs about Wires.

note

The component is performing MFA on every wire payment, the customer-token that is being used when using the component must have the upgradableScope attribute with the wire-payments-write scope. An example of creating a token:

{
"data": {
"type": "customerToken",
"attributes": {
"scope": "payments accounts",
"upgradableScope": "wire-payments-write",
"verificationToken": "i8FWKLBjXEg3TdeK93G3K9PKLzhbT6CRhn/VKkTsm....",
"verificationCode": "203130"
}
}
}
Component name: UNWirePaymentView
configure parameters:
NameTypeRequiredDescription
accountIdStringNOUnit account id. The account from which money is being sent.
customerTokenStringYESA Unit Customer token.
feeDoubleNOFee changed for making the wire payment, will be presented to the user.
isAutoFocusBooleanNOAuto-focus the money input field once the component is mounted. Default false
initialStageBackButtonBooleanNOAn action button at the first stage of the payment flow. Default false
finalStageDoneButtonBooleanNOAn action button at the final stage of the payment flow. Default false
languageStringNOA URL that specifies the language configuration.
themeStringNOA URL that specifies the UI configuration.
onLoad(onLoadResult: Result<List<UNAccountData>>) => VoidNOCallback Occurs after a component is loaded.
onPaymentCreated(data: UNWirePaymentData) => VoidNOCallback for the created wirePayment.
onInitialStageBackButtonClicked() => VoidNOOccurs when the initial stage back button is clicked.
onFinalStageDoneButtonClicked() => VoidNOOccurs when the final stage done button is clicked.

Example:


import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import co.unit.un_components.common.models.UNError
import co.unit.un_components.components.UNProgramDetailsView

class WirePaymentFragment : Fragment() {
private var unWirePaymentView: UNWirePaymentView? = null

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
unWirePaymentView = this.context?.let { UNWirePaymentView(it) }
unWirePaymentView?.configure(
customerToken = CUSTOMER_TOKEN,
accountId = ACCOUNT_ID,
isAutoFocus = true,
initialStageBackButton = true,
finalStageDoneButton = true,
onPaymentCreated = ::onPaymentCreated,
onInitialStageBackButtonClicked = ::onInitialStageBackButtonClicked,
onFinalStageDoneButtonClicked = ::onFinalStageDoneButtonClicked,
onLoad = { onLoadResult: Result<List<UNAccountData>> -> handleUnitOnLoad(onLoadResult) },
)

val fragmentLayout = inflater.inflate(R.layout.wire_payment, container, false)
fragmentLayout.findViewById<FrameLayout>(R.id.wire_payment_container).addView(unWirePaymentView)

return fragmentLayout
}

private fun onPaymentCreated(data: UNWirePaymentData) {
println("[Wire Payment Component] paymentCreatedResponse: $data")
}

private fun onInitialStageBackButtonClicked() {
println("[Wire Payment Component] onInitialStageBackButtonClicked")
findNavController().popBackStack()
}

private fun onFinalStageDoneButtonClicked() {
println("[Wire Payment Component] onFinalStageDoneButtonClicked")
findNavController().popBackStack()
}
}

Flows

Add card to wallet flow

Start by following the Add card to wallet instructions to use this flow.

After that, you can add a card to Google Wallet by calling the Unit SDK's startPushProvisioningFlow(context: Context, cardId: String, customerToken: String) method.

Example:

...
import co.unit.un_components.api.UnitSdk
...

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
...
UnitSdk.ui.flows.startPushProvisioning(context, YOUR_CARD_ID, YOUR_CUSTOMER_TOKEN)
...
}
}

Security

UNSecuritySettingsBuilder is designed to help you configure your security settings.

You can define your custom security settings using the builder. Then, apply these settings by passing them as a parameter to the SDK's init function.

Snapshot Protection

UNSnapshotProtectionStrategy defines how to protect your app's content from being captured in snapshots. The default strategy is FullProtection. The enum offers three strategies:

  1. Full Protection - Protects the entire activity's views from being captured in snapshots.
  2. None - no protection applied (likely used if you implement your own protection).

Example:

val securitySettings = UNSecuritySettingsBuilder()
.snapshotProtectionStrategy(UNSnapshotProtectionStrategy.FullProtection)

Additional Capabilities

Add card to wallet

This capability can be used with the Card Component or without it, as a separate flow.

Prerequirements

Complete the following steps at Steps to support Google Pay:

  1. Google Pay Prerequirements.
  2. Step 1 (UX/branding review) with screenshots that you can get from Unit.
  3. Step 2 (Push Provisioning API access).
Steps to integrate with the Visa SDK

Complete the following steps at integration steps:

  1. Prerequirements.
  2. Add VDE (Visa Digital Enablement) SDK to your project (steps 1,2 and 3).
Add to Wallet flow

You can find an overview of the add to wallet flow in this link.

Create a Kotlin class named UNVisaProvider. This class will be responsible to communicate and pass data from the Unit SDK and the VDE(Visa Digital Enablement) SDK through your app.

UNVisaProvider code
import android.content.Context
import androidx.lifecycle.ProcessLifecycleOwner
import co.unit.un_components.common.interfaces.UNVisaProviding
import co.unit.un_components.common.models.card.addToWallet.*
import com.visa.mobileEnablement.inAppCore.VisaInAppConfig
import com.visa.mobileEnablement.inAppCore.VisaInAppCore
import com.visa.mobileEnablement.inAppCore.VisaInAppCoreApplicationObserver
import com.visa.mobileEnablement.inAppCore.VisaInAppEnvironment
import com.visa.mobileEnablement.pushProvisioning.*

class UNVisaProvider(appId: String, env: VisaInAppEnvironment, context: Context):
UNVisaProviding, VisaPushProvisioningListener {
private var applicationContext: Context
private var pushProvisioningInterface: VisaPushProvisioningInterface? = null

private var launchInitializeCallback: ((signedNonce: UNVPResult<String>) -> Unit)? = null
private var launchGetWalletsCallback: ((wallets: UNVPResult<List<UNVisaWallet>>) -> Unit)? = null
private var launchStartCardProvisioningCallback: ((result: UNVPResult<UNVisaProvisionStatus>) -> Unit)? = null

init {
/* Configure Visa's SDK */
applicationContext = context.applicationContext
val visaInAppConfig = VisaInAppConfig(env, appId)
VisaInAppCore.configure(applicationContext, visaInAppConfig)
ProcessLifecycleOwner.get().lifecycle.addObserver(VisaInAppCoreApplicationObserver())
}

override fun launchInitialize(
launchInitializeCallback: (signedNonce: UNVPResult<String>) -> Unit,
) {
this.launchInitializeCallback = launchInitializeCallback

/* Initialize Visa's SDK */
pushProvisioningInterface = VisaPushProvisioningInterfaceFactory
.createPushProvisioningInterface(this)
pushProvisioningInterface?.initialize()
}

override fun launchGetWallets(
encPayload: String,
launchGetWalletsCallback: (wallets: UNVPResult<List<UNVisaWallet>>) -> Unit
) {
this.launchGetWalletsCallback = launchGetWalletsCallback

/* Get Wallets using Visa's SDK */
val supportedWalletsRequest = VPSupportedWalletRequest(encPayload)
pushProvisioningInterface?.getSupportedWallets(supportedWalletsRequest)
}

override fun launchStartCardProvisioning(
walletCode: String,
walletName: String,
launchStartCardProvisioningCallback: (result: UNVPResult<UNVisaProvisionStatus>) -> Unit
) {
this.launchStartCardProvisioningCallback = launchStartCardProvisioningCallback

/* Start Card Provisioning */
val vpCardProvisioningRequest = VPCardProvisioningRequest(enumValueOf(walletCode), walletName)
pushProvisioningInterface?.startCardProvisioning(applicationContext, vpCardProvisioningRequest)
}

/* VisaPushProvisioningListener callbacks */
override fun initializationFailure(
pushProvisioningInterface: VisaPushProvisioningInterface,
error: VPError
) {
launchInitializeCallback?.let {
it(UNVPResult.Error(UNVPError(error.code, error.description, error.type.toUNVPErrorType(), error.correlationId)))
}
}

override fun initializationSuccess(
pushProvisioningInterface: VisaPushProvisioningInterface,
response: VPInitResponse
) {
launchInitializeCallback?.let {
it(UNVPResult.Success(response.signedNonce))
}
}

override fun supportedWalletFailure(
pushProvisioningInterface: VisaPushProvisioningInterface,
error: VPError
) {
launchGetWalletsCallback?.let {
it(UNVPResult.Error(UNVPError(error.code, error.description, error.type.toUNVPErrorType(), error.correlationId)))
}
}

override fun supportedWalletSuccess(
pushProvisioningInterface: VisaPushProvisioningInterface,
response: VPSupportedWalletResponse
) {
launchGetWalletsCallback?.let {
it(UNVPResult.Success(response.wallets.map { it.toUNVPSupportedWallet() }))
}
}

override fun cardProvisioningFailure(
pushProvisioningInterface: VisaPushProvisioningInterface,
error: VPError
) {
launchStartCardProvisioningCallback?.let {
it(UNVPResult.Error(UNVPError(error.code, error.description, error.type.toUNVPErrorType(), error.correlationId)))
}
}

override fun cardProvisioningSuccess(
pushProvisioningInterface: VisaPushProvisioningInterface,
response: VPCardProvisioningResponse
) {
launchStartCardProvisioningCallback?.let {
it(UNVPResult.Success(response.walletStatus.toUNVPProvisionStatus()))
}
}
}

fun VPErrorType.toUNVPErrorType(): UNVPErrorType {
return when(this) {
VPErrorType.EmptyAppId -> UNVPErrorType.EmptyAppId
VPErrorType.DeviceAuthenticationFailed -> UNVPErrorType.DeviceAuthenticationFailed
VPErrorType.DeviceRootDetection -> UNVPErrorType.DeviceRootDetection
VPErrorType.HookDetection -> UNVPErrorType.HookDetection
VPErrorType.PlayIntegrityCheckFailed -> UNVPErrorType.PlayIntegrityCheckFailed
VPErrorType.EmptyEncryptedPayload -> UNVPErrorType.EmptyEncryptedPayload
VPErrorType.NoWallets -> UNVPErrorType.NoWallets
VPErrorType.InvalidCardId -> UNVPErrorType.InvalidCardId
VPErrorType.ProvisioningNotAllowed -> UNVPErrorType.ProvisioningNotAllowed
VPErrorType.CancelledByUser -> UNVPErrorType.CancelledByUser
VPErrorType.GoogleWalletCreationFailed -> UNVPErrorType.GoogleWalletCreationFailed
VPErrorType.UnknownErrorOccured -> UNVPErrorType.UnknownErrorOccured
VPErrorType.WalletProvisioningInconclusive -> UNVPErrorType.WalletProvisioningInconclusive
VPErrorType.WalletProvisioningError -> UNVPErrorType.WalletProvisioningError
VPErrorType.NetworkFailure -> UNVPErrorType.NetworkFailure
VPErrorType.SessionExpired -> UNVPErrorType.SessionExpired
VPErrorType.InvalidInfo -> UNVPErrorType.InvalidInfo
VPErrorType.PayloadDecryptionFailed -> UNVPErrorType.PayloadDecryptionFailed
VPErrorType.ApiError -> UNVPErrorType.ApiError
VPErrorType.InvalidNonce -> UNVPErrorType.InvalidNonce
VPErrorType.SDKLockout -> UNVPErrorType.SDKLockout
VPErrorType.NoBrowserFound -> UNVPErrorType.NoBrowserFound
VPErrorType.TLCMFeatureNotSupported -> UNVPErrorType.TLCMFeatureNotSupported
VPErrorType.TLCMUnsupportedWallet -> UNVPErrorType.TLCMUnsupportedWallet
VPErrorType.TLCMDetailsNotFoundInPaySdk -> UNVPErrorType.TLCMDetailsNotFoundInPaySdk
VPErrorType.TLCMTokenStatusExists -> UNVPErrorType.TLCMTokenStatusExists
VPErrorType.TLCMInvalidOperationInput -> UNVPErrorType.TLCMInvalidOperationInput
VPErrorType.TLCMInvalidRequest -> UNVPErrorType.TLCMInvalidRequest
VPErrorType.TLCMUpdateStatusNotAllowed -> UNVPErrorType.TLCMUpdateStatusNotAllowed
VPErrorType.TLCMTokenNotFound -> UNVPErrorType.TLCMTokenNotFound
VPErrorType.VerificationNotAllowed -> UNVPErrorType.VerificationNotAllowed
VPErrorType.PaymentMethodRemoved -> UNVPErrorType.PaymentMethodRemoved
VPErrorType.SdkInternalError -> UNVPErrorType.SdkInternalError
}
}

fun VPSupportedWallet.toUNVPSupportedWallet(): UNVisaWallet {
return UNVisaWallet(
code = this.code.toUNVisaSupportedWalletCode(),
name = this.name,
reason = this.reason?.reason,
status = this.status.toUNVPProvisionStatus()
)
}

fun VPSupportedWalletCode.toUNVisaSupportedWalletCode(): UNVisaSupportedWalletCode {
return when(this) {
VPSupportedWalletCode.GooglePayPushProvision -> UNVisaSupportedWalletCode.GooglePayPushProvision
VPSupportedWalletCode.SamsungPayPushProvision -> UNVisaSupportedWalletCode.SamsungPayPushProvision
VPSupportedWalletCode.VCEHPushProvision -> UNVisaSupportedWalletCode.VCEHPushProvision
}
}

fun VPProvisionStatus.toUNVPProvisionStatus(): UNVisaProvisionStatus {
return when(this) {
VPProvisionStatus.ReadyToProvision -> UNVisaProvisionStatus.ReadyToProvision
VPProvisionStatus.AlreadyProvisioned -> UNVisaProvisionStatus.AlreadyProvisioned
VPProvisionStatus.NotInstalled -> UNVisaProvisionStatus.NotInstalled
VPProvisionStatus.NotAvailable -> UNVisaProvisionStatus.NotAvailable
VPProvisionStatus.WalletSetupNotCompleted -> UNVisaProvisionStatus.WalletSetupNotCompleted
VPProvisionStatus.WalletAppUpdateAvailable -> UNVisaProvisionStatus.WalletAppUpdateAvailable
VPProvisionStatus.AlreadyProvisionedAndSetAsDefault -> UNVisaProvisionStatus.AlreadyProvisionedAndSetAsDefault
}
}

Set Unit SDK with the UNVisaProvider

Call UnitSdk.setVisaProvider with a UNVisaProvider instance. It is recommended to call it in the onCreate method of your main activity. You will need to make sure you're initializing the UnitSdk with UNEnvironment.Production environment prior to this step. Make sure you pass the UNVisaProvider your Visa's App ID, VisaInAppEnvironment.Production and your app's context.

Example:

import com.visa.mobileEnablement.inAppCore.VisaInAppEnvironment
import co.unit.un_components.api.UnitSdk
import co.unit.un_components.common.models.UNEnvironment
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
...
UnitSdk.setVisaProvider(UNVisaProvider(YOUR_APP_ID, VisaInAppEnvironment.Production, this))
...
}
}

After app development remaining steps

When you are done with the integration, complete the following steps.

Error Handling

By using unitOnLoad callback you can get a result of type Kotlin.Result for the requested component. On error - you will get a sealed class UNError that consist of several cases.

UNError:

CasefieldsDescription
OnLoaderrors: ArrayList<UNErrorResponseObject>Report UNErrorResponse on errors that happen during loading time

UNErrorResponseObject:

NameTypeDescription
statusStringA Unit-specific code, uniquely identifying the error type.
titleStringThe title of the error type.
detailString?Additional information about the error.
detailsString?Additional information about the error.
metaAny?Identifier to be used for further investigation.

Note: An UNErrorResponseObject MUST contain a title and the HTTP status code members.