web-dev-qa-db-fra.com

Quelle est la différence entre implémentation et compilation dans Gradle?

Après la mise à jour vers Android Studio 3.0 et la création d'un nouveau projet, j'ai remarqué que, dans build.gradle, il existe un nouveau moyen d'ajouter de nouvelles dépendances au lieu de compile, il y a implementation. et au lieu de testCompile, il y a testImplementation.

Exemple:

 implementation 'com.Android.support:appcompat-v7:25.0.0'
 testImplementation 'junit:junit:4.12'

au lieu de

 compile 'com.Android.support:appcompat-v7:25.0.0'
 testCompile 'junit:junit:4.12'

Quelle est la différence entre eux et que devrais-je utiliser?

826
humazed

tl; dr

Il suffit de remplacer:

  • compile avec implementation (si vous n'avez pas besoin de transitivité) ou api (si vous avez besoin de transitivité)
  • testCompile avec testImplementation
  • debugCompile avec debugImplementation
  • androidTestCompile avec androidTestImplementation
  • compileOnly est toujours valide. Il a été ajouté dans la version 3.0 pour remplacer fourni et non compilé. (provided introduit lorsque Gradle ne possède pas de nom de configuration pour ce cas d'utilisation et le nomme d'après l'étendue fournie par Maven.)

C'est l'un des changements marquants à venir avec Gradle 3.0 que Google annoncé à IO17 .

La configuration de compile est maintenant obsolète et doit être remplacée par implementation ou api

De la documentation Gradle :

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

Les dépendances apparaissant dans les configurations api seront exposées de manière transitoire aux utilisateurs de la bibliothèque et, en tant que telles, apparaîtront sur le chemin de classe de compilation des utilisateurs.

En revanche, les dépendances trouvées dans la configuration implementation ne seront pas exposées aux consommateurs et ne s'infiltreront donc pas dans le chemin de classe de compilation de ces derniers. Cela comporte plusieurs avantages:

  • les dépendances ne fuient plus dans le chemin de classe de compilation des consommateurs, vous ne dépendez donc jamais accidentellement d'une dépendance transitive
  • compilation plus rapide grâce à la réduction de la taille des chemins de classes
  • moins de recompilations lorsque les dépendances de mise en œuvre changent: les consommateurs n'auraient pas besoin d'être recompilés
  • édition plus propre: lorsqu'elles sont utilisées avec le nouveau plugin maven-publish, les bibliothèques Java produisent des fichiers POM qui font la distinction entre ce qui est nécessaire pour compiler avec la bibliothèque et ce qui est requis pour utiliser la bibliothèque à l'exécution En d'autres termes, ne mélangez pas ce qui est nécessaire pour compiler la bibliothèque elle-même et ce qui est nécessaire pour compiler avec la bibliothèque).

La configuration de compilation existe toujours, mais ne doit pas être utilisée car elle n'offrira pas les garanties fournies par les configurations api et implementation.


Remarque: Si vous utilisez uniquement une bibliothèque dans votre module d'application (dans le cas habituel), vous ne remarquerez aucune différence.
vous ne verrez la différence que si vous avez un projet complexe avec des modules qui dépendent les uns des autres ou si vous créez une bibliothèque.

1082
humazed

Cette réponse démontrera la différence entre implementation, api et compile sur un projet.


Disons que j'ai un projet avec trois modules Gradle:

  • app (une application Android)
  • myandroidlibrary (une bibliothèque Android)
  • myjavalibrary (une bibliothèque Java)

app a myandroidlibrary comme dépendances. myandroidlibrary a myjavalibrary comme dépendances.

Dependency1

myjavalibrary a une classe MySecret

public class MySecret {

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

myandroidlibrary a MyAndroidComponent classe qui manipule la valeur de MySecret classe.

public class MyAndroidComponent {

    private static String component = MySecret.getSecret();

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

Enfin, app ne s'intéresse qu'à la valeur de myandroidlibrary

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

Parlons maintenant des dépendances ...

app doit consommer :myandroidlibrary, donc dans app build.gradle, utilisez implementation.

( Note : Vous pouvez aussi utiliser api/compile. Mais gardez cette pensée un instant.)

dependencies {
    implementation project(':myandroidlibrary')      
}

Dependency2

À quoi pensez-vous que myandroidlibrary build.gradle devrait ressembler? Quelle portée devrions-nous utiliser?

Nous avons trois options:

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

Dependency3

Quelle est la différence entre eux et que devrais-je utiliser?

Compiler ou Api (option n ° 2 ou n ° 3) Dependency4

Si vous utilisez compile ou api. Notre application Android peut maintenant accéder à la dépendance myandroidcomponent, qui est une classe MySecret.

TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can access MySecret
textView.setText(MySecret.getSecret());

Mise en oeuvre (option n ° 1)

Dependency5

Si vous utilisez la configuration implementation, MySecret n'est pas exposé.

TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can NOT access MySecret
textView.setText(MySecret.getSecret()); // Won't even compile

Alors, quelle configuration choisir? Cela dépend vraiment de vos besoins.

Si vous souhaitez exposer des dépendances , utilisez api ou compile.

Si vous ne souhaitez pas exposer les dépendances (masquer votre module interne), utilisez implementation.

Remarque:

Ceci est juste un résumé des configurations de Gradle, voir Tableau 49.1. Java plug-in Library - configurations utilisées pour déclarer des dépendances pour une explication plus détaillée.

L'exemple de projet pour cette réponse est disponible sur https://github.com/aldoKelvianto/ImplementationVsCompile

280
aldok

La configuration de Compile est obsolète et doit être remplacée par implementation ou api.

Vous pouvez lire la documentation sur https://docs.gradle.org/current/userguide/Java_library_plugin.html#sec:Java_library_separation .

La brève partie étant-

La principale différence entre le plug-in standard Java et le plug-in Java Library est que ce dernier introduit le concept d'une API exposée aux consommateurs. Une bibliothèque est un composant Java destiné à être utilisé par d'autres composants. C'est un cas d'utilisation très courant dans les versions multi-projets, mais aussi dès que vous avez des dépendances externes.

Le plugin expose deux configurations pouvant être utilisées pour déclarer des dépendances: api et implémentation. La configuration de l'api doit être utilisée pour déclarer les dépendances exportées par l'API de la bibliothèque, tandis que la configuration de l'implémentation doit être utilisée pour déclarer les dépendances internes au composant.

Pour plus d'explications, reportez-vous à cette image. Brief explanation

59
Rishav

Brève solution:

La meilleure approche consiste à remplacer toutes les dépendances compile par des dépendances implementation. Et uniquement lorsque l'interface d'un module présente une fuite, vous devez utiliser api. Cela devrait causer beaucoup moins de recompilation.

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

Expliquez plus:

Avant Android Gradle plugin 3.0 : nous avons eu un gros problème, à savoir qu'un changement de code entraîne la recompilation de tous les modules. La cause fondamentale de ceci est que Gradle ne sait pas si vous divulguez l’interface d’un module par un autre ou non.

Après Android Gradle plug-in 3.0 : le dernier plug-in Android Gradle nécessite désormais que vous définissiez explicitement votre fuite. une interface de module. Basé sur cela, il peut faire le bon choix sur ce qu'il devrait recompiler.

En tant que telle, la dépendance compile est devenue obsolète et remplacée par deux nouvelles:

  • api: l'interface de ce module fuit via sa propre interface, ce qui signifie exactement la même chose que l'ancienne dépendance compile

  • implementation: vous utilisez ce module uniquement en interne et ne le perdez pas via votre interface

Vous pouvez donc maintenant explicitement demander à Gradle de recompiler un module si l’interface d’un module utilisé change ou non.

Gracieuseté de Jeroen Mols blog

43
Shayan Amani

La brève différence dans le terme profane est:

  • Si vous travaillez sur une interface ou un module prenant en charge d'autres modules en exposant les membres de la dépendance indiquée, vous devez utiliser 'api'.
  • Si vous créez une application ou un module qui va implémenter ou utiliser la dépendance indiquée en interne, utilisez 'implémentation'.
  • 'compiler' a fonctionné de la même manière que 'api', cependant, si vous ne faites que mettre en œuvre ou utilisez une bibliothèque, 'implémentation' fonctionnera mieux et vous permettra d'économiser des ressources.

lisez la réponse de @aldok pour un exemple complet.

6
Rushabh Agarwal
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| 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.  |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
5
Wajid Ali