Back to blog
Article

Cutting React Native APK size for field staff on cheap Android phones

Cutting React Native APK size for field staff on cheap Android phones
S

StriveBit

3 min readMobile Development

Cutting React Native APK size for field staff on cheap Android phones

A logistics client handed us a React Native app that shipped as a 78MB APK. Their field verification staff in Bihar and Jharkhand were refusing the update — the installer was eating 90MB of internal storage on phones with 8GB total, and downloading over a patchy 2G connection. We got it to 24MB. Each cut had a cost.

The first move was switching from APK to AAB at the Play Store. Google's dynamic delivery splits your bundle per device ABI and screen density, so a user on an ARMv7 phone with mdpi assets downloads roughly 24MB instead of the universal APK containing x86 and x86_64 slices they will never use. The cost is losing sideloading. If your field ops team distributes APKs over WhatsApp or a private MDM because Play Store access is spotty in rural areas, AAB does not help. We kept AAB for Play Store distribution and accepted that the manual install path stays fat.

Hermes was already on, but we had not enabled `enableProguardInReleaseBuilds` and `minifyEnabled`. Adding ProGuard with the right keep rules for our native modules knocked 6MB off the JS bundle and native libs. The cost was two days of debugging crashes in a barcode scanning library where ProGuard stripped a reflection call. You will need custom keep rules for any native dependency that uses JNI or runtime class lookups.

We replaced `react-native-vector-icons` MaterialCommunityIcons — all 6,000 icons bundled — with `react-native-svg` for the 40 icons the app actually used. That removed 1.2MB from the bundle. The cost was rewriting 40 icon components, which took an afternoon.

The heaviest asset was a 4MB onboarding video. We moved it out of the bundle entirely and lazy-loaded it from Cloudflare R2 on first launch. The cost was the video failing to play if the field staff opens the app offline before the video has cached. We added a silent fallback and stopped blocking onboarding on it.

Image assets were the steady leak. We had 18 PNGs at xxhdpi that were never going to look crisp but were bundled at 300KB each. We compressed with `pngquant --quality=65-80` and dropped to `@2x` for most. The cost is slightly soft edges on a 720p screen, which is invisible to a verifier scanning QR codes outdoors.

We stripped three libraries that were doing one job each badly. `moment` was 67KB of locales for three date formats. We replaced it with a 40-line function using the native `Intl` API. `lodash` was pulled in by a dependency tree and we were using `get` and `debounce` — both trivial to inline. `react-native-fs` was there for a single PDF write; we moved to the native sharing API. Each removal required reading what actually used it.

The last 4MB came from removing `react-native-maps` and using a webview with an OpenStreetMap tile layer. The field staff needed a pin drop on a location, not turn-by-turn navigation. The cost is slower pan performance and no offline tile caching.

The app installs now. The field ops team stopped getting "storage full" errors during their Monday morning update push.

Back to all articles

Ready to build something great?

We help ambitious teams build software that lasts. If you're interested in working with us or want to discuss your project, let's connect.

Get in touch