Zmniejsz rozmiar aplikacji

Użytkownicy często unikają pobierania aplikacji, które wydają się za duże, zwłaszcza na rynkach wschodzących, na których urządzenia łączą się z niestabilnymi sieciami 2G i 3G, lub opracowują abonamenty z limitami 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. Android App Bundle to format przesyłania, który uwzględnia cały skompilowany kod i zasoby aplikacji, ale opóźnia wygenerowanie pliku APK i podpisanie go 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. Korzystając z funkcji Play Feature Delivery i Play Asset Delivery, możesz używać w większym rozmiarze, ale zwiększenie rozmiaru aplikacji może negatywnie wpłynąć na jej sukces i zwiększyć liczbę odinstalowań. Dlatego zalecamy zastosowanie wskazówek opisanych na tej stronie w celu jak największego zmniejszenia rozmiaru pobieranej 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. Ten katalog zawiera podkatalog na potrzeby poszczególnych typów platform, takich jak armeabi, armeabi-v7a, arm64-v8a, x86, x86_64 czy mips.

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ą zawarte bezpośrednio w pliku resources.arsc, takich jak pliki układu i obrazy.
  • classes.dex: zawiera klasy skompilowane w formacie pliku DEX obsługiwanym przez maszynę wirtualną Dalvik lub ART.
  • AndroidManifest.xml: zawiera podstawowy plik manifestu Androida. Ten plik zawiera nazwę, wersję i prawa dostępu aplikacji oraz odniesienia do plików bibliotek. Plik wykorzystuje binarny format XML dla Androida.

Zmniejsz liczbę i rozmiar zasobów

Rozmiar pliku APK ma wpływ na szybkość wczytywania aplikacji, ilość wykorzystywanej pamięci i poziom zużycia energii. Możesz zmniejszyć rozmiar pliku APK, zmniejszając liczbę i rozmiar zasobów, które zawiera. Możesz na przykład usuwać zasoby, których aplikacja już nie używa, oraz używać skalowalnych obiektów Drawable zamiast plików graficznych. W tej sekcji omawiamy te metody oraz inne sposoby zmniejszania liczby zasobów w aplikacji, aby zmniejszyć ogólny rozmiar pliku APK.

Usuń nieużywane zasoby

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łączysz shrinkResources w pliku build.gradle.kts Twojej 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ż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 do systemu kompilacji za pomocą rodzaju resourceConfigurations 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 skorzystać z AndroidaX, by zwiększyć wygodę użytkowników na starszych urządzeniach, lub skorzystać z Usług Google Play, by pobrać automatyczne tłumaczenia tekstu w aplikacji.

Jeśli biblioteka jest przeznaczona do 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 dostosowanej do urządzeń mobilnych, by dodać do swojej 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 ich czasu trwania w przypadku obrazów w formacie animowanego GIF-a i animowanego 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 Twoich użytkowników korzysta z urządzeń o określonej gęstości ekranu, zastanów się, czy nie musisz uwzględniać w swojej aplikacji zasobów o określonej gęstości ekranu. Jeśli nie dodasz 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 obrazów pomniejszonych, możesz zaoszczędzić jeszcze więcej miejsca, korzystając z jednego wariantu obrazu w formacie drawable-nodpi/. Zalecamy dodanie do aplikacji co najmniej xxhdpi wersji obrazu.

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 generują obrazy monochromatyczne zgodne z wytycznymi Material Design.

Ponowne używanie zasobów

Możesz dołączyć osobny zasób dla wersji obrazu, np. zabarwionych, zacienionych lub obróconych wersji tego samego obrazu. 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:tint i tintMode.

Możesz też pominąć zasoby, które są tylko obraconym odpowiednikiem innego zasobu. Ten fragment kodu przedstawia przykład zmiany kciuka w górę w kciuk w dół przez obrócenie środka obrazu i 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ć, programowo renderując obrazy. Renderowanie proceduralne zwalnia miejsce, ponieważ nie musisz już przechowywać pliku graficznego w pliku APK.

Cruncha, pliki 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. Dzięki temu 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 rozszerzyć 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 }
        

    Odlotowe

        buildTypes.all { isCrunchPngs = false }
        

Kompresowanie plików PNG i JPEG

Możesz zmniejszyć rozmiar pliku PNG bez utraty jakości obrazu, korzystając z takich narzędzi jak pngcrush, pngquant czy 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 nim możesz znacznie zmniejszyć rozmiar pliku APK. Obrazy wektorów są reprezentowane w Androidzie 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 pracy z obiektami VectorDrawable znajdziesz w sekcji Elementy 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 do każdej klatki animacji, co znacznie zwiększa rozmiar pliku APK.

Zamiast tego użyj funkcji AnimatedVectorDrawableCompat, aby utworzyć animowane wektorowe obiekty rysunkowe.

Ograniczanie kodu natywnego i Java

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

Usuwanie niepotrzebnego wygenerowanego kodu

Pamiętaj, aby zapoznać się z zawartością każdego 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 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 korzyści związane z bezpieczeństwem typów enum.

Zmniejszanie rozmiaru natywnych plików binarnych

Jeśli aplikacja używa 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

Używanie symboli debugowania ma sens, jeśli aplikacja jest w fazie opracowywania 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 w pliku APK, ustawiając w pliku build.gradle.kts aplikacji wartość useLegacyPackaging na false. Wyłączenie tej flagi uniemożliwi 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. dodatkowe zasoby językowe 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. Po przesł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 niezbędne do uruchomienia Twojej aplikacji. Nie musisz tworzyć i podpisywać wielu plików APK ani zarządzać nimi, aby obsługiwać różne urządzenia, a użytkownicy pobierają pliki mniejsze i bardziej zoptymalizowane.

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 pobierze Twoją aplikację, urządzenie otrzyma odpowiedni plik APK z funkcjami i ustawieniami 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.