Zmniejsz rozmiar aplikacji

Użytkownicy często unikają pobierania aplikacji, które wydają się za duże, zwłaszcza na rynkach wschodzących, gdzie urządzenia łączą się z niestabilnymi sieciami 2G i 3G, lub opracowują abonamenty 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 natychmiast zapisać jej rozmiar po opublikowaniu 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 udostępniania aplikacji w Google Play wykorzystuje następnie Twój pakiet aplikacji do generowania i udostępniania zoptymalizowanych plików APK dla konfiguracji urządzeń poszczególnych użytkowników. Dzięki temu użytkownicy pobierają tylko kod i zasoby niezbędne do uruchomienia aplikacji. Nie musisz tworzyć i podpisywać wielu plików APK obsługiwanych na różnych urządzeniach ani nimi zarządzać, a użytkownicy uzyskują mniejsze, lepiej zoptymalizowane pliki do pobrania.

W przypadku aplikacji opublikowanych z pakietami aplikacji Google Play wymusza ograniczenie rozmiaru pobieranych plików skompresowanych do 200 MB. W przypadku korzystania z funkcji Play Feature Delivery i Play Asset Delivery możesz używać większych rozmiarów, 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.

Informacje o strukturze plików APK

Zanim zmniejszysz rozmiar aplikacji, warto poznać strukturę jej pliku APK. Plik APK to archiwum ZIP zawierające wszystkie pliki tworzące aplikację. Pliki te obejmują m.in. pliki klasy 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 związany z warstwą 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ż wymienione niżej pliki. Wymagane jest podanie tylko pola AndroidManifest.xml:

  • resources.arsc: zawiera skompilowane zasoby. Ten plik zawiera treść XML ze wszystkich konfiguracji folderu res/values/. Narzędzie do pakowania wyodrębnia zawartość XML, skompiluje ją do postaci binarnej i archiwizuje. Obejmuje to ciągi tekstowe i style językowe oraz ścieżki do treści, które nie są umieszczone bezpośrednio w pliku resources.arsc, np. do plików układu i obrazów.
  • 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 wpływa na to, jak szybko się wczytuje, ile pamięci zużywa oraz ile energii zużywa. Aby zmniejszyć rozmiar pliku APK, zmniejsz liczbę i rozmiar zawartych w nim zasobów. 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 i inne sposoby zmniejszenia zasobów w aplikacji, aby zmniejszyć ogólny rozmiar 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 odwołuje się Twój kod. Gdy narzędzie lint wykryje potencjalnie nieużywany zasób w projekcie, 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")
        }
    }
}

Odlotowe

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. Podczas 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 zmniejszania pliku APK w Android Studio 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 aplikację. Gradle przekazuje te informacje do systemu kompilacji za pomocą rodzaju resourceConfigurations i opcji defaultConfig. System kompilacji zapobiega wyświetlaniu w pliku APK zasobów z innych nieobsługiwanych konfiguracji, zmniejszając jego rozmiar. Więcej informacji o tej funkcji znajdziesz w artykule Usuwanie nieużywanych zasobów alternatywnych.

Minimalizuj wykorzystanie zasobów z bibliotek

Gdy tworzysz aplikację na Androida, zwykle korzystasz z bibliotek zewnętrznych, by zwiększyć przydatność i wszechstronność aplikacji. Możesz na przykład skorzystać z AndroidaX, by zwiększyć wygodę użytkowników na wcześniejszych urządzeniach, lub skorzystać z Usług Google Play, by pobrać automatyczne tłumaczenia tekstu w aplikacji.

Jeśli biblioteka jest przeznaczona dla 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 jej modyfikowanie. Możesz też użyć alternatywnej biblioteki przyjaznej dla urządzeń mobilnych, aby dodać do swojej aplikacji określone funkcje.

Natywne dekodowanie animowanego obrazu

W Androidzie 12 (poziom interfejsu API 31) interfejs API NDK ImageDecoder jest rozszerzony i dekoduje wszystkie klatki i dane o czasie z obrazów, które używają animowanych plików GIF i WebP.

Aby jeszcze bardziej zmniejszyć rozmiar pliku APK i korzystać z przyszłych aktualizacji dotyczących bezpieczeństwa 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

Mimo że Android obsługuje poprzednie gęstości, nie musisz eksportować zrastrowanych zasobów do poszczególnych 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 przeskalowanych obrazów, możesz zaoszczędzić jeszcze więcej miejsca, tworząc pojedynczy wariant obrazu w usłudze drawable-nodpi/. Zalecamy dodanie do aplikacji co najmniej xxhdpi wersji obrazu.

Więcej informacji o gęstościach ekranu znajdziesz w sekcji Rozmiary i gęstości ekranu.

Używanie obiektów rysowalnych

Niektóre obrazy nie wymagają zasobu obrazu statycznego. Platforma może zamiast tego dynamicznie rysować obraz w czasie działania aplikacji. Obiekty Drawable – lub <shape> w formacie XML – mogą zajmować niewielką ilość miejsca w pliku APK. Dodatkowo obiekty XML Drawable generują obrazy monochromatyczne zgodne z wytycznymi Material Design.

Ponowne wykorzystywanie zasobów

Możesz dodać osobny zasób dla odmian obrazu, np. podbarwione, zacienione lub obrócone wersje tego samego obrazu. Zalecamy jednak ponowne używanie tego samego zestawu zasobów i dostosowywanie ich 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 rotacyjnym odpowiednikiem innego zasobu. Ten fragment kodu zawiera 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ć, proceduralnie renderując obrazy. Renderowanie proceduralne pozwala zwolnić miejsce, ponieważ w pakiecie APK nie przechowujesz już pliku graficznego.

Cruncha, pliki PNG

Narzędzie aapt może zoptymalizować zasoby obrazu umieszczone w res/drawable/ przy użyciu bezstratnej kompresji podczas kompilacji. Narzędzie aapt może na przykład przekonwertować plik PNG z prawdziwymi kolorami, 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ł taką samą jakość, ale mniejszy rozmiar pamięci.

aapt ma te ograniczenia:

  • Narzędzie aapt nie zmniejsza plików PNG znajdujących się w folderze asset/.
  • Pliki obrazów mogą mieć maksymalnie 256 kolorów, aby można je było zoptymalizować za pomocą narzędzia aapt.
  • Narzędzie aapt może zwiększać rozmiar już skompresowanych plików PNG. Aby temu zapobiec, możesz użyć flagi isCrunchPngs do wyłączenia tego procesu w przypadku plików PNG:
  • Kotlin

        buildTypes.all { isCrunchPngs = false }
        

    Odlotowe

        buildTypes.all { isCrunchPngs = false }
        

Kompresuj pliki 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 przy zachowaniu postrzeganej jakości obrazu.

Szczególnie skuteczne jest narzędzie pngcrush. To narzędzie iteruje 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 generuje najmniejsze skompresowane dane wyjściowe.

Do skompresowania plików JPEG możesz użyć narzędzi takich jak packJPG czy guetzli.

Użyj formatu pliku WebP

Zamiast plików PNG lub JPEG możesz też użyć formatu pliku WebP. Format WebP zapewnia kompresję stratną i przejrzystość, np. JPG i PNG, i może zapewnić lepszą kompresję niż JPEG czy PNG.

Korzystając z Android Studio, możesz przekonwertować istniejące obrazy w formacie BMP, JPG, PNG lub statyczne pliki 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. Dzięki nim możesz znacznie zmniejszyć rozmiar pliku APK. Obrazy wektorowe są reprezentowane na Androidzie jako obiekty VectorDrawable. Korzystając z obiektu VectorDrawable, plik 100-bajtowy może wygenerować ostry obraz wielkości ekranu.

Wyrenderowanie każdego obiektu VectorDrawable przez system zajmuje jednak znacznie więcej czasu, a większe obrazy pojawiają się na ekranie jeszcze dłużej. Dlatego przy wyświetlaniu małych obrazów używaj grafiki wektorowej.

Więcej informacji o pracy z obiektami VectorDrawable znajdziesz w sekcji Elementy rysowalne.

Używaj grafiki wektorowej jako animowanych obrazów

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

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

Ogranicz kod natywny i kod Java

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

Usuń zbędny wygenerowany kod

Upewnij się, że znasz zasięg każdego kodu, który jest generowany automatycznie. Na przykład wiele narzędzi do buforowania protokołów generuje zbyt wiele metod i klas, co może skutkować dwukrotnie lub nawet trzykrotnym rozmiarem aplikacji.

Unikaj wyliczeń

Pojedyncze wyliczenie może dodać około 1,0–1,4 KB do pliku classes.dex aplikacji. Te dodatki mogą się szybko akumulować w przypadku złożonych systemów lub bibliotek udostępnionych. Jeśli to możliwe, rozważ użycie adnotacji @IntDef i zmniejszanie kodu w celu wyeliminowania wyliczeń i przekonwertowania ich na liczby całkowite. Konwersja tego typu zachowuje wszystkie korzyści związane z bezpieczeństwem tego typu wyliczenia.

Zmniejszanie rozmiaru natywnych plików binarnych

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

Usuń symbole debugowania

Używanie symboli debugowania ma sens, jeśli aplikacja jest w fazie opracowywania i nadal wymaga debugowania. Aby usunąć z bibliotek natywnych niepotrzebne symbole debugowania, użyj narzędzia arm-eabi-strip dostępnego w pakiecie Android NDK. Później możesz skompilować kompilację wersji.

Unikaj wyodrębniania bibliotek natywnych

Podczas tworzenia wersji produkcyjnej aplikacji utwórz pakiet nieskompresowanych plików .so w pliku APK, ustawiając parametr useLegacyPackaging na false w pliku build.gradle.kts aplikacji. Wyłączenie tej flagi uniemożliwia usłudze PackageManager kopiowanie plików .so z pakietu APK do systemu plików podczas instalacji. Ta metoda zmniejsza rozmiar aktualizacji aplikacji.

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 materiały o określonej gęstości ekranu. Aby ograniczyć pobieranie do minimum, prześlij aplikację do Google Play przy użyciu pakietów Android App Bundle. 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 w Google Play, możesz podzielić aplikację na kilka plików APK różniących się takimi czynnikami jak rozmiar ekranu czy obsługa tekstury 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 na potrzeby 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ć w przypadku urządzeń 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.