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 podpisuCERT.SF
iCERT.RSA
oraz plik manifestuMANIFEST.MF
.assets/
: zawiera komponenty aplikacji, które aplikacja może pobrać za pomocą obiektuAssetManager
.res/
: zawiera zasoby, które nie są kompilowane wresources.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
imips
.
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 folderures/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 plikuresources.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 reference
i przykł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:tint
i tintMode
.
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 folderzeasset/
. - 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ć flagiisCrunchPngs
, 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 packJPG i guetzli.
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 @IntDef
i zmniejszania 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-strip
narzę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 APK i Obsługa wielu plików APK.