Android SDK
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" />
| Permission | Why |
|---|---|
INTERNET | Network calls to the Moov Money API |
READ_CONTACTS | Offer the device address book when the user picks a recipient |
READ_PHONE_STATE | Device signals collected for fraud prevention during the payment flow |
USE_BIOMETRIC | Required by the SDK’s embedded device-intelligence library |
USE_FINGERPRINT | The 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 type | Collected | Shared | Purpose |
|---|---|---|---|
| Contacts | Yes | No | App functionality |
| Photos | Yes | No | App functionality |
| Device or other IDs | Yes | No | Fraud 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 #
- The SDK repo’s sample app (
samples/sample-app) is a complete working integration, and its manifest is the reference for the permissions above. - Payments and requests share the same entry point.
- See sender authentication for minting the session token.
- See the API reference for create participant and create sender token.