Android SDK

The three screens the SDK presents: choosing a recipient, entering an amount, and confirming.

The Android SDK lets your customers send money to anyone from inside your app. You build it once with your colors, launch it from a single call, and it owns the full-screen flow from there.

You supply a short-lived token from your backend. The SDK resolves the user’s funding methods itself and handles the rest. The other person claims or pays on the hosted page.

Requirements #

  • Android 7.0 (API level 24) or later
  • Java 21 toolchain; the SDK’s classes are Java 21 bytecode
  • Kotlin 2.x

Your app doesn’t need Jetpack Compose. The SDK runs in its own activity and renders its own UI, so a View-based host integrates the same way.

Add the repository and dependency #

The SDK publishes to a private Maven repository, so Gradle needs a credential before it can resolve anything. Moov supplies a dedicated GitHub account for your team.

Sign in to the GitHub account Moov gave you and create a personal access token with the read:packages scope. Keep it out of version control: put it in your user-level ~/.gradle/gradle.properties:

moovGitHubUsername=your-github-username
moovGitHubToken=your-personal-access-token

Then declare the repository in settings.gradle.kts:

dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven {
            url = uri("https://maven.pkg.github.com/moov-sdk/moov-money-android")
            credentials {
                username = providers.gradleProperty("moovGitHubUsername")
                    .orElse(providers.environmentVariable("MOOV_GITHUB_USERNAME")).get()
                password = providers.gradleProperty("moovGitHubToken")
                    .orElse(providers.environmentVariable("MOOV_GITHUB_TOKEN")).get()
            }
        }
    }
}

The environment variable fallback is there for CI, where no user-level gradle.properties exists. Set MOOV_GITHUB_USERNAME and MOOV_GITHUB_TOKEN as secrets on your build.

Add the dependency in your app’s build.gradle.kts:

dependencies {
    implementation("io.moov:moov-money-android:0.1.0-alpha02")
}

Pin the exact version. The SDK is pre-1.0, so releases can contain breaking changes, and pinning keeps an upgrade a deliberate act.

The SDK ships consumer ProGuard rules, so no additional R8 configuration is needed.

Declare permissions #

The SDK doesn’t declare the permissions it needs at runtime. Add them to your app’s AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
PermissionWhy
INTERNETNetwork calls to the Moov Money API
READ_CONTACTSOffer the device address book when the user picks a recipient
READ_PHONE_STATEDevice signals collected for fraud prevention during the payment flow
USE_BIOMETRICRequired by the SDK’s embedded device-intelligence library
USE_FINGERPRINTThe same requirement on Android 9 (API 28) and below

These are yours to declare rather than the SDK’s because several are install-time permissions that appear in your Play Store listing. That’s a disclosure about your app, so it shouldn’t arrive silently through a dependency. You only declare them; the SDK requests the runtime ones itself when the flow reaches the screen that needs them.

Mint a session token #

The SDK authenticates with a short-lived token minted by your backend for the currently signed-in user, supplied per invocation. Your session model stays the authority on who can send or request. See sender authentication for how to mint it.

// Your backend endpoint exchanges your session for a Moov Money token.
val sessionToken = myBackend.fetchMoovSessionToken()

There’s no environment switch to configure. The SDK reads the token’s audience claim and routes to the matching environment, so pointing at staging instead of production is just a matter of minting a token there.

Build the SDK instance #

Construct MoovMoney once, in your Application class or a DI module, passing your Application to the builder:

val moovMoney = MoovMoney.Builder(application)
    .configuration(
        MoovMoneyConfiguration(
            lightColors = MoovMoneyColors(primary = BrandBlue, background = Color.White),
            darkColors = MoovMoneyColors(primary = BrandBlueDark, background = Color.Black),
        )
    )
    .logger { priority, tag, message, throwable ->
        Timber.tag(tag).log(priority, throwable, message)
    }
    .build()

Both configuration and logger are optional. Omit the configuration and the SDK uses its own brand palette; omit the logger and nothing is surfaced to you. Supply the logger; see Diagnostics below.

Launch the flow #

Start the flow with the token you minted:

moovMoney.startPayout(token = sessionToken)

This launches a full-screen, portrait-locked activity covering recipient selection, amount entry, and confirmation. It’s self-contained: participant identity and the user’s eligible funding methods (the ones you registered against the participant) are both resolved server-side from the token, so you don’t need to make any FI-specific calls to drive it.

startPayout returns immediately and reports nothing back. The activity closes itself when the user finishes or backs out, and there’s no completion result delivered to your app.

Diagnostics #

The SDK returns nothing to your code: no result, no callback. A MoovMoneyLogger on the builder is the only channel by which your integration learns what the SDK is doing.

MoovMoney.Builder(application)
    .logger { priority, tag, message, throwable ->
        Timber.tag(tag).log(priority, throwable, message)
    }
    .build()

priority uses the standard android.util.Log constants (3 for DEBUG, 4 for INFO, 5 for WARN, 6 for ERROR), so most logging libraries accept it directly. tag names the subsystem that emitted the line, and throwable is the underlying cause when there was one.

The default is MoovMoneyLogger.None, so nothing reaches your code until you supply a handler. Messages and tags are debugging aids rather than a stable contract, and they change between releases. Don’t build alerting or parsing on them.

Theming #

MoovMoneyColors carries two slots today, both optional:

MoovMoneyColors(
    primary = BrandBlue,     // buttons, selection, accents
    background = Color.White // screen background
)

Leave either null and the SDK falls back to its own value for that slot. More slots are added as the UI grows. Supply a palette for each appearance via MoovMoneyConfiguration(lightColors = ..., darkColors = ...); which one renders follows the device’s night mode setting.

appearanceMode (SYSTEM, LIGHT, or DARK, defaulting to SYSTEM) forces the SDK’s newer internal theme to a fixed appearance.

Disclose data collection #

The SDK collects data that belongs in your Play Console Data safety declaration. Review these against your existing form:

Data typeCollectedSharedPurpose
ContactsYesNoApp functionality
PhotosYesNoApp functionality
Device or other IDsYesNoFraud prevention

Contacts covers the user’s address book, which the SDK uses to match contacts to Moov Money participants so the user can find and pay people they know.

Photos covers the profile photo a user chooses, which is stored against their account and used to render their avatar.

Device or other IDs covers the device and behavioral signals the SDK collects during the payment flow for fraud prevention. The SDK performs no advertising or analytics tracking and shares no data with third parties for those purposes.

Next steps #