DEV Community

myougaTheAxo
myougaTheAxo

Posted on

Android Biometric Auth & ProGuard R8 — Security Best Practices

Android Biometric Auth & ProGuard R8 — Security Best Practices

Building secure Android apps requires understanding both authentication mechanisms and code obfuscation. This guide covers BiometricPrompt for fingerprint/face authentication and ProGuard/R8 configuration for production builds.

Part 1: BiometricPrompt Setup

1. Add Dependencies

dependencies {
    implementation "androidx.biometric:biometric:1.2.0-alpha05"
}
Enter fullscreen mode Exit fullscreen mode

2. Check BiometricManager Availability

Always verify device capabilities before showing the prompt:

import androidx.biometric.BiometricManager
import androidx.biometric.BiometricManager.Authenticators

val biometricManager = BiometricManager.from(context)
val canAuthenticate = biometricManager.canAuthenticate(
    Authenticators.BIOMETRIC_STRONG or Authenticators.DEVICE_CREDENTIAL
)

when (canAuthenticate) {
    BiometricManager.BIOMETRIC_SUCCESS -> {
        // Device supports biometric authentication
        showBiometricPrompt()
    }
    BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> {
        // No biometric hardware available
        showPasswordAuth()
    }
    BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> {
        // Hardware temporarily unavailable
        showRetryButton()
    }
    BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> {
        // User hasn't enrolled biometric data
        showEnrollmentPrompt()
    }
}
Enter fullscreen mode Exit fullscreen mode

3. Display BiometricPrompt

import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
import java.util.concurrent.Executor

val executor: Executor = ContextCompat.getMainExecutor(context)

val biometricPrompt = BiometricPrompt(
    activity,
    executor,
    object : BiometricPrompt.AuthenticationCallback() {
        override fun onAuthenticationSucceeded(
            result: BiometricPrompt.AuthenticationResult
        ) {
            super.onAuthenticationSucceeded(result)
            // Authentication successful
            handleAuthSuccess(result)
        }

        override fun onAuthenticationError(
            errorCode: Int,
            errString: CharSequence
        ) {
            super.onAuthenticationError(errorCode, errString)
            // Authentication error (user canceled, etc.)
            handleAuthError(errorCode, errString)
        }

        override fun onAuthenticationFailed() {
            super.onAuthenticationFailed()
            // Biometric rejected (wrong finger, face mismatch)
            handleAuthFailed()
        }
    }
)

val promptInfo = BiometricPrompt.PromptInfo.Builder()
    .setTitle("Authenticate")
    .setSubtitle("Use your fingerprint or face to continue")
    .setNegativeButtonText("Cancel")
    .setAllowedAuthenticators(
        BiometricManager.Authenticators.BIOMETRIC_STRONG or
        BiometricManager.Authenticators.DEVICE_CREDENTIAL
    )
    .build()

biometricPrompt.authenticate(promptInfo)
Enter fullscreen mode Exit fullscreen mode

4. DEVICE_CREDENTIAL Fallback

The DEVICE_CREDENTIAL authenticator allows PIN/pattern/password as fallback:

setAllowedAuthenticators(
    BiometricManager.Authenticators.BIOMETRIC_STRONG or
    BiometricManager.Authenticators.DEVICE_CREDENTIAL
)
Enter fullscreen mode Exit fullscreen mode

When used, the system shows biometric first; if failed, user can switch to PIN/password without leaving the prompt.

5. CryptoObject for Encryption

For sensitive operations (payments, access tokens), tie authentication to encryption:

import javax.crypto.Cipher
import java.security.KeyStore

fun createCryptoObject(): BiometricPrompt.CryptoObject? {
    return try {
        val keyStore = KeyStore.getInstance("AndroidKeyStore")
        keyStore.load(null)

        val cipher = Cipher.getInstance(
            KeyProperties.KEY_ALGORITHM_AES + "/" +
            KeyProperties.BLOCK_MODE_CBC + "/" +
            KeyProperties.ENCRYPTION_PADDING_PKCS7
        )
        cipher.init(
            Cipher.ENCRYPT_MODE,
            keyStore.getKey("biometric_key", null)
        )
        BiometricPrompt.CryptoObject(cipher)
    } catch (e: Exception) {
        null
    }
}

// Use in authentication
val cryptoObject = createCryptoObject()
biometricPrompt.authenticate(promptInfo, cryptoObject)

// After success, get cipher from result
val cipher = result.cryptoObject?.cipher
val encryptedData = cipher?.doFinal(sensitiveData)
Enter fullscreen mode Exit fullscreen mode

Part 2: ProGuard/R8 Configuration

1. Enable Code Obfuscation

In your app's build.gradle:

android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
  • minifyEnabled true: Enables R8/ProGuard obfuscation
  • shrinkResources true: Removes unused resources
  • proguardFiles: Specifies keep rules

2. Keep Rules for Popular Libraries

Create/update proguard-rules.pro:

# Gson
-keep class com.google.gson.** { *; }
-keepclassmembers class ** {
    @com.google.gson.annotations.SerializedName <fields>;
}

# Retrofit
-keep interface retrofit2.** { *; }
-keep class retrofit2.** { *; }
-keepattributes Exceptions

# Room Database
-keep class androidx.room.** { *; }
-keep @androidx.room.Entity class * { *; }
-keep @androidx.room.Dao interface *

# Kotlin Serialization
-keep class kotlinx.serialization.** { *; }

# Your app's data classes (if using reflection)
-keep class com.example.myapp.models.** { *; }

# BiometricPrompt callback
-keepclassmembers class ** {
    *** onAuthenticationSucceeded(...);
    *** onAuthenticationError(...);
    *** onAuthenticationFailed(...);
}
Enter fullscreen mode Exit fullscreen mode

3. Understanding isMinifyEnabled & isShrinkResources

Setting Effect
minifyEnabled: true Obfuscates class/method/field names, removes dead code
shrinkResources: true Removes unused resources (layouts, strings, drawables)
Both false Debug builds with full debugging info
Both true Smallest APK, but requires proper keep rules

4. Using mapping.txt for Debugging

After a release build, R8 generates mapping.txt:

Path: app/build/outputs/mapping/release/mapping.txt

Example content:
com.example.myapp.login.LoginActivity → com.example.myapp.login.a:
    void onLoginClick() → a()
Enter fullscreen mode Exit fullscreen mode

When analyzing crash logs, use retrace:

./gradlew retrace -mapping app/build/outputs/mapping/release/mapping.txt crash_stacktrace.txt
Enter fullscreen mode Exit fullscreen mode

This unmasks the obfuscated names back to original class/method names.

5. ProGuard Full Mode (Advanced)

For maximum obfuscation, add to build.gradle:

android {
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

// Or in proguard-rules.pro:
-optimizationpasses 5
-dontusemixedcaseclassnames
-verbose
-renamesourcefileattribute SourceFile
Enter fullscreen mode Exit fullscreen mode

Full mode performs aggressive optimizations:

  • Method inlining
  • Class merging
  • Field removal
  • Unused branch elimination

6. Testing ProGuard Locally

Enable obfuscation in debug builds to catch issues early:

buildTypes {
    debug {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}
Enter fullscreen mode Exit fullscreen mode

Build and test thoroughly before releasing.


Security Checklist

✓ BiometricPrompt with BIOMETRIC_STRONG or DEVICE_CREDENTIAL
✓ CryptoObject for sensitive operations
✓ canAuthenticate() check before showing prompt
✓ Proper error handling for all callbacks
✓ ProGuard/R8 enabled in release builds
✓ Keep rules for serialization libraries (Gson, Retrofit, Room)
✓ mapping.txt stored safely for crash analysis
✓ Tested locally with minifyEnabled=true


Get Started

Ready to build secure Android apps? Explore 8 Android App Templates with biometric auth, ProGuard configs, and more:

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

Templates include:

  • BiometricPrompt integration
  • Room + Retrofit setup with keep rules
  • Proper ProGuard configuration
  • Example crash log analysis with mapping.txt

Top comments (0)