Optymalizacja dla autorów bibliotek

Jako autor biblioteki musisz zadbać o to, aby deweloperzy aplikacji mogli łatwo włączyć ją do swoich aplikacji, zachowując przy tym wysoką jakość wrażeń użytkowników. Upewnij się, że Twoja biblioteka jest zgodna z optymalizacją na Androida bez dodatkowej konfiguracji lub zgłoś, że może nie nadawać się do użycia na Androidzie.

Ta dokumentacja jest przeznaczona dla deweloperów opublikowanych bibliotek, ale może być też przydatna deweloperom modułów wewnętrznych bibliotek w dużej, skompilowanej aplikacji.

Jeśli jesteś deweloperem i chcesz dowiedzieć się więcej o optymalizacji aplikacji na Androida, przeczytaj artykuł Włączanie optymalizacji aplikacji. Aby dowiedzieć się, których bibliotek używać, przeczytaj artykuł Wybór odpowiednich bibliotek.

Używanie codegen zamiast reflection

Jeśli to możliwe, zamiast refleksji używaj generowania kodu (codegen). Zarówno generowanie kodu, jak i odwołania są popularnymi sposobami na unikanie szablonowego kodu podczas programowania, ale generowanie kodu jest bardziej zgodne z optymalizatorami aplikacji, takimi jak R8:

  • W przypadku codegen kod jest analizowany i modyfikowany podczas procesu kompilacji. Ponieważ po kompilacji nie ma żadnych istotnych modyfikacji, optymalizator wie, jaki kod jest potrzebny i co można bezpiecznie usunąć.
  • W przypadku odbicia kod jest analizowany i modyfikowany w czasie wykonywania. Ponieważ kod nie jest w pełni gotowy, dopóki się nie wykona, optymalizator nie wie, jaki kod można bezpiecznie usunąć. Prawdopodobnie usunie kod używany dynamicznie za pomocą odbicia lustrzanego podczas działania, co powoduje awarie aplikacji u użytkowników.

Wiele nowoczesnych bibliotek zamiast refleksji używa generowania kodu. Zapoznaj się z KSP, czyli wspólnym punktem wejścia używanym przez Room, Dagger2 i wiele innych usług.

Kiedy odbicie jest dopuszczalne

Jeśli musisz użyć odbicia, możesz to zrobić tylko w jednym z tych miejsc:

  • konkretne typy docelowe (konkretni implementatorzy interfejsu lub podklasy);
  • Kod korzystający z określonej adnotacji środowiska wykonawczego

Wykorzystanie odbicia w taki sposób ogranicza koszt działania i umożliwia tworzenie reguł dotyczących zachowania danych użytkownika.

Ta konkretna i wybiórcza forma odbicia jest wzorcem, który można zaobserwować zarówno w ramach platformy Android (np. podczas napełniania aktywności, widoków i elementów rysowalnych), jak i bibliotek AndroidX (np. podczas tworzenia obiektów WorkManager ListenableWorker lub RoomDatabases). Natomiast otwarta implementacja Gson nie jest odpowiednia do stosowania w aplikacjach na Androida.

Napisać reguły dotyczące zachowania konsumentów

Biblioteki powinny pakować reguły przechowywania „konsumenta”, które używają tego samego formatu co reguły przechowywania aplikacji. Te reguły są umieszczane w elementach biblioteki (AAR lub JAR) i automatycznie wykorzystywane podczas optymalizacji aplikacji na Androida, gdy biblioteka jest używana.

Biblioteki AAR

Aby dodać reguły dla konsumentów biblioteki AAR, użyj opcji consumerProguardFiles w skrypcie kompilacji modułu biblioteki na Androida. Więcej informacji znajdziesz w artykule o tworzeniu modułów biblioteki.

Kotlin

android {
    defaultConfig {
        consumerProguardFiles("consumer-proguard-rules.pro")
    }
    ...
}

Groovy

android {
    defaultConfig {
        consumerProguardFiles 'consumer-proguard-rules.pro'
    }
    ...
}

Biblioteki JAR

Aby zgrupować reguły z biblioteką Kotlin/Java dostarczaną jako plik JAR, umieść plik reguł w katalogu META-INF/proguard/ końcowego pliku JAR, pod dowolną nazwą. Jeśli na przykład Twój kod znajduje się w pliku <libraryroot>/src/main/kotlin, umieść plik reguł dla klienta w pliku <libraryroot>/src/main/resources/META-INF/proguard/consumer-proguard-rules.pro. Reguły zostaną zapakowane we właściwym miejscu w pliku JAR.

Sprawdź, czy końcowy plik JAR zawiera prawidłowe reguły, sprawdzając, czy znajdują się one w katalogu META-INF/proguard.

obsługa różnych narzędzi do kompresji (zaawansowane);

Możesz dostosować reguły do konkretnych kompresorów (R8 lub ProGuard), a także do konkretnych wersji kompresorów. Dzięki temu Twoja biblioteka będzie działać optymalnie w projektach korzystających z nowych wersji shrinkera, a obecne reguły będą mogły być nadal używane w projektach z starszymi wersjami shrinkera.

Aby określić reguły kompresji docelowej, musisz je uwzględnić w określonych miejscach w bibliotece AAR lub JAR, jak opisano poniżej.

In an AAR library:
    consumer-proguard-rules.pro (legacy location)
    classes.jar
    └── META-INF
        └── com.android.tools (targeted shrink rules location)
            ├── r8-from-<X>-upto-<Y>/<R8-rules-file>
            └── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>

In a JAR library:
    META-INF
    ├── proguard/<ProGuard-rules-file> (legacy location)
    └── com.android.tools (targeted shrink rules location)
        ├── r8-from-<X>-upto-<Y>/<R8-rules-file>
        └── proguard-from-<X>-upto-<Y>/<ProGuard-rules-file>

Oznacza to, że reguły ukierunkowanego kompresowania są przechowywane w katalogu META-INF/com.android.tools pliku JAR lub w katalogu META-INF/com.android.tools w pliku classes.jar pliku AAR.

W tym katalogu może być wiele katalogów o nazwach w formacie r8-from-<X>-upto-<Y> lub proguard-from-<X>-upto-<Y>, które wskazują, dla których wersji shrinkera zostały napisane reguły w katalogach. Pamiętaj, że części -from-<X> i -upto-<Y> są opcjonalne, wersja <Y> jest wyłączna, a zakresy wersji muszą być ciągłe.

Na przykład r8-upto-8.0.0, r8-from-8.0.0-upto-8.2.0r8-from-8.2.0 tworzą prawidłowy zbiór reguł skurczu docelowego. Reguły w katalogu r8-from-8.0.0-upto-8.2.0 będą używane przez R8 od wersji 8.0.0 do z wyjątkiem wersji 8.2.0.

Na podstawie tych informacji wtyczka Android Gradle wybiera reguły z odpowiednich katalogów R8. Jeśli biblioteka nie określa reguł kompresji, wtyczka Gradle dla Androida wybierze reguły z starszych lokalizacji (proguard.txt w przypadku pliku AAR lub META-INF/proguard/<ProGuard-rules-file> w przypadku pliku JAR).