Production Android apps must protect sensitive data and run smoothly on devices ranging from budget phones to flagships. Security and performance are not optional — they affect user trust, Play Store ratings, and retention.
Security Layer Performance Layer
────────────── ─────────────────
HTTPS + certificate pinning Avoid main thread blocking
Encrypted storage RecyclerView + paging
ProGuard / R8 obfuscation Image caching + compression
Secure API tokens Memory leak prevention
Least-privilege permissions Profiling with Android Studio
Area
Goal
Tool / Technique
Security
Protect data in transit and at rest
TLS, EncryptedSharedPreferences, Keystore
Code protection
Obfuscate release builds
R8 / ProGuard
Memory
Avoid leaks and OOM crashes
LeakCanary, lifecycle-aware components
Performance
Fast startup, smooth UI
Profiler, Baseline Profiles, lazy loading
1App Security Basics
Android app security starts with fundamental practices — secure storage, minimal permissions, network safety, and never hardcoding secrets in source code.
Security principles
Defense in depth — multiple layers of protection
Least privilege — request only permissions you need
Never trust client input — validate on server too
Assume device can be compromised — don't store plaintext secrets
Don't hardcode secrets
Kotlin — Bad vs good// BAD — API key in source code (can be extracted from APK)
const val API_KEY = "sk_live_abc123secret"
// BETTER — load from BuildConfig (still extractable, but not in Git)
// build.gradle.kts: buildConfigField("String", "API_KEY", "\"${project.findProperty("API_KEY")}\"")
// BEST — short-lived tokens from your backend after user auth
suspend fun getApiToken(): String = authRepository.fetchSessionToken()
Kotlin — EncryptionHelper.ktclass EncryptionHelper(context: Context) {
private val keyAlias = "app_encryption_key"
private val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) }
init {
if (!keyStore.containsAlias(keyAlias)) generateKey()
}
fun encrypt(plainText: String): String {
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
cipher.init(Cipher.ENCRYPT_MODE, getKey())
val iv = cipher.iv
val encrypted = cipher.doFinal(plainText.toByteArray(Charsets.UTF_8))
return Base64.encodeToString(iv + encrypted, Base64.DEFAULT)
}
fun decrypt(encryptedText: String): String {
val decoded = Base64.decode(encryptedText, Base64.DEFAULT)
val iv = decoded.copyOfRange(0, 12)
val encrypted = decoded.copyOfRange(12, decoded.size)
val cipher = Cipher.getInstance("AES/GCM/NoPadding")
val spec = GCMParameterSpec(128, iv)
cipher.init(Cipher.DECRYPT_MODE, getKey(), spec)
return String(cipher.doFinal(encrypted), Charsets.UTF_8)
}
private fun getKey(): SecretKey {
return (keyStore.getEntry(keyAlias, null) as KeyStore.SecretKeyEntry).secretKey
}
}
SQLCipher for encrypted Room database
Kotlin — Encrypted Room (concept)// For highly sensitive local data, use SQLCipher with Room
// implementation("net.zetetic:android-database-sqlcipher:4.5.4")
val passphrase = SQLiteDatabase.getBytes("user_passphrase".toCharArray())
val factory = SupportFactory(passphrase)
Room.databaseBuilder(context, AppDatabase::class.java, "secure_db.db")
.openHelperFactory(factory)
.build()
What to encrypt
Data
Recommended Approach
Auth tokens
EncryptedSharedPreferences
User credentials
Never store passwords — use tokens
PII in database
Room + SQLCipher or field-level encryption
Files (PDFs, images)
EncryptedFile API (Jetpack Security)
Network traffic
HTTPS/TLS (transport encryption)
3ProGuard
R8 (successor to ProGuard) shrinks, obfuscates, and optimizes release builds. It removes unused code, renames classes/methods, and reduces APK size — making reverse engineering harder.
Text — proguard-rules.pro# Keep data classes used by Gson
-keep class com.example.myapp.model.** { *; }
# Retrofit
-keepattributes Signature, InnerClasses, EnclosingMethod
-keepclassmembers,allowshrinking,allowobfuscation interface * {
@retrofit2.http.* <methods>;
}
# Room
-keep class * extends androidx.room.RoomDatabase
-keep @androidx.room.Entity class *
# Keep Parcelable creators
-keepclassmembers class * implements android.os.Parcelable {
public static final ** CREATOR;
}
# Remove logging in release
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
}
Keep rules for libraries
Kotlin — Common keep rules# Gson — keep fields for serialization
-keepattributes *Annotation*
-keepclassmembers class * {
@com.google.gson.annotations.SerializedName <fields>;
}
# Firebase / Crashlytics — usually auto-included via library consumer rules
-keep class com.google.firebase.** { *; }
# Hilt / Dagger — generated code kept automatically with correct setup
Test release builds
Always test a minified release build before publishing. R8 can strip classes used via reflection (Gson, Retrofit, Room) if keep rules are missing — causing runtime crashes that don't appear in debug builds.
4Secure APIs
API security ensures data traveling between your app and backend is authenticated, encrypted, and resistant to tampering. Use HTTPS, token-based auth, and certificate pinning for sensitive apps.
Memory leaks and excessive allocations cause slowdowns, ANRs, and crashes. Use lifecycle-aware components, recycle bitmaps properly, and detect leaks with profiling tools.