Jaka jest różnica między implementacją a kompilacją w Gradle?
Po aktualizacji do Android Studio 3.0 i utworzeniu nowego projektu zauważyłem, że w build.gradle
istnieje nowy sposób dodawania nowych zależności zamiast compile
jest implementation
, a zamiast testCompile
jest testImplementation
.
Przykład:
implementation 'com.android.support:appcompat-v7:25.0.0'
testImplementation 'junit:junit:4.12'
Zamiast
compile 'com.android.support:appcompat-v7:25.0.0'
testCompile 'junit:junit:4.12'
Jaka jest różnica między nimi a czym powinienem używać?
9 answers
Tl; dr
Just replace:
-
compile
zimplementation
(jeśli nie potrzebujesz przechodniości) lubapi
(jeśli potrzebujesz przechodniości) -
testCompile
ztestImplementation
-
debugCompile
zdebugImplementation
-
androidTestCompile
zandroidTestImplementation
-
compileOnly
jest nadal ważna. Został dodany w 3.0, aby zastąpić dostarczone, a nie skompilować. (provided
wprowadzono, gdy Gradle nie miał nazwy konfiguracyjnej dla tego przypadku użycia i nazwał ją po podanym przez Mavena zakresie.)
Jest to jeden z przełomowych zmian nadchodzących z Android Gradle plugin 3.0 że Google ogłosił na IO17.
Konfiguracja compile
jest teraz przestarzała i powinna zostać zastąpiona przez implementation
lub api
From the Gradle documentation :
dependencies { api 'commons-httpclient:commons-httpclient:3.1' implementation 'org.apache.commons:commons-lang3:3.5' }
Zależności pojawiające się w konfiguracjach
api
będą przejściowo narażone na działanie konsumentów biblioteki, a jako takie będzie pojawiają się na kompilacyjnej ścieżce klasowej konsumentów.Zależności Znalezione w Konfiguracji
implementation
będą, na drugiej strony, nie być narażone na konsumentów, a zatem nie przeciekać do compile classpath użytkownika. Wiąże się to z kilkoma korzyściami:
- zależności nie przeciekają już do ścieżki kompilacji konsumentów, więc nigdy nie będziesz przypadkowo zależny od przechodniego dependency
- szybsza kompilacja dzięki zmniejszonemu rozmiarowi classpath
- mniej rekompilacji podczas implementacji zmiany zależności: konsumenci nie muszą być rekompilowane
- cleaner publishing: w połączeniu z nową wtyczką Maven-publish biblioteki Javy wytwarzają pliki Pom, które rozróżnić dokładnie to, co jest wymagane do kompilacji z biblioteki i co jest wymagane do korzystania z biblioteki w czasie wykonywania (w innych słowa, nie mieszaj co jest potrzebne do kompilacji samej biblioteki i co jest potrzebna do kompilacji z biblioteką).
Konfiguracja kompilacji nadal istnieje, ale nie powinien być używany, ponieważ nie zapewni gwarancji, które zapewniają konfiguracje
api
iimplementation
.
Uwaga: Jeśli korzystasz tylko z biblioteki w module aplikacji-częsty przypadek - nie zauważysz żadnej różnicy.
różnica będzie widoczna tylko wtedy, gdy masz złożony projekt z modułami zależnymi od siebie lub tworzysz bibliotekę.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-07 14:46:00
Ta odpowiedź zademonstruje różnicę między implementation
, api
, i compile
nad projektem.
Załóżmy, że mam projekt z trzema modułami Gradle:
-
[[41]} app (Aplikacja na Androida)
- myandroidlibrary (Biblioteka Androida)
- myjavalibrary (Biblioteka Javy)
app
mA myandroidlibrary
jako zależności. myandroidlibrary
ma myjavalibrary
jako zależności.
myjavalibrary
mA MySecret
Klasa
public class MySecret {
public static String getSecret() {
return "Money";
}
}
myandroidlibrary
posiada klasę MyAndroidComponent
, która manipuluje wartością z klasy MySecret
.
public class MyAndroidComponent {
private static String component = MySecret.getSecret();
public static String getComponent() {
return "My component: " + component;
}
}
Wreszcie, app
jest zainteresowany tylko wartością z myandroidlibrary
TextView tvHelloWorld = findViewById(R.id.tv_hello_world);
tvHelloWorld.setText(MyAndroidComponent.getComponent());
Porozmawiajmy teraz o zależnościach...
app
trzeba konsumować :myandroidlibrary
, więc w app
budować.gradle use implementation
.
(Uwaga: Możesz również użyć api / kompilacji. Ale potrzymaj tę myśl przez chwilę.)
dependencies {
implementation project(':myandroidlibrary')
}
Co myślisz myandroidlibrary
buduj.gradle powinien wyglądać? Którego zakresu powinniśmy użyć?
Mamy Trzy opcje:
dependencies {
// Option #1
implementation project(':myjavalibrary')
// Option #2
compile project(':myjavalibrary')
// Option #3
api project(':myjavalibrary')
}
Jaka jest różnica między nimi a czym powinienem używać?
Compile lub Api (opcja # 2 lub #3)
Jeśli używasz compile
lub api
. Nasza aplikacja na Androida ma teraz dostęp do zależności myandroidcomponent
, która jest klasą MySecret
.
TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can access MySecret
textView.setText(MySecret.getSecret());
Realizacja (wariant #1)
Jeśli używasz konfiguracji implementation
, MySecret
nie jest narażona.
TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can NOT access MySecret
textView.setText(MySecret.getSecret()); // Won't even compile
Jaką konfigurację wybrać? To naprawdę zależy od twoich wymagań.
Jeśli chcesz ujawnić zależności użyj api
lub compile
.
Jeśli nie chcesz ujawniać zależności (ukrywanie wewnętrznego modułu), użyj implementation
.
Uwaga:
To jest tylko gist Gradle konfiguracje, patrz tabela 49.1. Java Library plugin-konfiguracje używane do deklarowania zależności w celu bardziej szczegółowego wyjaśnienia.
Przykładowy projekt dla tej odpowiedzi jest dostępny na https://github.com/aldoKelvianto/ImplementationVsCompile
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-19 12:36:31
Compile
konfiguracja została wycofana i powinna zostać zastąpiona przez implementation
lub api
.
Możesz przeczytać dokumenty na https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation.
Krótka część jest -
Kluczowa różnica między standardową wtyczką Java a Javą Plugin biblioteki jest to, że ten ostatni wprowadza pojęcie API narażone na działanie konsumentów. Biblioteka jest komponentem Javy przeznaczonym do spożywane przez inne komponenty. Jest to bardzo częsty przypadek użycia w buduje wiele projektów, ale także tak szybko, jak masz zewnętrzne zależności.
Wtyczka wyświetla dwie konfiguracje, które można wykorzystać do zadeklarowania zależności: api i implementacja. Konfiguracja api powinna być używany do deklarowania zależności, które są eksportowane przez API biblioteki, natomiast konfiguracja implementacji powinna być używana do deklarowania zależności wewnętrzne komponentu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-12 07:37:04
Krótkie Rozwiązanie:
Lepszym rozwiązaniem jest zastąpienie wszystkich compile
zależności implementation
zależnościami. I tylko tam, gdzie wycieknie interfejs modułu, należy użyć api
. To powinno spowodować o wiele mniejszą rekompilację.
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:25.4.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
// …
testImplementation 'junit:junit:4.12'
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
}
Wyjaśnij Więcej:
Przed Android Gradle plugin 3.0: mieliśmy duży problem, który polega na tym, że jedna zmiana kodu powoduje rekompilację wszystkich modułów. Główną przyczyną tego jest to, że Gradle nie wie, czy przeciekasz interfejs modułu przez inny lub nie.
Po Android Gradle plugin 3.0: najnowsza Wtyczka Android Gradle wymaga teraz jawnego zdefiniowania, czy wyciekasz interfejs modułu. Na tej podstawie może dokonać właściwego wyboru, co ma przekompilować.
Jako taka zależność compile
została wycofana i zastąpiona dwoma nowymi:
-
api
: Interfejs tego modułu przeciekasz przez własny interfejs, co oznacza dokładnie to samo co staracompile
zależność -
implementation
: używasz tego modułu tylko wewnętrznie i nie przeciekasz go przez interfejs
Więc teraz możesz jawnie powiedzieć Gradle, aby przekompilował moduł, jeśli interfejs używanego modułu się zmieni, czy nie.
Dzięki Uprzejmości Jeroen Mols blog
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| Name | Role | Consumable? | Resolveable? | Description |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| api | Declaring | no | no | This is where you should declare |
| | API | | | dependencies which are transitively |
| | dependencies | | | exported to consumers, for compile. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| implementation | Declaring | no | no | This is where you should |
| | implementation | | | declare dependencies which are |
| | dependencies | | | purely internal and not |
| | | | | meant to be exposed to consumers. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| compileOnly | Declaring compile | yes | yes | This is where you should |
| | only | | | declare dependencies |
| | dependencies | | | which are only required |
| | | | | at compile time, but should |
| | | | | not leak into the runtime. |
| | | | | This typically includes dependencies |
| | | | | which are shaded when found at runtime. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| runtimeOnly | Declaring | no | no | This is where you should |
| | runtime | | | declare dependencies which |
| | dependencies | | | are only required at runtime, |
| | | | | and not at compile time. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testImplementation | Test dependencies | no | no | This is where you |
| | | | | should declare dependencies |
| | | | | which are used to compile tests. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testCompileOnly | Declaring test | yes | yes | This is where you should |
| | compile only | | | declare dependencies |
| | dependencies | | | which are only required |
| | | | | at test compile time, |
| | | | | but should not leak into the runtime. |
| | | | | This typically includes dependencies |
| | | | | which are shaded when found at runtime. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| testRuntimeOnly | Declaring test | no | no | This is where you should |
| | runtime dependencies | | | declare dependencies which |
| | | | | are only required at test |
| | | | | runtime, and not at test compile time. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-04-09 12:55:06
Gradle 3.0
wprowadzono kolejne zmiany:
-
compile
->api
api
Słowo kluczowe jest takie samo jak deprecatedcompile
które ujawniają tę zależność dla wszystkich poziomów -
compile
->implementation
Jest preferowany sposób, ponieważ ma pewne zalety.
implementation
ujawnia zależność tylko dla o jeden poziom w górę w czasie budowania (zależność jest dostępna w czasie wykonywania). W rezultacie masz szybszą kompilację (nie ma potrzeby przekompilowywania konsumentów, które są wyżej niż 1 poziom wyżej) -
provided
->compileOnly
Ta zależność jest dostępna tylko w czasie kompilacji (zależność nie jest dostępna w czasie wykonywania). Zależność ta nie może być przechodnia i być
.aar
. Może być używany z procesorem adnotacji czasu kompilacji i pozwala zmniejszyć końcowy plik wyjściowy -
compile
->annotationProcessor
Bardzo podobne do
compileOnly
, ale również gwarantuje, że zależność przechodnia nie jest widoczna dla konsument -
apk
->runtimeOnly
Zależność nie jest dostępna w czasie kompilacji, ale dostępna w czasie wykonywania.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-16 18:51:09
Krótka różnica w pojęciu laika to:
- jeśli pracujesz nad interfejsem lub modułem, który zapewnia wsparcie dla innych modułów poprzez ujawnienie członków określonej zależności, powinieneś używać 'api'.
- Jeśli tworzysz aplikację lub moduł, który ma zaimplementować lub użyć podanej zależności wewnętrznie, użyj 'implementation'.
- 'compile' działa tak samo jak 'api', jednak jeśli tylko implementujesz lub używasz dowolnej biblioteki, 'implementacja' będzie działać lepiej i zaoszczędzić zasoby.
Przeczytaj odpowiedź @aldok na wyczerpujący przykład.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-23 03:12:35
Od wersji 5.6.3 Gradle documentation zawiera proste reguły pozwalające określić, czy stara compile
zależność (lub Nowa) powinna być zastąpiona implementation
lub api
zależność:
- preferuj konfigurację
implementation
zamiastapi
jeśli to możliweTo utrzymuje zależności poza ścieżką kompilacji konsumenta. Ponadto konsumenci natychmiast nie kompilują, jeśli jakiekolwiek typy implementacji przypadkowo wyciekną do publiczne API.
Kiedy więc należy użyć konfiguracji
api
? Zależność API to taka, która zawiera co najmniej jeden typ, który jest eksponowany w binarnym interfejsie biblioteki, często określanym jako ABI (Application Binary Interface). Dotyczy to między innymi:
- typy używane w super klasach lub interfejsach
- typy używane w publicznych parametrach metod, w tym ogólne typy parametrów (gdzie public to coś, co jest widoczne dla kompilatorów. Tj. publiczne, protected and package private members in the Java world)
- typy używane w polach publicznych
- typy adnotacji publicznych
Dla kontrastu, każdy typ, który jest używany w poniższej liście, jest nieistotny dla ABI i dlatego powinien być zadeklarowany jako zależność
implementation
:
- typy stosowane wyłącznie w organach metod
- typy używane wyłącznie w prywatnych członkach
- typy występujące wyłącznie w klasach wewnętrznych (przyszłe wersje Gradle pozwolą deklarujesz, które pakiety należą do publicznego API)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55
-
Implementacja: najczęściej używamy konfiguracji implementacji. Ukrywa wewnętrzną zależność modułu od jego konsumenta, aby uniknąć przypadkowego użycia jakiejkolwiek zależności przejściowej, a tym samym szybszej kompilacji i mniejszej rekompilacji.
-
Api: musi być używane bardzo ostrożnie, ponieważ przecieka do ścieżki kompilacji konsumenta, stąd niewłaściwe użycie api może prowadzić do zanieczyszczenia zależnościami.
-
CompileOnly: when we don ' t need any zależność w czasie wykonywania, ponieważ zależność compileOnly nie stanie się częścią ostatecznej kompilacji. otrzymamy mniejszy rozmiar budowy.
-
RuntimeOnly: gdy chcemy zmienić lub zamienić zachowanie biblioteki w czasie wykonywania (w końcowej kompilacji).
Stworzyłem post z dogłębnym zrozumieniem każdego z nich z działającym przykładem: źródło kod
Https://medium.com/@gauraw.negi/how-gradle-dependency-configurations-work-underhood-e934906752e5
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-13 06:37:40