2017-06-12 63 views
346

Po aktualizacji do Androida Studio 3.0 i tworzenia nowego projektu, zauważyłem, że w build.gradle istnieje nowy sposób na dodanie nowych zależności, zamiast compile jest implementation i zamiast testCompile istnieje testImplementation.Jaka jest różnica pomiędzy realizacją i skompilować w Gradle

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 i co powinienem używać?

Odpowiedz

496

Jest jednym z rozbijających zmian pochodzących z Gradle: 3.0 że Google announced at IO17 Gradle: 3,0

konfiguracja compile jest now deprecated i powinien zostać zastąpiony przez implementation lub api

Z gradle docs:

dependencies { 
    api 'commons-httpclient:commons-httpclient:3.1' 
    implementation 'org.apache.commons:commons-lang3:3.5' 
} 

Zależności pojawiające się w api konfiguracje będą przechodnie wystawione na działanie konsumentów biblioteki i jako takie będą pojawiać się na ścieżce kompilacji użytkowników. znalezione w konfiguracji implementation

zależne będą w drugiej strony, nie może być narażony na konsumentów, a zatem nie przedostają się kompilacji ścieżki klasy konsumentów. To jest kilka korzyści:

  • Zależności nie przedostają się do ścieżki klasy kompilacji konsumentów anymore, więc nigdy nie będzie przypadkowo zależą przechodniej zależnościami
  • szybciej kompilacji dzięki zmniejszonej wielkości ścieżce klasy
  • mniej rekompilując gdy zmieniają się zależności implementacji: konsumenci nie musieliby być rekompilowani
  • czystsze publikowanie: w połączeniu z nową wtyczką do publikowania maven, biblioteki Java generują pliki POM, które rozróżniają dokładnie to, co jest wymagane stos przeciwko bibliotece i co jest wymagane do korzystania z biblioteki w czasie wykonywania (w innych słowach , nie mieszaj tego, co jest potrzebne do kompilowania samej biblioteki i co jest potrzebne do kompilacji biblioteki).

Konfiguracja kompilacji nadal istnieje, ale nie powinna być używana, ponieważ nie oferuje gwarancji, które zapewnia konfiguracja api i implementacji.


tl; dr

Wystarczy wymienić:

  • compile z implementation
  • testCompile z testImplementation
  • debugCompile z debugImplementation
  • androidTestCompile z androidTestImplementation
+50

Kim są "konsumenci"? – Suragch

+11

konsument jest modułem korzystającym z biblioteki. w przypadku Androida jest to aplikacja na Androida. Myślę, że jest to jasne i nie jestem pewien, czy o to prosisz. – humazed

+9

Tak też brzmiał dla mnie. Ale jeśli tworzę bibliotekę, oczywiście chcę, aby jej interfejs API był narażony na działanie aplikacji. W przeciwnym razie, w jaki sposób programista aplikacji użyłby mojej biblioteki? Dlatego nie rozumiem znaczenia "implementacji" ukrywania zależności. Czy moje pytanie ma sens? – Suragch

33

Compile konfigurację przestarzała i powinna być zastąpiona przez implementation lub api.

Możesz przeczytać dokumentację pod numerem https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation.

Krótka część being-

Kluczowa różnica między standardową wtyczkę Java i wtyczki biblioteki Java jest to, że ten ostatni wprowadza pojęcie API narażonych konsumentów. Biblioteka to komponent Java, który ma być używany przez inne komponenty. Jest to bardzo powszechny przypadek użycia w kompilacjach wieloprojektowych , ale zaraz po uzyskaniu zewnętrznych zależności .

Wtyczka udostępnia dwie konfiguracje, za pomocą których można zadeklarować zależności: api i implementację. Konfiguracja api powinna być używana do deklarowania zależności wyeksportowanych przez bibliotekę API, , podczas gdy konfiguracja implementacji powinna być używana do deklarowania zależności, które są wewnętrzne dla komponentu.

Aby uzyskać więcej informacji, zapoznaj się z tym obrazem. Brief explanation

18

Brief Rozwiązanie:

Lepszym rozwiązaniem jest zastąpienie wszystkich compile zależności z implementation zależności. I tylko tam, gdzie wyciekasz interfejs modułu, powinieneś użyć api. To powinno spowodować o wiele mniej rekompilacji.

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śnić Więcej:

Przed Android Gradle wtyczki 3,0: mieliśmy duży problem, który jest jedna zmiana kodu powoduje wszystkie moduły do ​​rekompilacji. Główną przyczyną tego jest to, że Gradle nie wie, czy przenosisz interfejs modułu przez inny, czy też nie.

Po wtyczce Android Gradle 3.0: najnowsza wtyczka do systemu Android Gradle wymaga teraz jawnego zdefiniowania, czy wyciekuje się interfejs modułu. Na tej podstawie może dokonać właściwego wyboru, co należy przekompilować.

Jako taka zależność compile została wycofana i zastąpiona przez dwa nowe:

  • api: ty wyciek interfejs tego modułu za pośrednictwem własnego interfejsu, czyli dokładnie tak samo jak w starym compile uzależnienia

  • implementation: używać tylko ten moduł wewnętrznie i nie wycieka go za pośrednictwem interfejsu

Teraz możesz wyraźnie powiedzieć Gradle, aby przekompilować moduł, jeśli interfejs używanego modułu zmieni się lub nie.

Dzięki uprzejmości Jeroen Mols blogu

26

Ta odpowiedź będzie wykazać różnicę między implementation, api i compile nad projektem. Powiedzmy, że mam projekt z trzech modułów Gradle:

  • app (aplikacja Android)
  • myandroidlibrary (Android library)
  • myjavalibrary (biblioteka Java)

app ma myandroidlibrary jako zależności. myandroidlibrary ma myjavalibrary jako zależności.

app -> myandroidlibrary -> myjavalibrary

myjavalibrary ma MySecret klasa

public class MySecret { 

    public static String getSecret() { 
     return "Money"; 
    } 
} 

myandroidlibrary ma MyAndroidComponent klasę, która manipulowania wartości od MySecret klasie.

public class MyAndroidComponent { 

    private static String component = MySecret.getSecret(); 

    public static String getComponent() { 
     return "My component: " + component; 
    }  
} 

Wreszcie app jest zainteresowany tylko na wartości od myandroidlibrary

TextView tvHelloWorld = findViewById(R.id.tv_hello_world); 
tvHelloWorld.setText(MyAndroidComponent.getComponent()); 

Teraz pomówmy o zależnościach na app build.gradle. Jest bardzo prosty i intuicyjny.

dependencies { 
    implementation project(':myandroidlibrary')  
} 

Co sądzisz myandroidlibrary build.gradle powinien wyglądać jak? Mamy trzy możliwości:

dependencies { 
    // Option #1 
    implementation project(':myjavalibrary') 
    // Option #2 
    compile project(':myjavalibrary')  
    // Option #3 
    api project(':myjavalibrary')   
} 

Jaka jest różnica między nimi i co powinienem używać?

skompilować i Api

Jeśli używasz compile i api. Nasza aplikacja na Androida może teraz uzyskać 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

Jeśli używasz implementation konfiguracji 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ę należy 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 (ukrywając swój moduł wewnętrzny), użyj implementation.

To jest tylko istota konfiguracji Gradle, Table 49.1. Java Library plugin - configurations used to declare dependencies ma bardziej szczegółowe wyjaśnienie na ten temat.

Happy Exploring