Określanie, które zasoby mają być przechowywane

Gdy włączysz optymalizację aplikacji, domyślne działanie optymalizatora będzie się różnić w zależności od wersji R8.

  • W przypadku zaktualizowanego języka DSL, który jest dostępny w AGP 9.3 i nowszych wersjach, zmniejszanie zasobów jest domyślnie włączone, gdy włączona jest optymalizacja. Pamiętaj, że starsza wersja DSL, która wymaga wyraźnego włączenia optymalizacji kodu i zasobów, jest nadal obsługiwana.
  • W przypadku wersji starszych niż AGP 9.3 ustawienie isShrinkResources = true nakazuje optymalizatorowi usunięcie nieużywanych zasobów, co pomaga zmniejszyć rozmiar aplikacji. Zmniejszanie zasobów działa tylko w połączeniu ze zmniejszaniem kodu, więc jeśli optymalizujesz zasoby, ustaw też isMinifyEnabled = true.

AGP 9.3+ (Kotlin)

buildTypes {
    release {
        optimization {
            enable = true // Enables code and resource optimizations.
        }
    }
}

AGP 9.3+ (Groovy)

buildTypes {
    release {
        optimization {
            enable = true // Enables code and resource optimizations.
        }
    }
}

Starsza wersja DSL (Kotlin)

buildTypes {
    release {
        isMinifyEnabled = true
        isShrinkResources = true
        ...
    }
}

Starsza wersja DSL (Groovy)

buildTypes {
    release {
        minifyEnabled = true
        shrinkResources = true
        ...
    }
}

Jeśli chcesz zachować lub odrzucić określone zasoby, utwórz w zasobach projektu plik XML keep, np. res/raw/my.package.keep.xml. Plik keep ma te komponenty:

  • Tag <resources> – zawiera wszystkie elementy zasobów podrzędnych i atrybuty zachowywania/odrzucania.
  • Atrybut tools:keep – akceptuje rozdzieloną przecinkami listę nazw zasobów, które mają zostać zachowane.
  • Atrybut tools:discard – akceptuje rozdzieloną przecinkami listę nazw zasobów, które identyfikują zasoby do odrzucenia.

Użyj gwiazdki jako symbolu wieloznacznego, aby odwołać się do wielu zasobów w tym samym folderze, np.:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
    tools:discard="@layout/unused2" />

Określanie, które zasoby mają zostać odrzucone, może wydawać się zbędne, skoro można je usunąć, ale odrzucanie zasobów może być przydatne w przypadku korzystania z wariantów kompilacji.

Kierowanie na określone wersje

Aby usunąć zasoby tylko w niektórych wariantach kompilacji, umieść wszystkie zasoby w wspólnym katalogu projektu, a następnie utwórz osobny plik my.package.build.variant.keep.xml dla każdego wariantu kompilacji w katalogu zasobów wariantu. W pliku keep ręcznie określ zasoby do usunięcia, gdy dany zasób wydaje się być używany w kodzie (a więc nie jest usuwany przez narzędzie do zmniejszania kodu), ale wiesz, że w przypadku danego wariantu kompilacji nie będzie używany.

Usuwanie nieużywanych zasobów alternatywnych

Optymalizator usuwa tylko zasoby, do których nie odwołuje się kod aplikacji, co oznacza, że nie usuwa alternatywnych zasobów dla różnych konfiguracji urządzeń.

Użyj właściwości resConfigs Android Gradle w pliku build.gradle modułu aplikacji, aby usunąć zasoby alternatywne, których aplikacja nie potrzebuje.

Jeśli na przykład używasz biblioteki, która zawiera zasoby językowe (np. Usługi Google Play), Twoja aplikacja zawiera wszystkie przetłumaczone ciągi tekstowe komunikatów w tych bibliotekach, niezależnie od tego, czy reszta aplikacji jest przetłumaczona na te same języki. Aby zachować tylko języki, które Twoja aplikacja oficjalnie obsługuje, określ je za pomocą właściwości resConfigs. Wszystkie zasoby w językach, które nie zostały określone, zostaną usunięte.

Poniżej znajdziesz fragmenty pokazujące, jak ograniczyć zasoby językowe tylko do języka angielskiego i francuskiego:

android {
    defaultConfig {
        ...
        resourceConfigurations.addAll(listOf("en", "fr"))
    }
}

lub

android {
    defaultConfig {
        ...
        resConfigs "en", "fr"
    }
}

Gdy publikujesz aplikację w formacie Android App Bundle (AAB), domyślnie podczas instalacji pobierane są tylko języki skonfigurowane na urządzeniu użytkownika. Podobnie w pobieraniu uwzględniane są tylko zasoby pasujące do gęstości ekranu urządzenia i biblioteki natywne pasujące do interfejsu ABI urządzenia. Więcej informacji znajdziesz w artykule Ponowne włączanie i wyłączanie typów plików APK z konfiguracją.

W przypadku starszych aplikacji publikowanych jako pliki APK (utworzonych przed sierpniem 2021 roku) możesz dostosować gęstość ekranu lub zasoby interfejsu ABI, które mają być uwzględnione w pliku APK, tworząc wiele plików APK przeznaczonych na różne konfiguracje urządzeń.

Unikanie konfliktów podczas scalania zasobów

Domyślnie wtyczka Androida do obsługi Gradle (AGP) scala zasoby o identycznych nazwach, np. obiekty rysowalne o tej samej nazwie, które znajdują się w różnych folderach zasobów. To zachowanie nie jest kontrolowane przez właściwość shrinkResources i nie można go wyłączyć, ponieważ jest ono niezbędne, aby uniknąć błędów, gdy wiele zasobów ma nazwę, do której odwołuje się Twój kod.

Scalanie zasobów następuje tylko wtedy, gdy co najmniej 2 pliki mają identyczną nazwę, typ i kwalifikator zasobu. AGP wybiera plik, który uzna za najlepszy spośród duplikatów (na podstawie kolejności priorytetów opisanej poniżej), i przekazuje tylko ten zasób do AAPT w celu dystrybucji w końcowym artefakcie kompilacji.

Wtyczka Androida do obsługi Gradle szuka zduplikowanych zasobów w tych lokalizacjach:

  • Główne zasoby powiązane z głównym zbiorem źródeł, zwykle znajdujące się w folderze src/main/res/
  • Nakładki wariantów, które zależą od rodzaju kompilacji i rodzajów kompilacji.
  • Zależności projektu biblioteki

AGP scala zduplikowane zasoby w tej kolejności priorytetów:

Zależności → Główny → Wersja kompilacji → Rodzaj kompilacji

Jeśli na przykład zduplikowany zasób występuje zarówno w zasobach głównych, jak i w wersji kompilacji, Gradle wybierze zasób w wersji kompilacji.

Jeśli identyczne zasoby pojawią się w tym samym zestawie źródłowym, Gradle nie będzie w stanie ich scalić i wygeneruje błąd scalania zasobów. Może się tak zdarzyć, jeśli w pliku modułu build.gradle zdefiniujesz wiele zestawów źródeł we właściwości sourceSet, np. jeśli zarówno src/main/res/, jak i src/main/res2/ zawierają identyczne zasoby.

Rozwiązywanie problemów ze zmniejszaniem zasobów

Gdy zmniejszysz zasoby, w oknie Kompilacja pojawi się podsumowanie zasobów usuniętych z aplikacji. (Aby wyświetlić szczegółowe dane wyjściowe Gradle w formie tekstowej, kliknij Przełącz widok po lewej stronie okna). Przykład:

:android:shrinkDebugResources
Removed unused resources: Resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning

Gradle tworzy też plik diagnostyczny o nazwie resources.txt w folderze <module-name>/build/outputs/mapping/release/ (tym samym, w którym znajdują się pliki wyjściowe ProGuarda). Plik zawiera szczegóły, takie jak zasoby, które odwołują się do innych zasobów, oraz zasoby, które są używane lub usuwane.

Aby na przykład dowiedzieć się, dlaczego @drawable/ic_plus_anim_016 nadal znajduje się w aplikacji, otwórz plik resources.txt i wyszukaj tę nazwę pliku. Może się okazać, że odwołuje się do niego inny zasób:

16:25:48.005 [QUIET] [system.out] @drawable/add_schedule_fab_icon_anim : reachable=true
16:25:48.009 [QUIET] [system.out] @drawable/ic_plus_anim_016

Musisz teraz wiedzieć, dlaczego @drawable/add_schedule_fab_icon_anim jest osiągalny. Jeśli wyszukasz w górę, znajdziesz ten zasób na liście pod nagłówkiem Główne osiągalne zasoby to: w sekcji resources.txt.

Oznacza to, że w kodzie znajduje się odwołanie do add_schedule_fab_icon_anim, czyli w dostępnym kodzie znaleziono jego R.drawable.

Jeśli nie używasz ścisłego sprawdzania, identyfikatory zasobów mogą być oznaczane jako dostępne, jeśli istnieją stałe ciągi znaków, które wyglądają na takie, które mogą być używane do tworzenia nazw zasobów dla dynamicznie ładowanych zasobów. W takim przypadku, jeśli w wyniku kompilacji wyszukasz nazwę zasobu, możesz znaleźć taki komunikat:

10:32:50.590 [QUIET] [system.out] Marking drawable:ic_plus_anim_016:2130837506
    used because its format-string matches string pool constant ic_plus_anim_%1$d.

Jeśli widzisz jeden z tych ciągów znaków i masz pewność, że nie jest on używany do dynamicznego wczytywania danego zasobu, użyj atrybutu tools:discard w pliku keep, aby poinformować system kompilacji o usunięciu zasobu.