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
| Platform | Minimum Version | SDK Version |
|---|---|---|
| iOS | 13.0+ | 2.x |
| Android | API 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:
- File → Add Package Dependencies
- Enter:
https://github.com/savvymoney/ios-sdk - 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
| Issue | Solution |
|---|---|
| SDK initialization fails | Verify Partner ID and environment |
| Authentication fails | Check user token generation |
| Score not loading | Verify user is enrolled |
| Push notifications not working | Check device token registration |
Debug Logging
iOS Debug Logging
SavvyMoney.setLogLevel(.debug)
Android Debug Logging
SavvyMoney.setLogLevel(LogLevel.DEBUG)
Next Steps
- Review API Reference for additional endpoints
- Implement Webhooks for server-side updates
- Follow Security Best Practices