Bundle und Assets systematisch optimieren
Die App-Größe einer React-Native-App entscheidet über Installationsraten, Store-Warnungen und die Reichweite in Märkten mit langsamen Verbindungen. Android App Bundle mit R8-Shrinking, iOS App Thinning, WebP-Bilder und eine kontinuierliche Größenüberwachung in der CI-Pipeline senken die App-Größe messbar, ohne Funktionalität zu opfern.
Inhaltsverzeichnis
- 1. Warum App-Größe eine Geschäftskennzahl ist
- 2. Wo die Bytes tatsächlich hingehen
- 3. Android: App Bundle, R8 und ABI-Splits
- 4. iOS: App Thinning und Architektur-Slices
- 5. JS-Bundle-Größe analysieren
- 6. Bilder und Assets optimieren
- 7. Native Abhängigkeiten auf Bloat prüfen
- 8. Kontinuierliche Größenüberwachung in CI
- 9. Techniken zur App-Größen-Reduktion im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum App-Größe eine Geschäftskennzahl ist
Eine große App-Größe ist kein rein technisches Detail, sondern eine messbare Größe mit direktem Einfluss auf Installationsraten. Auf langsamen oder getakteten Verbindungen brechen Nutzer den Download ab, bevor die Installation überhaupt beginnt, besonders wenn Play Store oder App Store bereits vor dem Tippen auf "Installieren" eine Größenwarnung anzeigen. In Wachstumsmärkten mit begrenztem mobilem Datenvolumen kostet jedes zusätzliche Megabyte real messbare Installationen.
Play Store zeigt ab bestimmten Schwellenwerten explizite Warnhinweise zur Downloadgröße, App Store begrenzt bei größeren Apps den Download über Mobilfunk ohne WLAN-Bestätigung. Beide Mechanismen wirken sich direkt auf die Conversion-Rate zwischen App-Store-Besuch und tatsächlicher Installation aus, ein Effekt, der sich in App-Analytics klar nachvollziehen lässt.
Bevor man an der App-Größe arbeitet, lohnt sich ein konkreter Zielwert: Ein typisches produktives React-Native-App-Bundle sollte auf Android deutlich unter 50 MB und auf iOS unter 100 MB bleiben, abhängig von Funktionsumfang und Zielgruppe. Dieser Zielwert ist die Baseline, gegen die alle folgenden Optimierungsschritte gemessen werden.
2. Wo die Bytes tatsächlich hingehen
Bevor man die App-Größe reduziert, muss man wissen, wohin die Megabyte tatsächlich fließen. Ein typisches React-Native-App-Größenbudget teilt sich auf in den JavaScript-Bundle, native Binärdateien beziehungsweise Architektur-Slices, Bilder und Fonts sowie native Third-Party-SDKs. Ohne diese Aufschlüsselung wird Optimierung zum Ratespiel, bei dem man an der falschen Stelle Zeit investiert.
Der Android APK Analyzer, direkt in Android Studio integriert, visualisiert die Größenverteilung einer APK oder AAB-Datei nach Dateityp und Verzeichnis und zeigt sofort, ob native Bibliotheken, Ressourcen oder der JS-Bundle den größten Anteil ausmachen. Auf iOS liefert Xcode einen App-Größenbericht (App Thinning Size Report), der die Größe nach Gerätevariante aufschlüsselt und zeigt, wie viel jede Architektur-Slice zum Gesamtpaket beiträgt.
Diese Analyse-Schritte sollten am Anfang jeder Optimierungsrunde stehen, nicht danach. Wer zuerst misst, weiß, ob sich der Aufwand für ProGuard-Konfiguration, WebP-Konvertierung oder das Entfernen einer nativen SDK überhaupt lohnt, bevor Entwicklungszeit investiert wird.
3. Android: App Bundle, R8 und ABI-Splits
Der wirkungsvollste Hebel zur Reduktion der App-Größe auf Android ist der Wechsel von einer klassischen APK zu einem Android App Bundle (.aab). Play Feature Delivery generiert daraus für jedes Gerät ein optimiertes, gerätespezifisches APK, das nur die tatsächlich benötigten Ressourcen und CPU-Architekturen enthält, statt eine Universal-APK mit allem für alle auszuliefern.
Zusätzlich reduziert R8, der Nachfolger von ProGuard, die Größe durch Code-Shrinking (Entfernen ungenutzten Codes), Ressourcen-Shrinking und Obfuskation. Diese drei Schritte zusammen können den finalen App-Umfang spürbar senken, insbesondere in Projekten mit vielen ungenutzten Bibliotheksfunktionen oder Ressourcen aus Third-Party-SDKs.
// android/app/build.gradle
android {
buildTypes {
release {
// Enable R8 code shrinking and obfuscation
minifyEnabled true
// Remove unused resources not referenced by shrunk code
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
// Split output by CPU architecture instead of shipping all ABIs
splits {
abi {
enable true
reset()
include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
universalApk false
}
}
bundle {
// Let Play Feature Delivery generate per-device optimized APKs
language { enableSplit = true }
density { enableSplit = true }
abi { enableSplit = true }
}
}
Ein häufig übersehener Nebeneffekt von ABI-Splits: Ohne diese Konfiguration wird für jede Installation dieselbe APK mit allen vier CPU-Architekturen ausgeliefert, obwohl ein Gerät nur eine einzige davon benötigt. Diese App-Größe-Reduktion ist damit ein reiner Konfigurationsgewinn, ohne dass eine einzige Codezeile der App selbst verändert werden muss.
4. iOS: App Thinning und Architektur-Slices
Auf iOS übernimmt App Thinning eine ähnliche Rolle wie AAB-Splits auf Android: Der App Store liefert für jedes Gerät nur die passenden Assets und Architektur-Slices aus, statt ein Universalpaket mit allen Bildvarianten und CPU-Architekturen zu verteilen. On-Demand Resources ergänzen das, indem sie Assets, die nicht sofort beim Start gebraucht werden, erst bei Bedarf nachladen, statt sie fest im initialen Download zu bündeln.
Ein häufiges, aber leicht behebbares Problem bei React-Native-Apps mit vielen Third-Party-Frameworks: Diese Frameworks enthalten oft zusätzlich Simulator-Slices oder Architekturen, die für den finalen Store-Build gar nicht benötigt werden. Das Entfernen dieser ungenutzten Slices aus eingebetteten Frameworks vor dem Archivieren reduziert die App-Größe spürbar, ohne jede Funktionalität auf echten Geräten zu beeinträchtigen.
Asset-Kataloge (.xcassets) mit korrekt konfigurierter Kompression sind der zweite Hebel: Bilder, die versehentlich unkomprimiert oder in zu hoher Auflösung im Katalog landen, blähen die App-Größe unnötig auf. Xcode komprimiert Asset-Kataloge automatisch, aber nur, wenn die Quellbilder selbst nicht bereits ineffizient große Rohdaten enthalten.
5. JS-Bundle-Größe analysieren
Der Metro-Bundler von React Native hat im Vergleich zu modernen Web-Bundlern nur eingeschränktes Tree-Shaking, was bedeutet, dass versehentlich importierter toter Code oft im finalen Bundle landet, statt automatisch entfernt zu werden. Diese Lücke macht eine gezielte Bundle-Analyse zu einem wichtigen Schritt bei der Reduktion der App-Größe.
Werkzeuge wie react-native-bundle-visualizer oder source-map-explorer visualisieren, welche Module wie viel Platz im JS-Bundle beanspruchen, meist als interaktive Treemap. Ein klassischer Fund: Ein kompletter Import von lodash statt einer einzelnen Funktion, oder ein komplettes Icon-Font-Set, obwohl die App nur eine Handvoll Icons tatsächlich verwendet.
# Generate a source map and analyze bundle composition
npx react-native bundle \
--platform android \
--dev false \
--entry-file index.js \
--bundle-output android-release.bundle \
--sourcemap-output android-release.bundle.map
npx source-map-explorer android-release.bundle android-release.bundle.map
Der häufigste Fund bei dieser Analyse ist nicht ein einzelnes riesiges Modul, sondern viele kleine, versehentlich vollständig importierte Bibliotheken, deren Summe erheblich zur App-Größe beiträgt. Named Imports statt Default-Imports ganzer Bibliotheken lösen dieses Problem meist ohne funktionale Einbußen.
6. Bilder und Assets optimieren
Bilder sind in den meisten React-Native-Apps der größte einzelne Beitrag zur App-Größe, oft größer als der komplette JS-Bundle. Die Umwandlung von PNG in WebP reduziert die Dateigröße häufig erheblich bei visuell kaum wahrnehmbarem Qualitätsverlust, ohne dass Layout oder Rendering-Code angepasst werden müssen.
Ein zweiter häufiger Fehler: Statt korrekter @2x/@3x-Asset-Varianten wird ein einzelnes, überdimensioniertes Bild für alle Bildschirmdichten verwendet. Das Betriebssystem skaliert dieses Bild dann zur Laufzeit herunter, während die App unnötig große Rohdaten für jede Displaydichte mitschleppt. Korrekt dimensionierte Assets pro Dichte-Stufe sind meist der schnellste Weg, spürbar Speicherplatz einzusparen.
# Convert PNG assets to WebP with high quality, low size overhead
for f in assets/images/*.png; do
cwebp -q 85 "$f" -o "${f%.png}.webp"
done
# Compare original vs converted size
du -sh assets/images/*.png assets/images/*.webp
SVG ist für einfache Icons und Illustrationen oft die platzsparendste Alternative zu Rasterbildern, da ein einzelnes Vektorformat alle Auflösungen abdeckt, statt mehrere Rasterversionen vorzuhalten. Für Fotos und komplexe Bilder bleibt WebP hingegen die bessere Wahl. Remote-Bilder, die nicht in jedem Fall gebraucht werden, sollten grundsätzlich lazy geladen statt fest ins App-Bundle eingebettet werden.
7. Native Abhängigkeiten auf Bloat prüfen
Native SDKs für Analytics, Werbung oder Zahlungsabwicklung bringen oft mehrere Megabyte pro Bibliothek mit, unabhängig vom eigentlichen JS-Code der App. Diese Kosten schlagen sich direkt in der App-Größe nieder und werden bei der reinen Betrachtung des JS-Bundles leicht übersehen, weil sie ausschließlich auf nativer Ebene entstehen.
Nach jedem größeren Feature-Release lohnt sich eine Bestandsaufnahme der Autolinking-Konfiguration: Native Module, die durch entfernten JS-Code nicht mehr referenziert werden, bleiben oft trotzdem in der Build-Konfiguration verlinkt und werden weiterhin mitkompiliert. Ein Audit der tatsächlich genutzten nativen Pakete gegen die package.json deckt solche Leichen häufig zuverlässig auf.
Überlappende Bibliotheken sind ein weiteres verbreitetes Muster: Zwei unterschiedliche native HTTP-Client-Module, ein altes und ein neu eingeführtes, die parallel im Projekt existieren, verdoppeln native Abhängigkeitskosten ohne zusätzlichen Nutzen. Konsolidierung auf eine einzige Bibliothek pro Funktionsbereich reduziert die App-Größe oft überraschend deutlich.
8. Kontinuierliche Größenüberwachung in CI
Ohne kontinuierliche Überwachung wächst die App-Größe schleichend mit jedem Feature, jeder neuen Abhängigkeit und jedem zusätzlichen Bild, oft ohne dass ein einzelner Commit dafür verantwortlich gemacht werden kann. Ein Größenbudget in der CI-Pipeline macht diesen schleichenden Anstieg sichtbar, bevor er sich über viele Releases hinweg summiert.
Ein einfacher Ansatz: Nach jedem Build wird die resultierende AAB- oder IPA-Größe gemessen und mit einem festgelegten Schwellenwert verglichen. Überschreitet der Build diesen Wert, schlägt die Pipeline fehl oder markiert den Pull Request zur manuellen Prüfung, ähnlich wie ein Performance-Regressionstest.
#!/usr/bin/env bash
# ci-check-app-size.sh: fail the build if AAB size regresses
set -euo pipefail
MAX_SIZE_MB=45
AAB_PATH="android/app/build/outputs/bundle/release/app-release.aab"
size_bytes=$(stat -c%s "$AAB_PATH")
size_mb=$((size_bytes / 1024 / 1024))
echo "Current AAB size: ${size_mb} MB (budget: ${MAX_SIZE_MB} MB)"
if (( size_mb > MAX_SIZE_MB )); then
echo "ERROR: App size exceeds budget of ${MAX_SIZE_MB} MB" >&2
exit 1
fi
Fastlane-Lanes lassen sich um solche Größenprüfungen erweitern und liefern zusätzlich einen historischen Verlauf, der pro Release dokumentiert, wie sich die App-Größe über Zeit entwickelt hat. Diese Disziplin behandelt Größenregressionen mit derselben Sorgfalt wie Performance-Regressionen, statt sie erst zu bemerken, wenn Nutzer oder Store-Reviews bereits reagieren.
9. Techniken zur App-Größen-Reduktion im Vergleich
Nicht jede Technik bringt denselben Ertrag im Verhältnis zum Aufwand. Die folgende Übersicht ordnet die wichtigsten Optionen zur Reduktion der App-Größe ein.
| Technik | Typische Einsparung | Implementierungsaufwand | Risiko |
|---|---|---|---|
| R8/ProGuard-Shrinking | Hoch | Gering, Konfiguration einmalig | Gering, mit Testing absichern |
| Android App Bundle / ABI-Splits | Hoch | Gering | Sehr gering |
| WebP-Konvertierung | Mittel | Gering, Batch-Skript | Gering, visuelle Prüfung nötig |
| Ungenutzte Abhängigkeiten entfernen | Variabel, teils hoch | Mittel, Audit nötig | Mittel, Funktionsbruch möglich |
R8-Shrinking und AAB-Splits liefern das beste Verhältnis aus Einsparung und Aufwand, weil sie fast ausschließlich Konfigurationsänderungen sind. Das Entfernen ungenutzter Abhängigkeiten erfordert mehr Sorgfalt, da eine unvollständige Prüfung Funktionalität brechen kann, senkt die App-Größe bei richtiger Durchführung aber oft am deutlichsten.
Mironsoft
App-Größen-Audits und Build-Optimierung für React Native
App-Größe messbar senken, ohne Funktionalität zu riskieren?
Wir analysieren AAB, IPA und JS-Bundle, identifizieren die größten Einsparpotenziale und richten R8-Shrinking, AAB-Splits und eine CI-Größenüberwachung ein, damit eure App-Größe dauerhaft im Zielbereich bleibt.
Größen-Audit
APK-Analyzer- und App-Thinning-Report-Analyse mit konkreten Einsparpotenzialen
Build-Konfiguration
R8-Shrinking, AAB-Splits und App-Thinning korrekt und sicher einrichten
CI-Größenbudget
Automatisierte Größenprüfung pro Build, bevor Regressionen live gehen
10. Zusammenfassung
Die App-Größe einer React-Native-App reduziert man am wirkungsvollsten mit einer Kombination aus Build-Konfiguration und Asset-Disziplin: Android App Bundle mit ABI-Splits und R8-Shrinking auf Android, App Thinning und bereinigte Framework-Slices auf iOS, WebP-Konvertierung für Bilder und eine gezielte JS-Bundle-Analyse gegen versehentlich vollständig importierte Bibliotheken.
Der nachhaltigste Hebel ist jedoch kontinuierliche Überwachung statt einmaliger Optimierung: Ein Größenbudget in der CI-Pipeline verhindert, dass sich schleichendes Wachstum über viele Releases unbemerkt summiert. Wer die App-Größe als wiederkehrende Kennzahl behandelt statt als einmaliges Projekt, hält sie dauerhaft im Zielbereich.
React Native App-Größe reduzieren: Das Wichtigste auf einen Blick
Android App Bundle
AAB mit ABI-Splits liefert gerätespezifische, kleinere APKs statt einer Universalversion.
R8-Shrinking
minifyEnabled true und shrinkResources true entfernen ungenutzten Code und Ressourcen automatisch.
Bilder & Assets
WebP-Konvertierung und korrekte Dichte-Varianten sparen oft den größten Einzelanteil ein.
CI-Größenbudget
Automatisierte Größenprüfung pro Build verhindert schleichendes, unbemerktes Wachstum.