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 działają w ramach abonamentów z limitami danych. Na tej stronie dowiesz się, jak zmniejszyć rozmiar pobieranej 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ć rozmiar aplikacji 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 przesyłania aplikacji w Google Play wykorzystuje pakiet aplikacji do generowania i przesyłania zoptymalizowanych plików APK na potrzeby konfiguracji urządzenia każdego użytkownika. Dzięki temu pobierają oni 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 pobierają mniejsze i bardziej zoptymalizowane pliki.

W przypadku aplikacji opublikowanych w postaci pakietów aplikacji Google Play stosuje ograniczenie rozmiaru skompresowanego pliku do pobrania wynoszące 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 liczbę instalacji i odinstalowań. Dlatego zalecamy stosowanie wytycznych opisanych na tej stronie, aby jak najbardziej zmniejszyć rozmiar pobieranej aplikacji.

Struktura pliku APK

Zanim zmniejszysz rozmiar aplikacji, warto poznać strukturę pliku APK. Plik APK to archiwum ZIP zawierające wszystkie pliki, z których składa się aplikacja. 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.SFCERT.RSA oraz plik manifestu MANIFEST.MF.
  • assets/: zawiera komponenty aplikacji, które aplikacja może pobrać za pomocą obiektu AssetManager.
  • res/: zawiera zasoby, które nie są kompilowane w 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_64mips.

Plik APK zawiera też te pliki: Wymagane jest tylko pole AndroidManifest.xml:

  • resources.arsc: zawiera skompilowane zasoby. Ten plik zawiera treść XML ze wszystkich konfiguracji folderu res/values/. Narzędzie do pakowania wyodrębnia tę zawartość XML, kompiluje ją do postaci binarnej i archiwizuje. Obejmuje ona 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 pliku DEX, który jest rozpoznawany przez maszynę wirtualną Dalvik lub ART.
  • AndroidManifest.xml: zawiera główny plik manifestu Androida. Ten plik zawiera nazwę, wersję, prawa dostępu i pliki biblioteki, do których odwołuje się aplikacja. Plik jest w binarnym formacie XML Androida.

Zmniejsz liczbę i rozmiar zasobów

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

Usuwanie nieużywanych zasobów

Narzędzie lint, czyli statyczny analizator kodu, który jest częścią Android Studio, wykrywa w folderze res/ zasoby, do których nie odwołuje się Twój kod. Gdy narzędzie lint wykryje w Twoim projekcie potencjalnie nieużywane zasoby, wyświetli komunikat podobny do tego:

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

Biblioteki dodane do kodu mogą zawierać nieużywane zasoby. Gradle może automatycznie usuwać zasoby w Twoim imieniu, jeśli włączysz shrinkResources w pliku build.gradle.kts aplikacji.

Kotlin

android {
    // Other settings.

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

Groovy

android {
    // Other settings.

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

Aby użyć shrinkResources, włącz kompresowanie 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 kodu i zasobów oraz innych sposobach, w jakie Android Studio zmniejsza rozmiar pliku APK, znajdziesz w artykule Zmniejszanie, zaciemnianie i optymalizowanie aplikacji.

W wtyczce Androida do obsługi Gradle w wersji 7.0 lub nowszej możesz zadeklarować konfiguracje, które obsługuje Twoja aplikacja. Gradle przekazuje te informacje do systemu kompilacji za pomocą resourceConfigurations wersji i opcji defaultConfig. System kompilacji uniemożliwia następnie 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 wykorzystania zasobów z bibliotek

Podczas tworzenia aplikacji na Androida zwykle używasz zewnętrznych bibliotek, aby zwiększyć jej użyteczność i wszechstronność. Możesz na przykład odwoływać się do AndroidaX, aby zwiększyć wygodę użytkowników starszych urządzeń, 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 Twoja aplikacja nie potrzebuje. Aby uwzględnić tylko te części biblioteki, których potrzebuje Twoja aplikacja, możesz edytować pliki biblioteki, jeśli licencja pozwala na jej modyfikowanie. Możesz też użyć alternatywnej biblioteki zoptymalizowanej pod kątem urządzeń mobilnych, aby dodać do aplikacji określone funkcje.

Dekodowanie natywnych animowanych obrazów

W Androidzie 12 (poziom interfejsu API 31) interfejs NDKImageDecoder API został rozszerzony, aby dekodować wszystkie klatki i dane o czasie z obrazów, które używają formatów plików animowany GIF i animowany 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 ImageDecoder API znajdziesz w API referenceprzykładzie w GitHub.

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

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

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

Android obsługuje powyższe gęstości, ale nie musisz eksportować zasobów rastrowych w 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łączać 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 przeskalowanych obrazów, możesz zaoszczędzić jeszcze więcej miejsca, mając tylko jeden wariant obrazu w drawable-nodpi/. Zalecamy dodanie do aplikacji co najmniej xxhdpi wersji obrazu.

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

Używanie obiektów rysowalnych

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

Ponowne wykorzystanie zasobów

Możesz dodać osobny zasób dla odmian obrazu, takich jak wersje przyciemnione, zacienione lub obrócone. Zalecamy jednak ponowne używanie tego samego zestawu zasobów i dostosowywanie ich w razie potrzeby w czasie działania programu.

Android udostępnia kilka narzędzi do zmiany koloru komponentu za pomocą atrybutów android:tinttintMode.

Możesz też pominąć komponenty, które są tylko obróconym odpowiednikiem innego komponentu. Poniższy fragment kodu pokazuje, jak zmienić „kciuk w górę” na „kciuk w dół”, obracając obraz o 180 stopni wokół jego ś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

aapt narzędzie może optymalizować zasoby obrazów umieszczone w res/drawable/ za pomocą kompresji bezstratnej podczas procesu kompilacji. Na przykład narzędzie aapt może przekonwertować obraz PNG w pełnej gamie kolorów, który nie wymaga więcej niż 256 kolorów, na 8-bitowy obraz PNG z paletą kolorów. W ten sposób uzyskasz obraz o takiej samej jakości, ale zajmujący mniej miejsca w pamięci.

Formularz 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 obrazów, muszą one zawierać maksymalnie 256 kolorów.
  • Narzędzie aapt może powiększać pliki PNG, które są już skompresowane. Aby temu zapobiec, możesz użyć flagi isCrunchPngs, aby wyłączyć ten proces w przypadku plików PNG:
  • Kotlin

        buildTypes.all { isCrunchPngs = false }
        

    Groovy

        buildTypes.all { isCrunchPngs = false }
        

Kompresowanie plików PNG i JPEG

Rozmiar plików PNG możesz zmniejszyć 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 postrzeganej jakości obrazu.

Narzędzie pngcrush jest szczególnie skuteczne. To narzędzie iteruje filtry PNG i parametry zlib (Deflate), używając każdej kombinacji filtrów i parametrów do kompresji obrazu. Następnie wybiera konfigurację, która daje najmniejszy skompresowany wynik.

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

Używanie formatu pliku 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, ale może zapewniać lepszą kompresję niż JPEG lub PNG.

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

Używanie grafiki wektorowej

Za pomocą grafiki wektorowej możesz tworzyć ikony niezależne od rozdzielczości i inne skalowalne multimedia. Możesz użyć tych grafik, aby znacznie zmniejszyć rozmiar pliku APK. Obrazy wektorowe są reprezentowane w Androidzie jako obiekty VectorDrawable. W przypadku obiektu VectorDrawable plik o rozmiarze 100 bajtów może wygenerować ostry obraz o rozmiarze ekranu.

Jednak renderowanie każdego obiektu zajmuje systemowi znacznie więcej czasu, a wyświetlanie większych obrazów trwa jeszcze dłużej.VectorDrawable Dlatego używaj tych grafik wektorowych tylko wtedy, gdy wyświetlasz małe obrazy.

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

Używanie grafiki wektorowej w przypadku animowanych obrazów

Nie używaj tagu AnimationDrawable do tworzenia animacji klatka po klatce, ponieważ wymaga to dołączenia osobnego pliku bitmapy dla każdej klatki animacji, co znacznie zwiększa rozmiar pliku APK.

Zamiast tego użyj elementu AnimatedVectorDrawableCompat, aby utworzyć animowane rysunki wektorowe.

Ograniczanie kodu natywnego i kodu Java

Aby zmniejszyć rozmiar kodu Java i kodu natywnego w aplikacji, możesz zastosować te metody.

Usuwanie niepotrzebnego wygenerowanego kodu

Pamiętaj, aby poznać zakres działania każdego automatycznie wygenerowanego kodu. Na przykład wiele narzędzi do obsługi buforów protokołu generuje zbyt dużą liczbę metod i klas, co może podwoić lub potroić rozmiar aplikacji.

Unikaj wyliczeń

Pojedynczy typ wyliczeniowy może zwiększyć rozmiar pliku classes.dex aplikacji o 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, użyj adnotacji @IntDefzmniejszania kodu, aby usunąć wyliczenia i przekonwertować je na liczby całkowite. Taka konwersja typu zachowuje wszystkie zalety bezpieczeństwa typów wyliczeń.

Zmniejszanie rozmiaru binarnych plików natywnych

Jeśli Twoja aplikacja korzysta z kodu natywnego i pakietu Android NDK, możesz też zmniejszyć rozmiar wersji aplikacji przeznaczonej do publikacji, optymalizując kod. Dwie przydatne techniki to usuwanie symboli debugowania i niewyodrębnianie bibliotek natywnych.

Usuwanie symboli do debugowania

Używanie symboli debugowania ma sens, jeśli aplikacja jest w trakcie opracowywania i wymaga debugowania. Użyj arm-eabi-stripnarzędzia dostępnego w pakiecie Android NDK, aby usunąć z bibliotek natywnych niepotrzebne symbole debugowania. Następnie możesz skompilować wersję do udostępnienia.

Unikanie wyodrębniania bibliotek natywnych

Podczas tworzenia wersji aplikacji do publikacji spakuj nieskompresowane pliki .so w pakiecie APK, ustawiając wartość useLegacyPackaging na false w pliku build.gradle.kts aplikacji. Wyłączenie tego flagi uniemożliwia PackageManager kopiowanie plików .so z pliku APK do systemu plików podczas instalacji. Dzięki tej metodzie aktualizacje aplikacji będą mniejsze.

Utrzymywanie wielu uproszczonych plików APK

Plik APK może zawierać treści, które użytkownicy pobierają, ale nigdy nie używają, np. dodatkowe języki lub zasoby dla poszczególnych gęstości ekranu. Aby zapewnić użytkownikom minimalny rozmiar pobierania, prześlij aplikację do Google Play za pomocą pakietów aplikacji na Androida. Przesyłanie pakietów aplikacji umożliwia Google Play generowanie i przesyłanie zoptymalizowanych plików APK na potrzeby konfiguracji urządzeń poszczególnych użytkowników. Dzięki temu pobierają oni 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 pobierają mniejsze i bardziej zoptymalizowane pliki.

Jeśli nie publikujesz aplikacji w Google Play, możesz podzielić ją na kilka plików APK, które będą się różnić np. rozmiarem ekranu lub obsługą tekstur GPU.

Gdy użytkownik pobierze Twoją aplikację, na jego urządzenie zostanie przesłany 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 zasobów xxxhdpi, 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 APKObsługa wielu plików APK.