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 funkcjom Play Feature Delivery i Play Asset Delivery, ale zwiększenie rozmiaru aplikacji może negatywnie wpłynąć na jej skuteczność 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 podpisuCERT.SF
iCERT.RSA
, a także plik manifestuMANIFEST.MF
.assets/
: zawiera zasoby aplikacji, które aplikacja może pobrać za pomocą obiektuAssetManager
.res/
: zawiera zasoby, które nie są zgrupowane wresources.arsc
.lib/
: zawiera skompilowany kod, który jest specyficzny dla warstwy oprogramowania procesora. Katalog ten zawiera podkatalog dla każdego typu platformy, np.armeabi
,armeabi-v7a
,arm64-v8a
,x86
,x86_64
imips
.
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 folderures/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 językowe, a także ścieżki do treści, które nie są bezpośrednio zawarte w plikuresources.arsc
, takich jak pliki układu i obrazy.classes.dex
: zawiera klasy skompilowane w formacie pliku DEX, który jest obsługiwany przez maszynę wirtualną 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. Możesz na przykład 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 rozmiaru 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 nieużywany 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ą resourceConfigurations
flavor 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 bibliotek zewnętrznych, 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 xxhdpi
wariantu 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
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, 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 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 renderowanie obrazów. Renderowanie proceduralne pozwala zwolnić 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. 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 folderzeasset/
. - 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ć 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
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
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 @IntDef
i skracania 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 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. 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 Android App Bundle. 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żna 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 APK i Obsługa wielu plików APK.