DEV Community

myougaTheAxo
myougaTheAxo

Posted on

Firebase Crashlytics & Android Localization — Quality & Reach Guide

Firebase Crashlytics & Android Localization — Quality & Reach Guide

Building a production Android app requires two critical pillars: stability and user accessibility. Firebase Crashlytics monitors crashes in real-time, while Android localization (i18n) ensures your app speaks your users' language—literally.

Let's integrate both into a professional-grade app.


Part 1: Firebase Crashlytics Setup

Step 1: Add Firebase BOM and Dependencies

In your module-level build.gradle.kts:

dependencies {
    // Firebase BOM (Bill of Materials)
    implementation(platform("com.google.firebase:firebase-bom:33.1.0"))
    implementation("com.google.firebase:firebase-crashlytics-ktx")
    implementation("com.google.firebase:firebase-analytics-ktx")
}
Enter fullscreen mode Exit fullscreen mode

The BOM ensures all Firebase libraries are compatible versions—no version mismatch headaches.

Step 2: Configure google-services.json

  1. Download google-services.json from Firebase Console
  2. Place it in app/ directory (not app/src/)
  3. Add to build.gradle.kts (project level):
plugins {
    id("com.google.gms.google-services") version "4.4.1" apply false
}
Enter fullscreen mode Exit fullscreen mode
  1. Apply plugin in build.gradle.kts (app level):
plugins {
    id("com.android.application")
    id("com.google.gms.google-services")
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Record Exceptions Manually

In your crash-prone code:

val crashlytics = FirebaseCrashlytics.getInstance()

try {
    riskyOperation()
} catch (e: Exception) {
    crashlytics.recordException(e)
    // Don't crash the app, just log it
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Add Custom Keys & Logs

Attach context to crashes:

val crashlytics = FirebaseCrashlytics.getInstance()

// User identification
crashlytics.setUserId("user_${userId}")

// Custom key-value pairs
crashlytics.setCustomKey("subscription_tier", "premium")
crashlytics.setCustomKey("screen_name", "PaymentScreen")

// Breadcrumb logs (last 100 logged)
crashlytics.log("User initiated purchase flow")
crashlytics.log("API response: ${response.code()}")
Enter fullscreen mode Exit fullscreen mode

Step 5: Disable in Debug Builds

Avoid test crashes polluting production metrics:

if (!BuildConfig.DEBUG) {
    FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(true)
} else {
    FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(false)
}
Enter fullscreen mode Exit fullscreen mode

Or configure in AndroidManifest.xml:

<meta-data
    android:name="firebase_crashlytics_collection_enabled"
    android:value="false" />
Enter fullscreen mode Exit fullscreen mode

Step 6: Target Crash-Free Rate

Monitor dashboard metrics:

  • Target: 99.5%+ crash-free rate
  • Alert threshold: If crashes exceed 0.5% of sessions, investigate immediately
  • Release process: Only deploy if crash-free rate stays above 98% for 24h

Part 2: Android Localization (i18n)

Step 1: Create Locale-Specific Strings

Create resource directories:

res/
├── values/
│   └── strings.xml (English - default)
├── values-es/
│   └── strings.xml (Spanish)
├── values-ja/
│   └── strings.xml (Japanese)
├── values-fr/
│   └── strings.xml (French)
└── values-pt-rBR/
    └── strings.xml (Brazilian Portuguese)
Enter fullscreen mode Exit fullscreen mode

res/values/strings.xml (English):

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">MyApp</string>
    <string name="welcome_message">Welcome to %1$s</string>
    <string name="buy_button">Purchase Now</string>
    <string name="currency">USD</string>
</resources>
Enter fullscreen mode Exit fullscreen mode

res/values-es/strings.xml (Spanish):

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">MiApp</string>
    <string name="welcome_message">Bienvenido a %1$s</string>
    <string name="buy_button">Comprar Ahora</string>
    <string name="currency">EUR</string>
</resources>
Enter fullscreen mode Exit fullscreen mode

res/values-ja/strings.xml (Japanese):

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">マイアプリ</string>
    <string name="welcome_message">%1$sへようこそ</string>
    <string name="buy_button">今すぐ購入</string>
    <string name="currency">JPY</string>
</resources>
Enter fullscreen mode Exit fullscreen mode

Step 2: Use stringResource in Compose

import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource

@Composable
fun WelcomeScreen() {
    val appName = stringResource(R.string.app_name)
    val message = stringResource(R.string.welcome_message, appName)

    Text(text = message)
}
Enter fullscreen mode Exit fullscreen mode

For legacy XML layouts:

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/welcome_message" />
Enter fullscreen mode Exit fullscreen mode

Step 3: Handle Plurals

Different languages have different plural rules. Polish has 3! 🇵🇱

res/values/strings.xml:

<plurals name="item_count">
    <item quantity="zero">No items</item>
    <item quantity="one">1 item</item>
    <item quantity="other">%d items</item>
</plurals>
Enter fullscreen mode Exit fullscreen mode

res/values-ja/strings.xml:

<plurals name="item_count">
    <item quantity="other">%d件のアイテム</item>
</plurals>
Enter fullscreen mode Exit fullscreen mode

Usage in Compose:

val context = LocalContext.current
val itemCount = 5
val text = context.resources.getQuantityString(
    R.plurals.item_count,
    itemCount,
    itemCount
)
Text(text)
Enter fullscreen mode Exit fullscreen mode

Step 4: RTL Support (Arabic, Hebrew, etc.)

Enable RTL layouts:

<!-- AndroidManifest.xml -->
<application
    android:supportsRtl="true"
    ...>
</application>
Enter fullscreen mode Exit fullscreen mode

Use start/end instead of left/right:

<!-- Wrong ❌ -->
<TextView
    android:layout_marginLeft="16dp"
    android:drawableLeft="@drawable/ic_email" />

<!-- Correct ✅ -->
<TextView
    android:layout_marginStart="16dp"
    android:drawableStart="@drawable/ic_email" />
Enter fullscreen mode Exit fullscreen mode

In Compose:

Row(
    modifier = Modifier
        .padding(start = 16.dp, end = 16.dp)
) {
    Icon(painter = painterResource(R.drawable.ic_email), contentDescription = null)
    Text(text = stringResource(R.string.email_label))
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Per-App Language API (Android 13+)

Let users change language without system-wide change:

import androidx.appcompat.app.AppCompatDelegate
import java.util.Locale

fun setAppLanguage(languageCode: String) {
    val locale = Locale(languageCode)
    AppCompatDelegate.setApplicationLocales(
        LocaleListCompat.create(locale)
    )
}
Enter fullscreen mode Exit fullscreen mode

Call it from Settings:

Button(onClick = { setAppLanguage("ja") }) {
    Text("日本語に変更")
}
Enter fullscreen mode Exit fullscreen mode

Add dependency:

implementation("androidx.appcompat:appcompat:1.6.1")
Enter fullscreen mode Exit fullscreen mode

Integration: Crash Reporting + Localization

Monitor localization crashes:

try {
    val text = stringResource(R.string.missing_key)
    Text(text)
} catch (e: Exception) {
    FirebaseCrashlytics.getInstance().apply {
        setCustomKey("crash_type", "localization_missing_string")
        setCustomKey("locale", Locale.getDefault().language)
        recordException(e)
    }
    Text("Unable to load translation")
}
Enter fullscreen mode Exit fullscreen mode

This catches missing translations in specific locales before they hit production.


Checklist for Launch

  • [ ] Firebase Crashlytics enabled in release builds only
  • [ ] Custom keys attached to critical screens
  • [ ] Crash-free rate baseline established (target 99.5%+)
  • [ ] All UI strings in strings.xml (no hardcoded text)
  • [ ] RTL support enabled
  • [ ] At least 3 languages (English + 2 target markets)
  • [ ] Plurals tested in target languages
  • [ ] Per-App Language API working (Android 13+)
  • [ ] Localization crashes monitored via Crashlytics

8 Android App Templates → https://myougatheaxo.gumroad.com

Need battle-tested Kotlin templates? Check out our Android App Bundle—8 production-ready templates with Crashlytics, i18n, and best practices pre-configured. Save weeks of setup.

https://myougatheaxo.gumroad.com

Top comments (0)