Zmniejsz rozmiar aplikacji

Użytkownicy często unikają pobierania aplikacji, które wydają im się zbyt duże, zwłaszcza na rynkach rozwijających się, gdzie urządzenia łączą się z niestabilnymi sieciami 2G i 3G lub działają na planach z ograniczonym limitem danych. Na tej stronie opisujemy, jak zmniejszyć rozmiar pliku do pobrania aplikacji, aby umożliwić jej pobranie większej liczbie użytkowników.

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 zasoby aplikacji, ale generowanie i podpisywanie pliku APK jest odkładane na czas publikacji w Google Play.

Model obsługi aplikacji w Google Play korzysta z Twojego pakietu aplikacji, aby generować i przesyłać zoptymalizowane pliki 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. Użytkownicy otrzymują mniejsze, bardziej zoptymalizowane pliki do pobrania.

Google Play stosuje ograniczenie rozmiaru skompresowanego pliku do pobrania na poziomie 200 MB w przypadku aplikacji publikowanych w pakietach aplikacji. Większe rozmiary są możliwe dzięki użyciu funkcji 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 w jak największym stopniu zmniejszyć rozmiar pliku do pobrania aplikacji.

Struktura pliku APK

Zanim zmniejszysz rozmiar aplikacji, warto poznać strukturę pliku APK. Plik APK składa się z archiwum ZIP zawierającego wszystkie pliki, z których składa się aplikacja. Te pliki obejmują 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, 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ą zgrupowane w resources.arsc.
  • lib/: zawiera skompilowany kod specyficzny dla warstwy oprogramowania procesora. Katalog ten zawiera podkatalog dla każdego typu platformy, np. armeabi, armeabi-v7a, arm64-v8a, x86, x86_64mips.

Plik APK zawiera też te pliki: Wymagany jest tylko element AndroidManifest.xml:

  • resources.arsc: zawiera skompilowane zasoby. Ten plik zawiera zawartość XML ze wszystkich konfiguracji folderu res/values/. Narzędzie do pakowania wyodrębnia te treści XML, kompiluje je w postaci binarnej i archiwizuje. Te treści obejmują ciągi tekstowe i style w różnych językach, a także ścieżki do treści, które nie są bezpośrednio zawarte w pliku resources.arsc, takich jak pliki układu i obrazy.
  • classes.dex: zawiera klasy skompilowane w formacie pliku DEX zrozumiałym dla maszyny wirtualnej Dalvik lub ART.
  • AndroidManifest.xml: zawiera podstawowy plik manifestu Androida. Plik ten zawiera listę nazw, wersji, praw dostępu i plików biblioteki aplikacji, do których odwołuje się aplikacja. Plik jest zapisany w binarnym formacie XML Androida.

Zmniejsz liczbę i rozmiar zasobów

Rozmiar pliku APK ma wpływ na szybkość wczytywania aplikacji, ilość wykorzystywanej pamięci i pobór mocy. Możesz zmniejszyć rozmiar pliku APK, zmniejszając liczbę i rozmiar zasobów, które zawiera. W szczególności możesz usunąć zasoby, których aplikacja już nie używa, oraz zastąpić pliki graficzne skalowalnymi obiektami Drawable. W tej sekcji omawiamy te metody oraz inne sposoby zmniejszania liczby zasobów w aplikacji, aby zmniejszyć ogólny rozmiar pliku APK.

Usuwanie nieużywanych zasobów

Narzędzie lint, czyli analizator kodu stałego zawarty w Android Studio, wykrywa zasoby w folderze res/, do których nie odwołuje się kod. Gdy narzędzie lint wykryje w Twoim projekcie potencjalnie niewykorzystany zasób, 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 pliku build.gradle.kts aplikacji włączysz opcję shrinkResources.

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żywać 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 skracaniu kodu i zasobów oraz innych sposobach zmniejszania rozmiaru pliku APK w Android Studio znajdziesz w artykule Skracanie, zaciemnianie i optymalizowanie aplikacji.

W pliku Android Gradle Plugin w wersji 7.0 lub nowszej możesz deklarować konfiguracje obsługiwane przez aplikację. Gradle przekazuje te informacje systemowi kompilacji za pomocą resourceConfigurationsflavor i opcji defaultConfig. System kompilacji zapobiega wtedy pojawianiu się w pliku APK zasobów z innych nieobsługiwanych konfiguracji, co zmniejsza jego rozmiar. 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ć użyteczność i wszechstronność aplikacji. Możesz na przykład używać AndroidX, aby poprawić wrażenia użytkowników na starszych urządzeniach, lub Usług Google Play, aby pobierać automatyczne tłumaczenia tekstu w aplikacji.

Jeśli biblioteka została zaprojektowana na potrzeby serwera lub komputera, 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 modyfikowanie biblioteki. Możesz też użyć alternatywnej biblioteki zoptymalizowanej pod kątem urządzeń mobilnych, aby dodać do aplikacji określone funkcje.

Dekodowanie natywnego obrazu animowanego

W Androidzie 12 (poziom interfejsu API 31) interfejs API NDKImageDecoder został rozszerzony o funkcję dekodowania wszystkich klatek i danych dotyczących czasu dla obrazów używających formatów animowanych GIF-ów i animowanych plików WebP.

Zamiast bibliotek innych firm używaj bibliotek ImageDecoder, aby zmniejszyć rozmiar pliku APK i korzystać z przyszłych aktualizacji dotyczących zabezpieczeń i wydajności.

Więcej informacji o interfejsie API ImageDecoder znajdziesz w dokumentacji API reference oraz w przykładowym pliku na GitHubie.

Obsługują tylko określone wartości 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 te gęstości, nie musisz eksportować zasobów rastrowych do każdej gęstości.

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

Jeśli Twoja aplikacja potrzebuje tylko obrazów pomniejszonych, możesz zaoszczędzić jeszcze więcej miejsca, korzystając z jednego wariantu obrazu w formacie drawable-nodpi/. Zalecamy uwzględnienie w aplikacji co najmniej 1 wariantu obrazu xxhdpi.

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

Używanie obiektów do rysowania

Niektóre obrazy nie wymagają statycznych zasobów obrazów. Platforma może zamiast tego rysować obraz dynamicznie w czasie działania. Obiekty Drawable (lub <shape> w XML) zajmują w pliku APK bardzo mało miejsca. Dodatkowo obiekty XML Drawable tworzą monochromatyczne obrazy zgodne ze wskazówkami dotyczącymi Material Design.

Ponowne używanie zasobów

Możesz dołączyć osobny zasób dla wersji obrazu, takich jak wersje tego samego obrazu z przyciemnieniem, zacienieniem lub obrócone. Zalecamy jednak ponowne używanie tego samego zestawu zasobów i dostosowywanie go w razie potrzeby w czasie wykonywania.

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

Możesz też pominąć zasoby, które są tylko obraconym odpowiednikiem innego zasobu. Ten fragment kodu pokazuje, jak zmienić „kciuk w górę” na „kciuk w dół” przez obrócenie 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" />

Renderowanie z kodu

Rozmiar pliku APK możesz też zmniejszyć, stosując procedurowy sposób renderowania obrazów. Renderowanie proceduralne oszczędza miejsce, ponieważ nie musisz już przechowywać pliku graficznego w pliku APK.

Kompresowanie plików PNG

Narzędzie aapt może optymalizować zasoby obrazów umieszczone w res/drawable/ za pomocą bezstratnej kompresji podczas procesu kompilacji. Na przykład narzędzie aapt może przekonwertować plik PNG w kolorze rzeczywistym, który nie wymaga więcej niż 256 kolorów, do 8-bitowego pliku PNG z paletą kolorów. W rezultacie obraz będzie miał taką samą jakość, ale zajmie mniej miejsca w pamięci.

aapt ma te ograniczenia:

  • Narzędzie aapt nie zmniejsza plików PNG znajdujących się w folderze asset/.
  • Aby narzędzie aapt mogło zoptymalizować pliki graficzne, muszą one zawierać maksymalnie 256 kolorów.
  • Narzędzie aapt może rozszerzać już skompresowane pliki 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 }
        

    Groovy

        buildTypes.all { isCrunchPngs = false }
        

Kompresowanie plików PNG i JPEG

Rozmiary plików PNG możesz zmniejszać bez utraty jakości obrazu, korzystając z narzędzi takich jak pngcrush, pngquant lub zopflipng. Wszystkie te narzędzia mogą zmniejszyć rozmiar pliku PNG, zachowując przy tym jakość obrazu.

Narzędzie pngcrush jest szczególnie skuteczne. To narzędzie przechodzi przez 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 najmniejsze wyjście po skompresowaniu.

Aby skompresować pliki JPEG, możesz użyć narzędzi takich jak packJPG i guetzli.

Używanie formatu pliku WebP

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

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

Używanie grafik wektorowych

Grafiki wektorowej możesz używać do tworzenia ikon niezależnych od rozdzielczości i innych skalowanych multimediów. Dzięki tym grafikom możesz znacznie zmniejszyć ślad APK. Obrazy wektorowe są w Androidzie reprezentowane jako obiekty VectorDrawable. W przypadku obiektu VectorDrawable plik o rozmaju 100 bajtów może wygenerować ostry obraz o rozmiarze ekranu.

Jednak system potrzebuje znacznie więcej czasu na renderowanie każdego obiektu VectorDrawable, a większe obrazy wyświetlają się jeszcze dłużej. Dlatego rozważ użycie grafik wektorowych tylko wtedy, gdy wyświetlasz małe obrazy.

Więcej informacji o obsługiwaniu obiektów VectorDrawable znajdziesz w artykule Obiekty rysowalne.

Używanie grafiki wektorowej do obrazów animowanych

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

Zamiast tego użyj AnimatedVectorDrawableCompat, aby tworzyć animowane wektory drawable.

Ograniczanie kodu natywnego i Java

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

Usuwanie niepotrzebnego wygenerowanego kodu

Dowiedz się, jaki ślad pozostawia kod generowany automatycznie. Na przykład wiele narzędzi do buforowania protokołów generuje nadmierną liczbę metod i klas, co może podwoić lub potroić rozmiar aplikacji.

Unikaj enumeracji

Pojedynczy typ enum może zwiększyć rozmiar pliku classes.dex aplikacji o 1,0–1,4 KB. W przypadku złożonych systemów lub bibliotek współdzielonych te dodatki mogą szybko się kumulować. Jeśli to możliwe, użyj adnotacji @IntDefskracania kodu, aby usunąć wyliczenia i przekształcić je w liczby całkowite. Ta konwersja zachowuje wszystkie zalety bezpieczeństwa typów enum.

Zmniejsz rozmiar natywnych plików binarnych

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

Usuwanie symboli debugowania

Korzystanie z symboli debugowania ma sens, jeśli aplikacja jest w trakcie tworzenia i nadal wymaga debugowania. Aby usunąć zbędne symbole debugowania z bibliotek natywnych, użyj narzędzia arm-eabi-strip dostępnego w Android NDK. Następnie możesz skompilować wersję wydania.

Unikaj wyodrębniania bibliotek natywnych

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

Utrzymywanie wielu smukłych plików APK

Plik APK może zawierać treści, które użytkownicy pobierają, ale nigdy z nich nie korzystają, np. zasoby dla dodatkowych języków lub zasoby dla różnych gęstości ekranu. Aby zapewnić użytkownikom minimalny rozmiar pliku do pobrania, 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 dla każdej konfiguracji urządzenia użytkownika, dzięki czemu pobiera on 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. Użytkownicy otrzymują mniejsze, bardziej zoptymalizowane pliki do pobrania.

Jeśli nie publikujesz aplikacji w Google Play, możesz podzielić ją na kilka pakietów APK, które różnią się od siebie pod względem takich czynników jak rozmiar ekranu czy obsługa tekstur GPU.

Gdy użytkownik pobiera aplikację, jego urządzenie otrzymuje 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ć na urządzeniach z wyświetlaczami o wyższej gęstości.

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