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ć?

Author: SOFe, 2017-06-12

9 answers

Tl; dr

Just replace:

  • compile z implementation (jeśli nie potrzebujesz przechodniości) lub api (jeśli potrzebujesz przechodniości)
  • testCompile z testImplementation
  • debugCompile z debugImplementation
  • androidTestCompile z androidTestImplementation
  • 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 i implementation.


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ę.

 1382
Author: humazed,
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.

Dependency1

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')      
}

Dependency2

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')           
}

Dependency3

Jaka jest różnica między nimi a czym powinienem używać?

Compile lub Api (opcja # 2 lub #3) Dependency4

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)

Dependency5

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

 422
Author: aldok,
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.

Do dalszych Wyjaśnienie odnosi się do tego obrazu. Krótkie wyjaśnienie

 73
Author: Rishav,
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 stara compile 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

 47
Author: Shayan Amani,
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.  |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
 29
Author: Wajid,
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 deprecated compile 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.

[Typ zależności POM]

 16
Author: yoAlex5,
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.

 10
Author: Rushabh Agarwal,
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 zamiast api jeśli to możliwe

To 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)
 7
Author: Pom12,
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

Konfiguracje Gradle

 1
Author: Gauraw Negi,
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