DEV Community

Ajmal Hasan
Ajmal Hasan

Posted on

How I Reduced My React Native 0.81 APK Size by 50% (Without Breaking Anything)

A large APK size can slow down downloads, increase install drop-offs, and impact user experience — especially in regions with slower internet connections.

In this post, I'll walk you through the exact steps I used to reduce a production React Native 0.81 app's APK size by ~50%, while maintaining full functionality and security.


📊 The Results

Before After Reduction
~85 MB ~42 MB ~50%

🛠️ Step 1: Build Only for arm64-v8a Architecture

Most optimization guides tell you to split APKs by CPU architecture. But here's the thing: if your minSdkVersion is 29+ (Android 10+), you only need arm64-v8a.

Why? Because:

  • ✅ All Android 10+ devices support 64-bit (arm64-v8a)
  • ✅ Google Play Store requires 64-bit support
  • ✅ 95%+ of active Android devices use arm64-v8a
  • ❌ armeabi-v7a is for 32-bit devices (pre-2014)
  • ❌ x86/x86_64 is for Intel devices (<1% market share)

Implementation

In your android/app/build.gradle:

// Enable separate builds per CPU architecture
def enableSeparateBuildPerCPUArchitecture = true

android {
// ... existing config ...

splits {
    abi {
        reset()
        enable enableSeparateBuildPerCPUArchitecture
        universalApk false  // No universal APK needed
        include "arm64-v8a"  // Only modern 64-bit devices
    }
}
Enter fullscreen mode Exit fullscreen mode

}💡 Pro tip: Set universalApk false to skip building a fat universal APK — it's unnecessary when targeting a single architecture.


🌍 Step 2: Keep Only Necessary Languages

Your app probably only supports a few languages, but by default, Android bundles resources for ALL languages from your dependencies (like Google Play Services).

Implementation

In android/app/build.gradle, inside defaultConfig:

defaultConfig {
// ... existing config ...

// Keep only necessary languages to reduce APK size
resConfigs "ar", "en", "fr"  // Add your supported languages
Enter fullscreen mode Exit fullscreen mode

}This single line can remove several megabytes of unused language resources!


📦 Step 3: Enable Resource Shrinking & PNG Compression

Enable these in your release build type:

buildTypes {
release {
signingConfig signingConfigs.release
debuggable false
minifyEnabled true // Code shrinking (already enabled)
shrinkResources true // Remove unused resources
crunchPngs true // Extra PNG compression
zipAlignEnabled true // Memory optimization
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
}
}### What Each Does:

Option Benefit
minifyEnabled true Removes unused code, obfuscates names
shrinkResources true Removes unused drawables, layouts, etc.
crunchPngs true Additional PNG compression
zipAlignEnabled true Optimizes APK for memory-mapped reading

🔐 Step 4: Optimize ProGuard Rules

ProGuard (or R8) is powerful but can break your app if not configured correctly. Here's a comprehensive, battle-tested configuration for React Native 0.81:

android/app/proguard-rules.pro

guard

========== STANDARD OPTIMIZATIONS ==========

-optimizationpasses 3
-allowaccessmodification
-overloadaggressively
-repackageclasses ''
-dontusemixedcaseclassnames
-dontpreverify

Remove debug logging in production (keeps error logs)

-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
public static *** i(...);
public static *** w(...);
}

Keep crash reporting info

-keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute SourceFile
-keepattributes Signature, Annotation

========== REACT NATIVE CORE ==========

-keep class com.facebook.hermes.** { ; }
-keep class com.facebook.hermes.unicode.
* { ; }
-keep class com.facebook.react.
* { ; }
-keep class com.facebook.jni.
* { ; }
-keep class com.facebook.soloader.
* { *; }

Bridge & Native Modules

-keep public class * extends com.facebook.react.bridge.NativeModule { ; }
-keep class com.facebook.react.bridge.
* { *; }
-keepclassmembers class * {
@com.facebook.react.bridge.ReactMethod *;
}
-keepclassmembers class * {
@com.facebook.proguard.annotations.DoNotStrip *;
}

UI Manager & View System

-keep @com.facebook.react.uimanager.annotations.ReactProp class * { ; }
-keep @com.facebook.react.uimanager.annotations.ReactPropGroup class * { *; }
-keep class * extends com.facebook.react.uimanager.ViewManager { *; }
-keep class com.facebook.react.uimanager.
* { *; }

TurboModules (New Architecture)

-keep class com.facebook.react.turbomodule.** { ; }
-keep class com.facebook.react.animated.
* { ; }
-keep class com.facebook.react.common.
* { *; }

========== COMMON LIBRARIES ==========

Reanimated

-keep class com.swmansion.reanimated.** { ; }
-keep class com.swmansion.
* { ; }
-dontwarn com.swmansion.
*

SVG

-keep public class com.horcrux.svg.** { *; }

Fast Image

-keep class com.dylanvann.fastimage.** { *; }

Firebase

-keep class com.google.firebase.** { ; }
-dontwarn com.google.firebase.
*

OkHttp

-keep class okhttp3.** { ; }
-keep interface okhttp3.
* { ; }
-dontwarn okhttp3.
*
-dontwarn okio.**### Why This Works:

  1. -optimizationpasses 3 — Multiple optimization passes for maximum shrinkage
  2. Log removal — Strips debug/verbose/info/warning logs (keeps errors for debugging)
  3. -keepattributes SourceFile,LineNumberTable — Preserves stack traces for crash reporting
  4. Comprehensive -keep rules — Protects all React Native internals and common libraries

✅ Step 5: Verify Hermes is Enabled

Hermes is React Native's optimized JavaScript engine. It should be enabled by default in RN 0.81, but verify in your android/gradle.properties:

hermesEnabled=trueHermes provides:

  • ✅ Faster app startup
  • ✅ Smaller JS bundle size
  • ✅ Lower memory usage

🧪 Testing Your Build

After applying all optimizations:

Clean previous builds

cd android && ./gradlew clean

Build release APK

./gradlew assembleRelease

Check APK size

ls -lh app/build/outputs/apk//release/.apk---

📋 Complete Checklist

  • [ ] Set enableSeparateBuildPerCPUArchitecture = true
  • [ ] Include only arm64-v8a architecture (if minSdk 29+)
  • [ ] Set universalApk false
  • [ ] Add resConfigs for your supported languages
  • [ ] Enable shrinkResources true
  • [ ] Enable crunchPngs true
  • [ ] Enable zipAlignEnabled true
  • [ ] Add comprehensive ProGuard rules
  • [ ] Verify Hermes is enabled
  • [ ] Test on real devices before release!

🎯 Summary

Optimization APK Size Impact
Single architecture (arm64-v8a) -30-40%
Resource shrinking -5-10%
Language filtering -2-5%
ProGuard optimizations -5-10%
PNG compression -1-3%

⚠️ Important Notes

  1. Always test on real devices after applying these optimizations
  2. Keep error logs — don't strip Log.e() for production debugging
  3. Firebase Crashlytics still works — we preserved SourceFile,LineNumberTable
  4. Play Store accepts single-architecture APKs — they'll deliver the right one to users

Hope this helps you ship a lighter, faster React Native app! 🚀

Got questions or improvements? Drop them in the comments! 👇


Found this useful? Follow me for more React Native optimization tips!

Top comments (0)