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 niesprawnymi sieciami 2G i 3G lub pracują nad abonamentami 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 zapisać jej rozmiar po opublikowaniu jej w Google Play. Android App Bundle to format przesyłania, który obejmuje cały skompilowany kod i zasoby aplikacji, ale opóźnia generowanie plików APK i podpisywanie ich w Google Play.

Model udostępniania aplikacji przez Google Play wykorzystuje Twój pakiet aplikacji do generowania i udostępniania zoptymalizowanych plików APK dla konfiguracji urządzeń każdego użytkownika, tak aby pobierał on tylko kod i zasoby niezbędne do uruchomienia Twojej aplikacji. Nie musisz tworzyć i podpisywać wielu plików APK ani nimi zarządzać, by obsługiwać różne urządzenia, a użytkownicy otrzymują mniejsze, lepiej zoptymalizowane pliki do pobrania.

W przypadku aplikacji opublikowanych z pakietami aplikacji w Google Play obowiązuje ograniczenie rozmiaru pobieranego pliku skompresowanego do 200 MB, dlatego zalecamy stosowanie się do wskazówek opisanych na tej stronie, aby jak najbardziej zmniejszyć rozmiar pobieranej aplikacji.

Struktura pliku APK

Zanim zmniejszysz rozmiar aplikacji, warto poznać strukturę jej pliku APK. Plik APK składa się z archiwum ZIP zawierającego wszystkie pliki wchodzące w skład aplikacji. Pliki te obejmują pliki klas Java, pliki zasobów oraz plik zawierający skompilowane zasoby.

Plik APK zawiera te katalogi:

  • META-INF/: zawiera pliki podpisu CERT.SF i CERT.RSA oraz 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ą skompilowane w resources.arsc.
  • lib/: zawiera skompilowany kod 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ż wymienione poniżej pliki. Obowiązkowe pole jest tylko AndroidManifest.xml:

  • resources.arsc: zawiera skompilowane zasoby. Ten plik zawiera treść XML ze wszystkich konfiguracji folderu res/values/. Narzędzie do tworzenia pakietów wyodrębnia zawartość XML, kompilowa ją do postaci binarnej i archiwizuje ją. Obejmuje to ciągi tekstowe i style językowe, a także ścieżki do treści, których nie ma bezpośrednio w pliku resources.arsc, takich jak pliki układu i obrazy.
  • classes.dex: zawiera klasy skompilowane w formacie DEX rozumienym przez maszynę wirtualną Dalvik lub ART.
  • AndroidManifest.xml: zawiera podstawowy plik manifestu Androida. Ten plik zawiera nazwę, wersję, prawa dostępu oraz odniesienia do plików biblioteki aplikacji. Plik wykorzystuje binarny format XML Androida.

Zmniejsz liczbę i rozmiar zasobów

Rozmiar pliku APK wpływa na to, jak szybko wczytuje się aplikacja, ile pamięci używa oraz ile energii. Możesz zmniejszyć rozmiar pliku APK, zmniejszając liczbę i rozmiar zawartych w nim zasobów. Możesz w szczególności usunąć zasoby, których Twoja aplikacja już nie używa, a zamiast nich używać skalowalnych obiektów Drawable. W tej sekcji omawiamy te metody oraz inne sposoby zmniejszenia zasobów aplikacji w celu zmniejszenia ogólnego rozmiaru pliku APK.

Usuń nieużywane zasoby

Narzędzie lint – statyczny analizator kodu dostępny w Android Studio – wykrywa w folderze res/ zasoby, do których nie odnosi się Twój kod. Gdy narzędzie lint wykryje potencjalnie nieużywany zasób w Twoim projekcie, wyświetli komunikat podobny do tego:

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

Biblioteki, które dodajesz 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")
        }
    }
}

Odlotowy

android {
    // Other settings.

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

Aby używać funkcji shrinkResources, włącz zmniejszanie kodu. W trakcie 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 o tym, jak Android Studio zmniejsza rozmiar pliku APK, znajdziesz w artykule Zmniejszanie, zaciemnianie i optymalizowanie aplikacji.

We wtyczce Androida do obsługi Gradle w wersji 7.0 i nowszych możesz zadeklarować konfiguracje obsługiwane przez Twoją aplikację. Gradle przekazuje te informacje do systemu kompilacji za pomocą rodzaju resourceConfigurations i opcji defaultConfig. System kompilacji zapobiega pojawianiu się w pliku APK zasobów z innych nieobsługiwanych konfiguracji, zmniejszając w ten sposób jego rozmiar. Więcej informacji o tej funkcji znajdziesz w artykule Usuwanie nieużywanych zasobów alternatywnych.

Minimalizuj wykorzystanie zasobów bibliotek

Gdy tworzysz aplikację na Androida, zwykle korzystasz z bibliotek zewnętrznych, aby zwiększyć jej użyteczność i wszechstronność. Możesz na przykład powołać się na AndroidX, aby zwiększyć wygodę użytkowników na starszych urządzeniach, albo użyć Usług Google Play, aby pobrać automatyczne tłumaczenia 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 Twoja aplikacja, możesz edytować pliki biblioteki, o ile licencja umożliwia jej modyfikowanie. Możesz też użyć alternatywnej biblioteki dostosowanej do komórek, aby dodać określone funkcje do swojej aplikacji.

Natywne dekodowanie obrazów animowanych

W Androidzie 12 (poziom interfejsu API 31) interfejs API NDK ImageDecoder jest rozszerzony, aby dekodować wszystkie klatki i dane o czasie z obrazów zawierających animowane pliki GIF i animowane formaty WebP.

Aby jeszcze bardziej zmniejszyć rozmiar plików APK i czerpać korzyści z przyszłych aktualizacji związanych z bezpieczeństwem i wydajnością, używaj ImageDecoder zamiast bibliotek innych firm.

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

Obsługuj tylko określone gęstości

Android obsługuje różne gęstości ekranu, na przykład:

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

Chociaż Android obsługuje wcześniejsze gęstości, nie musisz eksportować zrasteryzowanych zasobów do poszczególnych gęstości.

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

Jeśli Twoja aplikacja potrzebuje tylko skalowanych obrazów, możesz zaoszczędzić jeszcze więcej miejsca, umieszczając w usłudze drawable-nodpi/ pojedynczy wariant obrazu. Zalecamy dodanie do aplikacji co najmniej xxhdpi wersji obrazu.

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

Używanie obiektów, które można rysować

Niektóre obrazy nie wymagają zasobu obrazu statycznego. Platforma może dynamicznie rysować obraz w czasie działania. Obiekty Drawable lub <shape> w pliku XML mogą zajmować niewielką ilość miejsca w pliku APK. Dodatkowo obiekty XML Drawable generują obrazy monochromatyczne zgodne ze wskazówkami dotyczącymi Material Design.

Ponowne wykorzystanie zasobów

Możesz dołączyć osobne zasoby dla różnych wersji obrazu, np. wersji barwnych, zacienionych lub obróconych. Zalecamy jednak ponowne używanie tego samego zbioru zasobów i dostosowanie ich do potrzeb w czasie działania.

Android udostępnia kilka narzędzi do zmiany koloru zasobu za pomocą atrybutów android:tint i tintMode.

Możesz też pominąć zasoby, które są tylko obróconymi odpowiednikami innego zasobu. Poniższy fragment kodu zawiera przykład przekształcenia kciuka w górę w kciuk w dół przez obrócenie go na środku obrazu o 180 stopni:

<?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" />

Renderuj na podstawie kodu

Możesz też zmniejszyć rozmiar pliku APK przez proceduralne renderowanie obrazów. Renderowanie procedury pozwala zwolnić miejsce, ponieważ w pakiecie APK nie jest już przechowywany plik graficzny.

Zwiń pliki PNG

Narzędzie aapt może optymalizować zasoby obrazów umieszczone w komponencie res/drawable/ za pomocą bezstratnej kompresji podczas procesu kompilacji. Na przykład narzędzie aapt może przekonwertować plik PNG o rzeczywistych kolorach, który nie wymaga więcej niż 256 kolorów, na 8-bitowy plik PNG z paletą kolorów. Dzięki temu obraz będzie miał podobną jakość, ale zużycie pamięci będzie mniejsze.

aapt ma następujące ograniczenia:

  • Narzędzie aapt nie zmniejsza plików PNG znajdujących się w folderze asset/.
  • Pliki graficzne muszą używać maksymalnie 256 kolorów, aby narzędzie aapt mogło je zoptymalizować.
  • Narzędzie aapt może zwiększać rozmiar plików PNG, które są już skompresowane. Aby temu zapobiec, możesz użyć flagi isCrunchPngs do wyłączenia tego procesu w przypadku plików PNG:
  • Kotlin

        buildTypes.all { isCrunchPngs = false }
        

    Odlotowy

        buildTypes.all { isCrunchPngs = false }
        

Kompresuj pliki PNG i JPEG

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

Szczególnie skuteczne jest narzędzie pngcrush. Narzędzie to iteruje w oparciu o filtry PNG i parametry zlib (Deflate), wykorzystując każdą kombinację filtrów i parametrów do skompresowania obrazu. Następnie wybiera konfigurację, która da najmniejszy skompresowany plik wyjściowy.

Pliki JPEG możesz skompresować za pomocą narzędzi takich jak packJPG czy guetzli.

Użyj formatu pliku WebP

Zamiast plików PNG lub JPEG możesz też przesyłać obrazy w formacie WebP. Format WebP zapewnia kompresję stratną i przezroczystość, taką jak JPG i PNG, oraz zapewnia lepszą kompresję niż JPEG i PNG.

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

Używaj grafiki wektorowej

Za pomocą grafiki wektorowej możesz tworzyć ikony niezależne od rozdzielczości i inne skalowalne multimedia. Korzystając z tych obrazów, możesz znacznie zmniejszyć rozmiar pliku APK. Obrazy wektorowe są w Androidzie prezentowane jako obiekty VectorDrawable. Dzięki obiektowi VectorDrawable plik 100-bajtowy może wygenerować ostry obraz o rozmiarze ekranu.

Renderowanie każdego obiektu VectorDrawable przez system zajmuje jednak znacznie więcej czasu, a większe obrazy jeszcze dłużej pojawiają się na ekranie. Dlatego zalecamy korzystanie z tej grafiki wektorowej tylko do wyświetlania małych obrazów.

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

Używaj grafiki wektorowej do obrazów animowanych

Nie używaj funkcji AnimationDrawable do tworzenia animacji klatka po klatce, bo wymaga to dodawania osobnego pliku bitmapy na każdą klatkę animacji, co znacznie zwiększa rozmiar pliku APK.

Zamiast tego do tworzenia animowanych elementów graficznych wektorowych używaj kodu AnimatedVectorDrawableCompat.

Ogranicz kod natywny i kod Java

Aby zmniejszyć rozmiar kodu Java i natywnej bazy kodu w aplikacji, możesz użyć poniższych metod.

Usuń niepotrzebny wygenerowany kod

Pamiętaj, aby poznać ślad kodu, który jest generowany automatycznie. Na przykład wiele narzędzi do buforowania protokołów generuje nadmierną liczbę metod i klas, co może dwukrotnie lub trzykrotnie zwiększyć rozmiar aplikacji.

Unikaj wyliczeń

Pojedyncza wyliczenie może zwiększyć rozmiar pliku classes.dex aplikacji o ok. 1,0–1,4 KB. Takie dodatki mogą być szybko dodawane do złożonych systemów lub bibliotek udostępnionych. Jeśli to możliwe, rozważ skorzystanie z adnotacji @IntDef i zmniejszanie kodu, by usunąć wyliczenia i przekonwertować je na liczby całkowite. Konwersja tego typu zachowuje wszystkie korzyści związane z bezpieczeństwem tego typu, jakie zapewniają wyliczenia.

Zmniejsz rozmiar natywnych plików binarnych

Jeśli Twoja aplikacja korzysta z kodu natywnego i pakietu Android NDK, możesz też zmniejszyć jej rozmiar, optymalizując kod. Dwie przydatne metody to usuwanie symboli debugowania i pomijanie wyodrębniania bibliotek natywnych.

Usuń symbole do debugowania

Używanie symboli debugowania ma sens wtedy, gdy aplikacja jest wciąż rozwijana i nadal wymaga debugowania. Aby usunąć zbędne symbole debugowania z bibliotek natywnych, użyj narzędzia arm-eabi-strip dostępnego w pakiecie Android NDK. Następnie możesz skompilować kompilację wersji.

Unikaj wyodrębniania bibliotek natywnych

Tworząc wersję do publikacji, spakuj nieskompresowane pliki .so w pliku APK, ustawiając dla parametru useLegacyPackaging wartość false w pliku build.gradle.kts aplikacji. Wyłączenie tej flagi uniemożliwia PackageManager kopiowanie .so plików z pakietu APK do systemu plików podczas instalacji. Dzięki tej metodzie aktualizacje aplikacji są mniejsze.

Przechowywanie wielu prostych plików APK

Twój plik APK może zawierać treści, które użytkownicy pobierają, ale nigdy z nich nie korzystają, takie jak dodatkowe zasoby językowe lub zasoby dostosowane do gęstości ekranu. Aby użytkownicy mogli pobrać ją jak najmniej, prześlij ją do Google Play, korzystając z pakietów Android App Bundle. Dzięki przesyłaniu pakietów aplikacji Google Play może generować i udostępniać zoptymalizowane pliki APK dostosowane do konfiguracji urządzenia każdego użytkownika. Dzięki temu użytkownicy pobierają tylko kod i zasoby potrzebne do uruchomienia Twojej aplikacji. Nie musisz tworzyć i podpisywać wielu plików APK ani nimi zarządzać, by obsługiwać różne urządzenia. Użytkownicy mogą pobierać mniejsze, lepiej zoptymalizowane pliki.

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

Gdy użytkownik pobiera aplikację, urządzenie otrzymuje właściwy pakiet APK określony na podstawie funkcji i ustawień urządzenia. Dzięki temu urządzenia nie będą otrzymywać zasobów z funkcji, których nie mają. Jeśli na przykład użytkownik ma urządzenie z hdpi, nie potrzebuje zasobów xxxhdpi, które możesz uwzględnić na potrzeby urządzeń z wyświetlaczami o wyższej gęstości.

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