Skip to main content

Mobile SDK Integration

Build native mobile experiences with our iOS and Android SDKs. The mobile SDKs provide optimized performance and native UI components.

Overview

The mobile SDKs offer:

  • ✅ Native performance
  • ✅ Pre-built UI components
  • ✅ Biometric authentication support
  • ✅ Push notification integration
  • ✅ Offline caching
  • ✅ Customizable theming

Time to implement: 4-6 weeks

Platform Support

PlatformMinimum VersionSDK Version
iOS13.0+2.x
AndroidAPI 24+ (Android 7.0)2.x

iOS Integration

Installation

CocoaPods

Podfile
platform :ios, '13.0'

target 'YourApp' do
use_frameworks!

pod 'SavvyMoneySDK', '~> 2.0'
end

Then run:

pod install

Swift Package Manager

Add the package in Xcode:

  1. File → Add Package Dependencies
  2. Enter: https://github.com/savvymoney/ios-sdk
  3. Select version: 2.x

Configuration

AppDelegate.swift
import SavvyMoneySDK

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {

// Configure SavvyMoney SDK
SavvyMoney.configure(
partnerId: "YOUR_PARTNER_ID",
environment: .sandbox // Use .production for release
)

// Optional: Configure theming
SavvyMoney.theme = SavvyMoneyTheme(
primaryColor: UIColor(hex: "#004987"),
backgroundColor: .systemBackground,
textColor: .label
)

return true
}
}

User Authentication

Authenticate User
class CreditScoreViewController: UIViewController {

func authenticateUser() {
// Get user token from your backend
YourAPIClient.getSavvyMoneyToken(userId: currentUser.id) { result in
switch result {
case .success(let token):
SavvyMoney.authenticate(userToken: token) { authResult in
switch authResult {
case .success:
self.showCreditScore()
case .failure(let error):
self.handleError(error)
}
}
case .failure(let error):
self.handleError(error)
}
}
}
}

Display Credit Score

Using Pre-built UI

Pre-built Credit Score View
import SavvyMoneySDK

class CreditScoreViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

// Create and configure the credit score view
let creditScoreView = SavvyCreditScoreView()
creditScoreView.delegate = self
creditScoreView.translatesAutoresizingMaskIntoConstraints = false

view.addSubview(creditScoreView)

NSLayoutConstraint.activate([
creditScoreView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
creditScoreView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
creditScoreView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
creditScoreView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])

// Load the credit score
creditScoreView.loadCreditScore()
}
}

extension CreditScoreViewController: SavvyCreditScoreViewDelegate {

func creditScoreView(_ view: SavvyCreditScoreView, didLoadScore score: CreditScore) {
print("Score loaded: \(score.score)")
}

func creditScoreView(_ view: SavvyCreditScoreView, didSelectOffer offer: Offer) {
// Handle offer selection
openURL(offer.applicationURL)
}

func creditScoreView(_ view: SavvyCreditScoreView, didFailWithError error: Error) {
showErrorAlert(error.localizedDescription)
}
}

Using API Directly

Custom UI with API
class CustomCreditScoreViewController: UIViewController {

func fetchCreditScore() {
SavvyMoney.getCreditScore { result in
DispatchQueue.main.async {
switch result {
case .success(let creditScore):
self.updateUI(with: creditScore)
case .failure(let error):
self.handleError(error)
}
}
}
}

private func updateUI(with score: CreditScore) {
scoreLabel.text = "\(score.score)"
ratingLabel.text = score.rating

// Update factors
factorsStackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
for factor in score.factors {
let factorView = CreditFactorView(factor: factor)
factorsStackView.addArrangedSubview(factorView)
}
}
}

Android Integration

Installation

Gradle

build.gradle.kts (app level)
dependencies {
implementation("com.savvymoney:sdk:2.0.0")
}

Add the repository to your project:

settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url = uri("https://maven.savvymoney.com/releases") }
}
}

Configuration

Application.kt
import com.savvymoney.sdk.SavvyMoney
import com.savvymoney.sdk.SavvyMoneyConfig
import com.savvymoney.sdk.Environment

class MyApplication : Application() {

override fun onCreate() {
super.onCreate()

// Configure SavvyMoney SDK
val config = SavvyMoneyConfig.Builder()
.partnerId("YOUR_PARTNER_ID")
.environment(Environment.SANDBOX) // Use PRODUCTION for release
.theme(
SavvyMoneyTheme.Builder()
.primaryColor(Color.parseColor("#004987"))
.build()
)
.build()

SavvyMoney.initialize(this, config)
}
}

User Authentication

Authenticate User
class CreditScoreActivity : AppCompatActivity() {

private fun authenticateUser() {
// Get user token from your backend
viewModel.getSavvyMoneyToken(currentUser.id).observe(this) { result ->
when (result) {
is Result.Success -> {
SavvyMoney.authenticate(result.data.token) { authResult ->
when (authResult) {
is AuthResult.Success -> showCreditScore()
is AuthResult.Failure -> handleError(authResult.error)
}
}
}
is Result.Error -> handleError(result.exception)
}
}
}
}

Display Credit Score

Using Pre-built UI

activity_credit_score.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.savvymoney.sdk.ui.SavvyCreditScoreView
android:id="@+id/creditScoreView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
CreditScoreActivity.kt
class CreditScoreActivity : AppCompatActivity(), SavvyCreditScoreView.Listener {

private lateinit var binding: ActivityCreditScoreBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityCreditScoreBinding.inflate(layoutInflater)
setContentView(binding.root)

binding.creditScoreView.listener = this
binding.creditScoreView.loadCreditScore()
}

override fun onScoreLoaded(score: CreditScore) {
Log.d("CreditScore", "Score loaded: ${score.score}")
}

override fun onOfferSelected(offer: Offer) {
// Open offer URL
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(offer.applicationUrl))
startActivity(intent)
}

override fun onError(error: SavvyMoneyError) {
Toast.makeText(this, error.message, Toast.LENGTH_LONG).show()
}
}

Using Jetpack Compose

CreditScoreComposable.kt
@Composable
fun CreditScoreScreen(viewModel: CreditScoreViewModel = hiltViewModel()) {
val uiState by viewModel.uiState.collectAsState()

when (val state = uiState) {
is UiState.Loading -> LoadingIndicator()
is UiState.Success -> CreditScoreContent(state.data)
is UiState.Error -> ErrorMessage(state.message)
}
}

@Composable
fun CreditScoreContent(score: CreditScore) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
// Score display
Text(
text = score.score.toString(),
style = MaterialTheme.typography.displayLarge,
color = MaterialTheme.colorScheme.primary
)

Text(
text = score.rating,
style = MaterialTheme.typography.titleMedium
)

Spacer(modifier = Modifier.height(24.dp))

// Factors list
LazyColumn {
items(score.factors) { factor ->
CreditFactorItem(factor)
}
}
}
}

Push Notifications

iOS Setup

Push Notification Registration
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
// Register device token with SavvyMoney
SavvyMoney.registerPushToken(deviceToken)
}

// Handle incoming notifications
func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
) {
if SavvyMoney.handleNotification(response.notification.request.content.userInfo) {
// SavvyMoney handled the notification
completionHandler()
return
}

// Handle other notifications
completionHandler()
}

Android Setup

FirebaseMessagingService
class MyFirebaseMessagingService : FirebaseMessagingService() {

override fun onNewToken(token: String) {
super.onNewToken(token)
SavvyMoney.registerPushToken(token)
}

override fun onMessageReceived(remoteMessage: RemoteMessage) {
if (SavvyMoney.handleNotification(remoteMessage.data)) {
// SavvyMoney handled the notification
return
}

// Handle other notifications
}
}

Theming

iOS Theme Configuration

let theme = SavvyMoneyTheme(
primaryColor: UIColor(hex: "#004987"),
secondaryColor: UIColor(hex: "#0075C9"),
backgroundColor: .systemBackground,
surfaceColor: .secondarySystemBackground,
textColor: .label,
secondaryTextColor: .secondaryLabel,
errorColor: .systemRed,
successColor: .systemGreen,
fontFamily: "OpenSans",
cornerRadius: 8
)

SavvyMoney.theme = theme

Android Theme Configuration

val theme = SavvyMoneyTheme.Builder()
.primaryColor(Color.parseColor("#004987"))
.secondaryColor(Color.parseColor("#0075C9"))
.backgroundColor(Color.WHITE)
.textColor(Color.BLACK)
.cornerRadius(8f)
.fontFamily(ResourcesCompat.getFont(context, R.font.open_sans))
.build()

SavvyMoney.setTheme(theme)

Troubleshooting

Common Issues

IssueSolution
SDK initialization failsVerify Partner ID and environment
Authentication failsCheck user token generation
Score not loadingVerify user is enrolled
Push notifications not workingCheck device token registration

Debug Logging

iOS Debug Logging
SavvyMoney.setLogLevel(.debug)
Android Debug Logging
SavvyMoney.setLogLevel(LogLevel.DEBUG)

Next Steps