studio - configuration androidtestapi is obsolete and has been replaced with android test implementation
¿Cuál es la diferencia entre implementación y compilación en Gradle? (6)
Esta respuesta demostrará la diferencia entre
implementation
,
api
y
compile
en un proyecto.
Digamos que tengo un proyecto con tres módulos Gradle:
- aplicación (una aplicación de Android)
- myandroidlibrary (una biblioteca de Android)
- myjavalibrary (una biblioteca de Java)
app
tiene
myandroidlibrary
como dependencias.
myandroidlibrary
tiene
myjavalibrary
como dependencias.
myjavalibrary
tiene una clase
MySecret
public class MySecret {
public static String getSecret() {
return "Money";
}
}
myandroidlibrary
tiene la clase
MyAndroidComponent
que manipula el valor de la clase
MySecret
.
public class MyAndroidComponent {
private static String component = MySecret.getSecret();
public static String getComponent() {
return "My component: " + component;
}
}
Por último, la
app
solo está interesada en el valor de
myandroidlibrary
TextView tvHelloWorld = findViewById(R.id.tv_hello_world);
tvHelloWorld.setText(MyAndroidComponent.getComponent());
Ahora, hablemos de las dependencias ...
app
necesita consumir
:myandroidlibrary
, por lo que en la
app
build.gradle usa la
implementation
.
( Nota : también puedes usar api / compile. Pero mantén ese pensamiento por un momento).
dependencies {
implementation project('':myandroidlibrary'')
}
¿
myandroidlibrary
crees que debería verse
myandroidlibrary
build.gradle?
¿Qué alcance debemos usar?
Tenemos tres opciones:
dependencies {
// Option #1
implementation project('':myjavalibrary'')
// Option #2
compile project('':myjavalibrary'')
// Option #3
api project('':myjavalibrary'')
}
¿Cuál es la diferencia entre ellos y qué debo usar?
Compilar o API (opción # 2 o # 3)
Si está utilizando
compile
o
api
.
Nuestra aplicación de Android ahora puede acceder a la dependencia
myandroidcomponent
, que es una clase
MySecret
.
TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can access MySecret
textView.setText(MySecret.getSecret());
Implementación (opción # 1)
Si está utilizando la configuración de
implementation
,
MySecret
no está expuesto.
TextView textView = findViewById(R.id.text_view);
textView.setText(MyAndroidComponent.getComponent());
// You can NOT access MySecret
textView.setText(MySecret.getSecret()); // Won''t even compile
Entonces, ¿qué configuración debe elegir? Eso realmente depende de su requerimiento.
Si
desea exponer dependencias,
use
api
o
compile
.
Si
no desea exponer dependencias
(ocultar su módulo interno), use la
implementation
.
Nota:
Esto es solo una esencia de las configuraciones de Gradle, consulte la Tabla 49.1. Complemento de la Biblioteca Java: configuraciones utilizadas para declarar dependencias para una explicación más detallada.
El proyecto de muestra para esta respuesta está disponible en https://github.com/aldoKelvianto/ImplementationVsCompile
Después de actualizar a Android Studio 3.0 y crear un nuevo proyecto, noté que en
build.gradle
hay una nueva forma de agregar nuevas dependencias en lugar de
compile
hay
implementation
y en lugar de
testCompile
hay
testImplementation
.
Ejemplo:
implementation ''com.android.support:appcompat-v7:25.0.0''
testImplementation ''junit:junit:4.12''
en vez de
compile ''com.android.support:appcompat-v7:25.0.0''
testCompile ''junit:junit:4.12''
¿Cuál es la diferencia entre ellos y qué debo usar?
Compile
configuración de
Compile
ha quedado obsoleta y debe reemplazarse por
implementation
o
api
.
Puede leer los documentos en https://docs.gradle.org/current/userguide/java_library_plugin.html#sec:java_library_separation .
La breve parte es-
La diferencia clave entre el complemento estándar de Java y el complemento de la Biblioteca Java es que este último introduce el concepto de una API expuesta a los consumidores. Una biblioteca es un componente de Java destinado a ser consumido por otros componentes. Es un caso de uso muy común en las compilaciones de proyectos múltiples, pero también tan pronto como tenga dependencias externas.
El complemento expone dos configuraciones que se pueden usar para declarar dependencias: api e implementación. La configuración de la API debe usarse para declarar dependencias que son exportadas por la API de la biblioteca, mientras que la configuración de implementación debe usarse para declarar dependencias que son internas al componente.
Breve solución:
El mejor enfoque es reemplazar todas las dependencias de
compile
con dependencias de
implementation
.
Y solo cuando pierda la interfaz de un módulo, debe usar
api
.
Eso debería causar mucha menos recompilación.
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''
})
}
Explica más:
Antes de Android Gradle plugin 3.0 : tuvimos un gran problema, un cambio de código hace que todos los módulos se vuelvan a compilar. La causa raíz de esto es que Gradle no sabe si se pierde la interfaz de un módulo a través de otro o no.
Después del complemento Android Gradle 3.0 : el último complemento Android Gradle ahora requiere que defina explícitamente si pierde la interfaz de un módulo. En base a eso, puede tomar la decisión correcta sobre lo que debería compilar.
Como tal, la dependencia de
compile
ha quedado en desuso y ha sido reemplazada por dos nuevas:
-
api
: filtra la interfaz de este módulo a través de su propia interfaz, lo que significa exactamente lo mismo que la antigua dependencia decompile
-
implementation
: solo usa este módulo internamente y no lo filtra a través de su interfaz
Entonces ahora puede decirle explícitamente a Gradle que recompile un módulo si la interfaz de un módulo usado cambia o no.
Cortesía del blog de Jeroen Mols.
La breve diferencia en el término de laico es:
- Si está trabajando en una interfaz o módulo que proporciona soporte a otros módulos al exponer a los miembros de la dependencia indicada, debería usar ''api''.
- Si está creando una aplicación o módulo que va a implementar o usar internamente la dependencia indicada, use ''implementación''.
- ''compilar'' funcionó igual que ''api'', sin embargo, si solo está implementando o utilizando cualquier biblioteca, ''implementación'' funcionará mejor y le ahorrará recursos.
lea la respuesta de @aldok para obtener un ejemplo completo.
tl; dr
Solo reemplace:
-
compile
conimplementation
(si no necesita transitividad) oapi
(si necesita transitividad) -
testCompile
contestImplementation
-
debugCompile
withdebugImplementation
-
androidTestCompile
conandroidTestImplementation
-
compileOnly
sigue siendo válido. Fue agregado en 3.0 para reemplazar provisto y no compilar. (provided
cuando Gradle no tenía un nombre de configuración para ese caso de uso y lo nombró por el alcance proporcionado por Maven).
Es uno de los cambios importantes que viene con Gradle 3.0 que Google anunció en IO17 .
La configuración de
compile
ahora
está en
desuso
y debe reemplazarse por
implementation
o
api
De la documentación de Gradle :
dependencies { api ''commons-httpclient:commons-httpclient:3.1'' implementation ''org.apache.commons:commons-lang3:3.5'' }
Las dependencias que aparecen en las configuraciones de la
api
estarán expuestas de forma transitiva a los consumidores de la biblioteca y, como tales, aparecerán en la compilación classpath de los consumidores.Las dependencias encontradas en la configuración de la
implementation
, por otro lado, no estarán expuestas a los consumidores y, por lo tanto, no se filtrarán en la ruta de compilación de los consumidores. Esto viene con varios beneficios:
- las dependencias ya no se filtran en el classpath de compilación de los consumidores, por lo que nunca dependerá accidentalmente de una dependencia transitiva
- compilación más rápida gracias al tamaño reducido de classpath
- menos recompilaciones cuando cambian las dependencias de implementación: los consumidores no necesitarían ser recompilados
- Publicación más limpia: cuando se usa junto con el nuevo complemento de publicación de Maven, las bibliotecas Java producen archivos POM que distinguen exactamente entre lo que se requiere para compilar contra la biblioteca y lo que se requiere para usar la biblioteca en tiempo de ejecución (en otras palabras, no mezclar lo que se necesita para compilar la biblioteca en sí y lo que se necesita para compilar contra la biblioteca).
La configuración de compilación todavía existe, pero no debe usarse, ya que no ofrecerá las garantías que proporcionan la
api
yimplementation
configuraciones deimplementation
.
Nota:
si solo está utilizando una biblioteca en el módulo de su aplicación, el caso común, no notará ninguna diferencia.
solo verá la diferencia si tiene un proyecto complejo con módulos que dependen uno del otro, o si está creando una biblioteca.
+--------------------+----------------------+-------------+--------------+-----------------------------------------+
| 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. |
+--------------------+----------------------+-------------+--------------+-----------------------------------------+