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.8.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.

Example:#

import androidx.appcompat.app.AppCompatActivityimport android.os.Bundleimport co.unit.un_components.common.models.UNEnvironmentimport 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.
  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.

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: 3).

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.
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.Bundleimport android.view.LayoutInflaterimport android.view.Viewimport android.view.ViewGroupimport android.widget.LinearLayoutimport androidx.fragment.app.Fragmentimport co.unit.un_components.components.UNCardViewimport co.unit.un_components.common.models.UNCardData
class CardFragment : Fragment(){    override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val unCardComponent = this.context?.let { UNCardView(it) }        unCardComponent?.configure(            YOUR_CARD_ID,            YOUR_CUSTOMER_TOKEN,            THEME,            onStatusChanged = ::onStatusChanged,        onLoad = ::cardUnitOnLoad,        onCardActivated = ::onCardActivated        )
        yourView.addView(unCardComponent)
        // ...    }
    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 UNCardComponent is loaded. (can be verified by onLoad callback)

Example:#

unCardComponent.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
// .......
unCardComponent.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  unCardComponent.showSensitiveData()  unCardComponent.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
accountIdStringYESUnit account id. The account from which money is being sent.
customerTokenStringYESA Unit Customer token.
counterPartyAccountIdStringYESUnit account id. The account which will receive money.
counterPartyNameStringYESName 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
themeStringNOA URL that specifies the UI configuration.
languageStringNOA URL that specifies the language configuration.
onPaymentCreated(data: UNBookPaymentData) => VoidNOCallback for the created bookPayment.
onLoad(onLoadResult: Result<UNAccountData>) => VoidNOCallback Occurs after a component is loaded.

Example:#

import android.os.Bundleimport android.view.LayoutInflaterimport android.view.Viewimport android.view.ViewGroupimport android.widget.FrameLayoutimport androidx.fragment.app.Fragmentimport 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.
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.
onLoad(onLoadResult: Result<UNActivityOnLoadResponse>) => VoidNOCallback Occurs after a component is loaded.

Example:#

import android.os.Bundleimport android.view.LayoutInflaterimport android.view.Viewimport android.view.ViewGroupimport android.widget.FrameLayoutimport androidx.fragment.app.Fragmentimport 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)            }        }    }  }

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.
onLoad(onLoadResult: Result<List<UNAccountData>>) => VoidNOCallback Occurs after a component is loaded.
onAccountChanged(account: UNAccountData) => VoidNoCallback for account changes.
hideActionsMenuButtonBooleanNOHide actions menu button in case value is true.
hideSelectionMenuButtonBooleanNOHide selection menu button in case value is true.

Example:#

import android.os.Bundleimport android.view.LayoutInflaterimport android.view.Viewimport android.view.ViewGroupimport android.widget.FrameLayoutimport androidx.fragment.app.Fragmentimport co.unit.un_components.components.UNAccountViewimport 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 UNAccountComponent is loaded.

Example:#

unAccountComponent.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
// .......
unAccountComponent.openAction(UNAccountMenuAction.OpenAccountDetails)

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.
feeDoubleYESA Unit Customer token.
themeStringNOA URL that specifies the UI configuration.
languageStringNOA URL that specifies the language configuration.
onDepositCreated(depositCheckData: UNCheckDeposit) => VoidNOOccurs when a check deposit is successfully created
onRestartRequest(depositCheckData: UNCheckDeposit) => VoidNOOccurs when "Deposit another check" is clicked
onLoad(onLoadResult: Result<UNAccountData>) => VoidNOCallback Occurs after a component is loaded.

Example:#

import android.os.Bundleimport android.view.LayoutInflaterimport android.view.Viewimport android.view.ViewGroupimport android.widget.FrameLayoutimport androidx.fragment.app.Fragmentimport 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] (https://app.s.unit.sh/org-settings#tab=Integrations) and [Unit Production Dashboard] (https://app.unit.co/org-settings#tab=Integrations).

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
accountIdStringYESUnit 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.
feeDoubleNOBill your counterparty for his activity.
isAutoFocusBooleanNOAuto-focus the 'add new recipient' button once the component is mounted. Default "false"
sameDayBooleanNOEnables Same Day ACH
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.Bundleimport android.view.LayoutInflaterimport android.view.Viewimport android.view.ViewGroupimport android.widget.FrameLayoutimport androidx.fragment.app.Fragmentimport co.unit.un_components.common.models.UNACHDataimport co.unit.un_components.components.UNACHDebitViewimport constants.*import com.plaid.link.OpenPlaidLinkimport 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]{https://guides.unit.co/android-sdk#ach-debit-component}.

Component name: UNACHCreditView#
configure parameters:#
NameTypeRequiredDescription
accountIdStringYESUnit 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.
feeDoubleNOBill your counterparty for his activity.
isAutoFocusBooleanNOAuto-focus the 'add new recipient' button once the component is mounted. Default "false"
sameDayBooleanNOEnables Same Day ACH
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.Bundleimport android.view.LayoutInflaterimport android.view.Viewimport android.view.ViewGroupimport android.widget.FrameLayoutimport androidx.fragment.app.Fragmentimport co.unit.un_components.common.models.UNACHDataimport co.unit.un_components.components.UNACHCreditViewimport 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)
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.Bundleimport android.view.LayoutInflaterimport android.view.Viewimport android.view.ViewGroupimport android.widget.FrameLayoutimport androidx.fragment.app.Fragmentimport co.unit.un_components.common.models.UNErrorimport co.unit.un_components.common.models.multipleCards.UNMultipleCardsComponentPaginationTypeimport 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)                }            }        }    }}

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)        ...    }}

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.Contextimport androidx.lifecycle.ProcessLifecycleOwnerimport co.unit.un_components.common.interfaces.UNVisaProvidingimport co.unit.un_components.common.models.card.addToWallet.*import com.visa.mobileEnablement.inAppCore.VisaInAppConfigimport com.visa.mobileEnablement.inAppCore.VisaInAppCoreimport com.visa.mobileEnablement.inAppCore.VisaInAppCoreApplicationObserverimport com.visa.mobileEnablement.inAppCore.VisaInAppEnvironmentimport 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    }}
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.VisaInAppEnvironmentimport co.unit.un_components.api.UnitSdkimport co.unit.un_components.common.models.UNEnvironmentimport androidx.appcompat.app.AppCompatActivityimport 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.