Zmniejsz rozmiar aplikacji

Użytkownicy często unikają pobierania aplikacji, które wydają się zbyt duże, zwłaszcza na rynkach wschodzących, gdzie urządzenia łączą się z niestabilnymi sieciami 2G i 3G lub korzystają z planów z limitami danych. Na tej stronie opisujemy, jak zmniejszyć rozmiar pliku do pobrania aplikacji, aby więcej użytkowników mogło ją pobrać.

Przesyłanie aplikacji za pomocą pakietów Android App Bundle

Prześlij aplikację jako pakiet Android App Bundle, aby od razu zmniejszyć jej rozmiar podczas publikowania w Google Play. Pakiet Android App Bundle to format przesyłania, który zawiera cały skompilowany kod i wszystkie zasoby aplikacji, ale generowanie i podpisywanie plików APK jest odroczone do momentu publikacji w Google Play.

Model udostępniania aplikacji w Google Play używa pakietu aplikacji do generowania i udostępniania zoptymalizowanych plików APK dla każdej konfiguracji urządzenia użytkownika. Dzięki temu użytkownicy pobierają tylko kod i zasoby potrzebne do uruchomienia aplikacji. Nie musisz tworzyć, podpisywać ani zarządzać wieloma plikami APK, aby obsługiwać różne urządzenia, a użytkownicy otrzymują mniejsze i bardziej zoptymalizowane pliki do pobrania.

W przypadku aplikacji publikowanych za pomocą pakietów aplikacji Google Play wymusza ograniczenie rozmiaru skompresowanego pliku do pobrania do 200 MB. Większe rozmiary są możliwe dzięki funkcjom Play Feature Delivery i Play Asset Delivery, ale zwiększenie rozmiaru aplikacji może negatywnie wpłynąć na skuteczność instalacji i zwiększyć liczbę odinstalowań. Dlatego zalecamy stosowanie się do wskazówek opisanych na tej stronie, aby jak najbardziej zmniejszyć rozmiar pliku do pobrania aplikacji.

Struktura pliku APK

Zanim zaczniesz zmniejszać rozmiar aplikacji, warto poznać strukturę pliku APK. Plik APK to archiwum ZIP, które zawiera wszystkie pliki składające się na aplikację. Są to m.in. pliki klas Java, pliki zasobów i plik zawierający skompilowane zasoby.

Plik APK zawiera te katalogi:

  • META-INF/: zawiera pliki podpisu CERT.SF i CERT.RSA, a także plik manifestu MANIFEST.MF.
  • assets/: zawiera zasoby aplikacji, które aplikacja może pobrać za pomocą obiektu AssetManager.
  • res/: zawiera zasoby, które nie są kompilowane do resources.arsc.
  • lib/: zawiera skompilowany kod, który jest specyficzny dla warstwy oprogramowania procesora. Ten katalog zawiera podkatalog dla każdego typu platformy, np. armeabi, armeabi-v7a, arm64-v8a, x86, x86_64 i mips.

Plik APK zawiera też te pliki. Obowiązkowy jest tylko plik AndroidManifest.xml:

  • resources.arsc: zawiera skompilowane zasoby. Ten plik zawiera treść XML ze wszystkich konfiguracji folderu res/values/. Narzędzie do przygotowywania pakietów wyodrębnia tę treść XML, kompiluje ją do postaci binarnej i archiwizuje. Ta treść obejmuje ciągi tekstowe i style, a także ścieżki do treści, które nie są bezpośrednio zawarte w pliku resources.arsc, np. pliki układu i obrazy.
  • classes.dex: zawiera klasy skompilowane w formacie DEX, który jest zrozumiały dla maszyn wirtualnych Dalvik i ART.
  • AndroidManifest.xml: zawiera główny plik manifestu Androida. Ten plik zawiera nazwę, wersję, prawa dostępu i pliki bibliotek, do których odwołuje się aplikacja. Plik jest w binarnym formacie XML Androida.

Zmniejszanie liczby i rozmiaru zasobów

Rozmiar pliku APK wpływa na szybkość wczytywania aplikacji, ilość używanej przez nią pamięci i zużycie energii. Możesz zmniejszyć rozmiar pliku APK, zmniejszając liczbę i rozmiar zawartych w nim zasobów. W szczególności możesz usunąć zasoby, których aplikacja już nie używa, i używać skalowalnych obiektów Drawable zamiast plików graficznych. W tej sekcji omawiamy te metody i inne sposoby zmniejszania liczby zasobów w aplikacji, aby zmniejszyć ogólny rozmiar pliku APK.

Usuwanie nieużywanych zasobów

Narzędzie lint – statyczny analizator kodu w Androidzie Studio – wykrywa w folderze res/ zasoby, do których nie odwołuje się kod. Gdy narzędzie lint wykryje w projekcie potencjalnie nieużywany zasób, wyświetli komunikat podobny do tego przykładu:

res/layout/preferences.xml: Warning: The resource R.layout.preferences appears
    to be unused [UnusedResources]

Biblioteki dodawane do kodu mogą zawierać nieużywane zasoby. Jeśli w pliku build.gradle.kts aplikacji włączysz opcję shrinkResources, Gradle może automatycznie usunąć zasoby.

Kotlin

android {
    // Other settings.

    buildTypes {
        getByName("release") {
            minifyEnabled = true
            shrinkResources = true
            proguardFiles(getDefaultProguardFile('proguard-android.txt'), "proguard-rules.pro")
        }
    }
}

Dynamiczny

android {
    // Other settings.

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

Aby użyć opcji shrinkResources, włącz zmniejszanie rozmiaru kodu. Podczas procesu kompilacji R8 najpierw usuwa nieużywany kod. Następnie wtyczka Androida do obsługi Gradle usuwa nieużywane zasoby.

Więcej informacji o zmniejszaniu rozmiaru kodu i zasobów oraz o innych sposobach zmniejszania rozmiaru pliku APK w Androidzie Studio znajdziesz w artykule Zmniejszanie rozmiaru, zaciemnianie i optymalizowanie aplikacji.

We wtyczce Androida do obsługi Gradle w wersji 7.0 i nowszych możesz zadeklarować konfiguracje obsługiwane przez aplikację. Gradle przekazuje te informacje do systemu kompilacji za pomocą opcji resourceConfigurations i defaultConfig. System kompilacji uniemożliwia wtedy pojawianie się w pliku APK zasobów z innych nieobsługiwanych konfiguracji, co zmniejsza rozmiar pliku APK. Więcej informacji o tej funkcji znajdziesz w artykule Usuwanie nieużywanych zasobów alternatywnych.

Minimalizowanie użycia zasobów z bibliotek

Podczas tworzenia aplikacji na Androida zwykle używasz bibliotek zewnętrznych, aby zwiększyć użyteczność i wszechstronność aplikacji. Możesz na przykład odwoływać się do AndroidX aby poprawić wygodę użytkowników na starszych urządzeniach, lub używać Usług Google Play do pobierania automatycznych tłumaczeń tekstu w aplikacji.

Jeśli biblioteka jest przeznaczona na serwer lub komputer, może zawierać wiele obiektów i metod, których aplikacja nie potrzebuje. Aby uwzględnić tylko te części biblioteki, których potrzebuje aplikacja, możesz edytować pliki biblioteki, jeśli licencja na to pozwala. Możesz też użyć alternatywnej biblioteki dostosowanej do urządzeń mobilnych, aby dodać do aplikacji określone funkcje.

Dekodowanie animowanych obrazów w kodzie natywnym

W Androidzie 12 (poziom interfejsu API 31) interfejs NDK ImageDecoder został rozszerzony, aby dekodować wszystkie klatki i dane o czasie z obrazów, które używają formatów plików animowanych GIF i animowanych WebP.

Używaj ImageDecoder zamiast bibliotek innych firm, aby jeszcze bardziej zmniejszyć rozmiar pliku APK i korzystać z przyszłych aktualizacji związanych z bezpieczeństwem i wydajnością.

Więcej informacji o interfejsie API ImageDecoder znajdziesz w API reference i w przykładzie na GitHubie.

Obsługa tylko określonych gęstości

Android obsługuje różne gęstości ekranu, takie jak:

  • ldpi
  • mdpi
  • tvdpi
  • hdpi
  • xhdpi
  • xxhdpi
  • xxxhdpi

Chociaż Android obsługuje powyższe gęstości, nie musisz eksportować zasobów rastrowych do każdej z nich.

Jeśli wiesz, że tylko niewielki odsetek użytkowników ma urządzenia o określonej gęstości, zastanów się, czy musisz dołączyć te gęstości do aplikacji. Jeśli nie uwzględnisz zasobów dla określonej gęstości ekranu, Android automatycznie skaluje istniejące zasoby pierwotnie zaprojektowane dla innych gęstości ekranu.

Jeśli aplikacja potrzebuje tylko skalowanych obrazów, możesz zaoszczędzić jeszcze więcej miejsca, umieszczając pojedynczy wariant obrazu w folderze drawable-nodpi/. Zalecamy, aby w aplikacji uwzględnić co najmniej wariant obrazu xxhdpi.

Więcej informacji o gęstości ekranu znajdziesz w artykule Rozmiary i gęstości ekranu.

Używanie obiektów drawable

Niektóre obrazy nie wymagają statycznego zasobu obrazu. Zamiast tego framework może dynamicznie rysować obraz w czasie działania. Obiekty Drawable – lub <shape> w XML – mogą zajmować bardzo mało miejsca w pliku APK. Obiekty Drawable w XML tworzą też monochromatyczne obrazy zgodne z wytycznymi Material Design.

Ponowne używanie zasobów

Możesz uwzględnić osobny zasób dla wariantów obrazu, np. jego wersji z odcieniem, cieniem lub obróconej. Zalecamy jednak ponowne używanie tego samego zestawu zasobów i dostosowywanie ich w razie potrzeby w czasie działania.

Android udostępnia kilka narzędzi do zmiany koloru zasobu, np. atrybuty android:tint i tintMode.

Możesz też pominąć zasoby, które są tylko obróconym odpowiednikiem innego zasobu. Ten fragment kodu pokazuje, jak zmienić obraz „kciuka w górę” na „kciuk w dół”, obracając go o 180 stopni wokół środka:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_thumb_up"
    android:pivotX="50%"
    android:pivotY="50%"
    android:fromDegrees="180" />

Renderowanie z kodu

Możesz też zmniejszyć rozmiar pliku APK, renderując obrazy proceduralnie. Renderowanie proceduralne zwalnia miejsce, ponieważ nie musisz już przechowywać pliku obrazu w pliku APK.

Kompresowanie plików PNG

Podczas procesu kompilacji narzędzie aapt może optymalizować zasoby obrazów umieszczone w folderze res/drawable/ za pomocą kompresji bezstratnej. Narzędzie aapt może na przykład przekonwertować obraz PNG w pełnej palecie kolorów, który nie wymaga więcej niż 256 kolorów, na 8-bitowy obraz PNG z paletą kolorów. Dzięki temu obraz ma taką samą jakość, ale mniejsze wykorzystanie pamięci.

Narzędzie aapt ma te ograniczenia:

  • Narzędzie aapt nie zmniejsza rozmiaru plików PNG znajdujących się w folderze asset/.
  • Aby narzędzie aapt mogło zoptymalizować pliki graficzne, muszą one używać 256 lub mniej kolorów.
  • Narzędzie aapt może zwiększyć rozmiar już skompresowanych plików PNG. Aby temu zapobiec , możesz użyć flagi isCrunchPngs, aby wyłączyć ten proces w przypadku plików PNG:
  • Kotlin

        buildTypes.all { isCrunchPngs = false }
        

    Dynamiczny

        buildTypes.all { isCrunchPngs = false }
        

Kompresowanie plików PNG i JPEG

Możesz zmniejszyć rozmiar plików PNG bez utraty jakości obrazu za pomocą narzędzi takich jak pngcrush, pngquant, lub zopflipng. Wszystkie te narzędzia mogą zmniejszyć rozmiar pliku PNG przy zachowaniu jakości obrazu.

Szczególnie skuteczne jest narzędzie pngcrush. Iteruje ono po filtrach PNG i parametrach zlib (Deflate), używając każdej kombinacji filtrów i parametrów do kompresowania obrazu. Następnie wybiera konfigurację, która daje najmniejszy skompresowany wynik.

Do kompresowania plików JPEG możesz używać narzędzi takich jak packJPG i guetzli.

Używanie formatu WebP

Zamiast plików PNG lub JPEG możesz też używać formatu WebP. Format WebP zapewnia kompresję stratną i przezroczystość, podobnie jak JPG i PNG, a także może zapewnić lepszą kompresję niż JPEG lub PNG.

Za pomocą Androida Studio możesz przekonwertować istniejące obrazy BMP, JPG, PNG lub statyczne GIF na format WebP. Więcej informacji znajdziesz w artykule Tworzenie obrazów WebP.

Używanie grafiki wektorowej

Grafiki wektorowej możesz używać do tworzenia ikon niezależnych od rozdzielczości i innych skalowalnych multimediów. Możesz używać tych grafik, aby znacznie zmniejszyć rozmiar pliku APK. Obrazy wektorowe są reprezentowane w Androidzie jako obiekty VectorDrawable. Dzięki obiektowi VectorDrawable plik o rozmiarze 100 bajtów może wygenerować ostry obraz o rozmiarze ekranu.

Renderowanie każdego obiektu VectorDrawable zajmuje jednak znacznie więcej czasu, a większe obrazy pojawiają się na ekranie jeszcze dłużej. Dlatego rozważ używanie tych grafik wektorowych tylko wtedy, gdy wyświetlasz małe obrazy.

Więcej informacji o pracy z obiektami VectorDrawable znajdziesz w artykule Obiekty drawable.

Używanie grafiki wektorowej w przypadku animowanych obrazów

Nie używaj AnimationDrawable do tworzenia animacji klatka po klatce, ponieważ wymaga to uwzględnienia osobnego pliku bitmapy dla każdej klatki animacji, co drastycznie zwiększa rozmiar pliku APK.

Zamiast tego używaj AnimatedVectorDrawableCompat do tworzenia animowanych obiektów drawable.

Zmniejszanie rozmiaru kodu natywnego i kodu Java

Aby zmniejszyć rozmiar kodu Java i kodu natywnego w aplikacji, możesz użyć tych metod.

Usuwanie niepotrzebnego wygenerowanego kodu

Upewnij się, że rozumiesz rozmiar każdego kodu, który jest generowany automatycznie. Na przykład wiele narzędzi do obsługi buforów protokołów generuje nadmierną liczbę metod i klas, co może podwoić lub potroić rozmiar aplikacji.

Unikanie wyliczeń

Pojedyncze wyliczenie może dodać do pliku classes.dex aplikacji około 1,0–1,4 KB. W przypadku złożonych systemów lub bibliotek udostępnionych te dodatki mogą się szybko kumulować. Jeśli to możliwe, rozważ użycie adnotacji @IntDef i zmniejszania rozmiaru kodu , aby usunąć wyliczenia i przekonwertować je na liczby całkowite. Ta konwersja typu zachowuje wszystkie zalety bezpieczeństwa typów wyliczeń.

Zmniejszanie rozmiaru plików binarnych kodu natywnego

Jeśli aplikacja używa kodu natywnego i Androida NDK, możesz też zmniejszyć rozmiar wersji aplikacji przeznaczonej do publikacji, optymalizując kod. Dwie przydatne techniki to usuwanie symboli do debugowania i nieekstrahowanie bibliotek natywnych.

Usuwanie symboli do debugowania

Używanie symboli do debugowania ma sens, jeśli aplikacja jest w trakcie opracowywania i nadal wymaga debugowania. Aby usunąć niepotrzebne symbole do debugowania z bibliotek natywnych, użyj narzędzia arm-eabi-strip dostępnego w Androidzie NDK. Następnie możesz skompilować kompilację do publikacji.

Unikanie ekstrahowania bibliotek natywnych

Podczas tworzenia wersji aplikacji przeznaczonej do publikacji spakuj nieskompresowane .so pliki w pliku APK, ustawiając useLegacyPackaging na false w pliku build.gradle.kts aplikacji. Wyłączenie tej flagi uniemożliwia usłudze PackageManager kopiowanie plików .so z pliku APK do systemu plików podczas instalacji. Ta metoda zmniejsza rozmiar aktualizacji aplikacji.

Utrzymywanie wielu małych plików APK

Plik APK może zawierać treści, które użytkownicy pobierają, ale nigdy nie używają, np. dodatkowe zasoby językowe lub zasoby dla poszczególnych gęstości ekranu. Aby zapewnić użytkownikom minimalny rozmiar pliku do pobrania, prześlij aplikację do Google Play za pomocą pakietów Android App Bundle. Przesyłanie pakietów aplikacji umożliwia Google Play generowanie i udostępnianie zoptymalizowanych plików APK dla każdej konfiguracji urządzenia użytkownika. Dzięki temu użytkownicy pobierają tylko kod i zasoby potrzebne do uruchomienia aplikacji. Nie musisz tworzyć, podpisywać ani zarządzać wieloma plikami APK, aby obsługiwać różne urządzenia, a użytkownicy otrzymują mniejsze i bardziej zoptymalizowane pliki do pobrania.

Jeśli nie publikujesz aplikacji w Google Play, możesz podzielić ją na kilka plików APK, które różnią się takimi czynnikami jak rozmiar ekranu lub obsługa tekstur GPU.

Gdy użytkownik pobierze aplikację, jego urządzenie otrzyma odpowiedni plik APK na podstawie funkcji i ustawień urządzenia. Dzięki temu urządzenia nie otrzymują zasobów dla funkcji, których nie mają. Jeśli na przykład użytkownik ma urządzenie hdpi, nie potrzebuje xxxhdpi zasobów, które możesz uwzględnić w przypadku urządzeń z wyświetlaczami o większej gęstości.

Więcej informacji znajdziesz w artykułach Tworzenie wielu plików APK i Obsługa wielu plików APK.