Android
Gradle para Android
Buscar..
Introducción
Gradle es un sistema de compilación basado en JVM que permite a los desarrolladores escribir scripts de alto nivel que pueden utilizarse para automatizar el proceso de compilación y producción de aplicaciones. Es un sistema flexible basado en complementos, que le permite automatizar varios aspectos del proceso de construcción; incluyendo compilar y firmar un .jar
, descargar y administrar dependencias externas, inyectar campos en el AndroidManifest
o utilizar versiones específicas del SDK.
Sintaxis
apply plugin
: los complementos que deberían usarse normalmente solo'com.android.application'
o'com.android.library'
.android
: la configuración principal de tu aplicación.-
compileSdkVersion
: la versión SDK de compilación -
buildToolsVersion
: la versión de herramientas de construcción -
defaultConfig
: la configuración predeterminada que puede ser sobrescrita por tipos y tipos de compilación-
applicationId
: el ID de la aplicación que usas, por ejemplo, en PlayStore, es casi igual al nombre de tu paquete -
minSdkVersion
: la versión mínima de SDK requerida -
targetSdkVersion
: la versión de SDK con la que compila (debe ser siempre la primera) -
versionCode
: el número de versión interna que debe ser mayor en cada actualización -
versionName
: el número de versión que el usuario puede ver en la página de detalles de la aplicación
-
-
buildTypes
: ver en otro lugar (TODO)
-
dependencies
: las dependencias locales o locales de su aplicación-
compile
una sola dependencia -
testCompile
: una dependencia para la unidad o pruebas de integración
-
Observaciones
Ver también
- La página oficial de Gradle.
- Cómo configurar compilaciones de gradle
- El plugin de android para gradle
- Android Gradle DSL
Gradle para Android - Documentación extendida:
Hay otra etiqueta donde puedes encontrar más temas y ejemplos sobre el uso de gradle en Android.
http://www.riptutorial.com/topic/2092
Un archivo build.gradle básico
Este es un ejemplo de un archivo build.gradle
predeterminado en un módulo.
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion '25.0.3'
signingConfigs {
applicationName {
keyAlias 'applicationName'
keyPassword 'password'
storeFile file('../key/applicationName.jks')
storePassword 'keystorePassword'
}
}
defaultConfig {
applicationId 'com.company.applicationName'
minSdkVersion 14
targetSdkVersion 25
versionCode 1
versionName '1.0'
signingConfig signingConfigs.applicationName
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:design:25.3.1'
testCompile 'junit:junit:4.12'
}
DSL (lenguaje específico de dominio)
Cada bloque en el archivo anterior se llama un DSL
(lenguaje específico del dominio).
Complementos
La primera línea, apply plugin: 'com.android.application'
, aplica el complemento de Android para Gradle a la compilación y hace que el bloque android {}
esté disponible para declarar las opciones de compilación específicas de Android.
Para una aplicación de Android :
apply plugin: 'com.android.application'
Para una biblioteca de Android :
apply plugin: 'com.android.library'
Entendiendo los DSLs en el ejemplo anterior
La segunda parte, el bloque de android {...}
, es el DSL
Android que contiene información sobre su proyecto.
Por ejemplo, puede configurar el compileSdkVersion
que especifica el nivel de la API de Android, que Gradle debe usar para compilar su aplicación.
El subbloque defaultConfig
contiene los valores predeterminados para su manifiesto. Puede override
con Sabores del producto .
Puedes encontrar más información en estos ejemplos:
- DSL para el módulo de la aplicación
- Tipos de construcción
- Sabores del producto
- Configuracion de firma
Dependencias
El bloque de dependencies
se define fuera del bloque de android
{...}
: Esto significa que no está definido por el complemento de Android, pero es Gradle estándar.
El bloque de dependencies
especifica qué bibliotecas externas (normalmente las bibliotecas de Android, pero las bibliotecas de Java también son válidas) que desea incluir en su aplicación. Gradle descargará automáticamente estas dependencias por usted (si no hay una copia local disponible), solo necesita agregar líneas de compile
similares cuando desee agregar otra biblioteca.
Veamos una de las líneas aquí presentes:
compile 'com.android.support:design:25.3.1'
Esta línea básicamente dice
agregar una dependencia de la biblioteca de diseño de soporte de Android a mi proyecto.
Gradle se asegurará de que la biblioteca esté descargada y presente para que pueda usarla en su aplicación, y su código también se incluirá en su aplicación.
Si está familiarizado con Maven, esta sintaxis es GroupId , dos puntos, ArtifactId , otros dos puntos, luego la versión de la dependencia que desea incluir, lo que le da un control total sobre las versiones.
Si bien es posible especificar versiones de artefactos usando el signo más (+), la mejor práctica es evitar hacerlo; puede llevar a problemas si la biblioteca se actualiza con cambios de última hora sin su conocimiento, lo que probablemente provocaría bloqueos en su aplicación.
Puedes agregar diferentes tipos de dependencias:
Se debe dedicar una atención particular a las dependencias planas .
Puede encontrar más detalles en este tema.
Nota sobre el -v7 en appcompat-v7
compile 'com.android.support:appcompat-v7:25.3.1'
Esto simplemente significa que esta biblioteca ( appcompat
) es compatible con la API de Android de nivel 7 y appcompat
.
Nota sobre el junit: junit: 4.12
Esta es la dependencia de prueba para la prueba de unidad.
Especificando dependencias específicas para diferentes configuraciones de compilación
Puede especificar que una dependencia solo se use para una determinada configuración de compilación o puede definir diferentes dependencias para los tipos de compilación o las versiones del producto (por ejemplo, depuración, prueba o lanzamiento) utilizando debugCompile
, testCompile
o releaseCompile
lugar de la compile
habitual .
Esto es útil para mantener las dependencias relacionadas con la prueba y la depuración fuera de su versión de lanzamiento, lo que mantendrá su APK
versión lo más delgado posible y ayudará a garantizar que no se pueda usar ninguna información de depuración para obtener información interna sobre su aplicación.
firmaConfig
La signingConfig
permite configurar su Gradle para incluir información del keystore
y garantizar que el APK creado con estas configuraciones esté firmado y listo para la versión de Play Store.
Aquí puedes encontrar un tema dedicado .
Nota : no se recomienda mantener las credenciales de firma dentro de su archivo de Gradle. Para eliminar las configuraciones de firma, basta con omitir la signingConfigs
parte.
Puedes especificarlos de diferentes maneras:
- almacenar en un archivo externo
- Almacenándolos en la configuración de variables de entorno .
Consulte este tema para obtener más detalles: Firmar APK sin exponer la contraseña del almacén de claves .
Puede encontrar más información sobre Gradle para Android en el tema dedicado de Gradle .
Definición de sabores de producto.
Los sabores del producto se definen en el archivo build.gradle
dentro del bloque de android { ... }
como se ve a continuación.
...
android {
...
productFlavors {
free {
applicationId "com.example.app.free"
versionName "1.0-free"
}
paid {
applicationId "com.example.app.paid"
versionName "1.0-paid"
}
}
}
Al hacer esto, ahora tenemos dos sabores de productos adicionales: free
y de paid
. Cada uno puede tener su propia configuración y atributos específicos. Por ejemplo, nuestros dos nuevos sabores tienen un applicationId
y versionName
separados de nuestro main
sabor existente (disponible por defecto, por lo que no se muestra aquí).
Adición de dependencias específicas del sabor del producto.
Se pueden agregar dependencias para un sabor de producto específico, similar a cómo se pueden agregar para configuraciones de compilación específicas.
Para este ejemplo, suponga que ya hemos definido dos sabores de productos llamados free
y de paid
(más información sobre cómo definir sabores aquí ).
Luego podemos agregar la dependencia de AdMob para el sabor free
, y la biblioteca de Picasso para el paid
como:
android {
...
productFlavors {
free {
applicationId "com.example.app.free"
versionName "1.0-free"
}
paid {
applicationId "com.example.app.paid"
versionName "1.0-paid"
}
}
}
...
dependencies {
...
// Add AdMob only for free flavor
freeCompile 'com.android.support:appcompat-v7:23.1.1'
freeCompile 'com.google.android.gms:play-services-ads:8.4.0'
freeCompile 'com.android.support:support-v4:23.1.1'
// Add picasso only for paid flavor
paidCompile 'com.squareup.picasso:picasso:2.5.2'
}
...
Añadiendo recursos específicos del sabor del producto.
Se pueden agregar recursos para un sabor de producto específico.
Para este ejemplo, suponga que ya hemos definido dos tipos de productos llamados free
y de paid
. Para agregar recursos específicos del sabor del producto, creamos carpetas de recursos adicionales junto con la carpeta main/res
, a la que luego podemos agregar recursos como de costumbre. Para este ejemplo, definiremos una cadena, status
, para cada sabor de producto:
/ src / main /res/values/strings.xml
<resources>
<string name="status">Default</string>
</resources>
/ src / free /res/values/strings.xml
<resources>
<string name="status">Free</string>
</resources>
/ src / paid /res/values/strings.xml
<resources>
<string name="status">Paid</string>
</resources>
Las cadenas de status
específicas del sabor del producto anularán el valor del status
en el sabor main
.
Definir y usar los campos de configuración de construcción
BuildConfigField
Gradle permite que buildConfigField
líneas buildConfigField
definan constantes. Estas constantes serán accesibles en tiempo de ejecución como campos estáticos de la clase BuildConfig
. Esto se puede usar para crear sabores definiendo todos los campos dentro del bloque defaultConfig
, y luego reemplazándolos para crear sabores individuales según sea necesario.
Este ejemplo define la fecha de compilación y marca la compilación para la producción en lugar de la prueba:
android {
...
defaultConfig {
...
// defining the build date
buildConfigField "long", "BUILD_DATE", System.currentTimeMillis() + "L"
// define whether this build is a production build
buildConfigField "boolean", "IS_PRODUCTION", "false"
// note that to define a string you need to escape it
buildConfigField "String", "API_KEY", "\"my_api_key\""
}
productFlavors {
prod {
// override the productive flag for the flavor "prod"
buildConfigField "boolean", "IS_PRODUCTION", "true"
resValue 'string', 'app_name', 'My App Name'
}
dev {
// inherit default fields
resValue 'string', 'app_name', 'My App Name - Dev'
}
}
}
El <package_name> generado automáticamente. BuildConfig
.java en la carpeta gen contiene los siguientes campos basados en la directiva anterior:
public class BuildConfig {
// ... other generated fields ...
public static final long BUILD_DATE = 1469504547000L;
public static final boolean IS_PRODUCTION = false;
public static final String API_KEY = "my_api_key";
}
Los campos definidos ahora se pueden usar dentro de la aplicación en tiempo de ejecución accediendo a la clase BuildConfig
generada:
public void example() {
// format the build date
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
String buildDate = dateFormat.format(new Date(BuildConfig.BUILD_DATE));
Log.d("build date", buildDate);
// do something depending whether this is a productive build
if (BuildConfig.IS_PRODUCTION) {
connectToProductionApiEndpoint();
} else {
connectToStagingApiEndpoint();
}
}
Valorar
El resValue
en los productFlavors
crea un valor de recursos. Puede ser cualquier tipo de recurso ( string
, dimen
, color
, etc.). Esto es similar a definir un recurso en el archivo apropiado: por ejemplo, definir una cadena en un archivo strings.xml
. La ventaja es que el definido en gradle se puede modificar en función de su productFlavor / buildVariant. Para acceder al valor, escriba el mismo código como si estuviera accediendo a una resolución desde el archivo de recursos:
getResources().getString(R.string.app_name)
Lo importante es que los recursos definidos de esta manera no pueden modificar los recursos existentes definidos en los archivos. Solo pueden crear nuevos valores de recursos.
Algunas bibliotecas (como la API de Android de Google Maps) requieren una clave API proporcionada en el manifiesto como una etiqueta de meta-data
. Si se necesitan claves diferentes para la depuración y las compilaciones de producción, especifique un marcador de posición manifiesto completado por Gradle.
En su archivo AndroidManifest.xml
:
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}"/>
Y luego establezca el campo correspondiente en su archivo build.gradle
:
android {
defaultConfig {
...
// Your development key
manifestPlaceholders = [ MAPS_API_KEY: "AIza..." ]
}
productFlavors {
prod {
// Your production key
manifestPlaceholders = [ MAPS_API_KEY: "AIza..." ]
}
}
}
El sistema de compilación de Android genera una serie de campos automáticamente y los coloca en BuildConfig.java
. Estos campos son:
Campo | Descripción |
---|---|
DEBUG | un Boolean indica si la aplicación está en modo de depuración o lanzamiento |
APPLICATION_ID | una String contiene el ID de la aplicación (por ejemplo, com.example.app ) |
BUILD_TYPE | una String contiene el tipo de compilación de la aplicación (generalmente debug o release ) |
FLAVOR | una String contiene el sabor particular de la construcción |
VERSION_CODE | un int contiene el número de versión (compilación). Esto es lo mismo que versionCode en build.gradle o versionCode en AndroidManifest.xml |
VERSION_NAME | una String contiene el nombre de la versión (compilación). Este es el mismo como versionName en build.gradle o versionName en AndroidManifest.xml |
Además de lo anterior, si ha definido múltiples dimensiones de sabor, entonces cada dimensión tendrá su propio valor. Por ejemplo, si tiene dos dimensiones de sabor para el color
y el size
, también tendrá las siguientes variables:
Campo | Descripción |
---|---|
FLAVOR_color | una String contiene el valor para el sabor 'color'. |
FLAVOR_size | una String contiene el valor para el sabor 'tamaño'. |
Centralizando dependencias a través del archivo "dependencies.gradle"
Cuando se trabaja con proyectos de múltiples módulos, es útil centralizar las dependencias en una sola ubicación en lugar de tenerlos distribuidos en muchos archivos de compilación, especialmente para bibliotecas comunes como las bibliotecas de soporte de Android y las bibliotecas Firebase .
Una forma recomendada es separar los archivos de compilación de Gradle, con un build.gradle
por módulo, así como uno en la raíz del proyecto y otro para las dependencias, por ejemplo:
root
+- gradleScript/
| dependencies.gradle
+- module1/
| build.gradle
+- module2/
| build.gradle
+- build.gradle
Entonces, todas sus dependencias se pueden ubicar en gradleScript/dependencies.gradle
:
ext {
// Version
supportVersion = '24.1.0'
// Support Libraries dependencies
supportDependencies = [
design: "com.android.support:design:${supportVersion}",
recyclerView: "com.android.support:recyclerview-v7:${supportVersion}",
cardView: "com.android.support:cardview-v7:${supportVersion}",
appCompat: "com.android.support:appcompat-v7:${supportVersion}",
supportAnnotation: "com.android.support:support-annotations:${supportVersion}",
]
firebaseVersion = '9.2.0';
firebaseDependencies = [
core: "com.google.firebase:firebase-core:${firebaseVersion}",
database: "com.google.firebase:firebase-database:${firebaseVersion}",
storage: "com.google.firebase:firebase-storage:${firebaseVersion}",
crash: "com.google.firebase:firebase-crash:${firebaseVersion}",
auth: "com.google.firebase:firebase-auth:${firebaseVersion}",
messaging: "com.google.firebase:firebase-messaging:${firebaseVersion}",
remoteConfig: "com.google.firebase:firebase-config:${firebaseVersion}",
invites: "com.google.firebase:firebase-invites:${firebaseVersion}",
adMod: "com.google.firebase:firebase-ads:${firebaseVersion}",
appIndexing: "com.google.android.gms:play-services-appindexing:${firebaseVersion}",
];
}
Que luego se puede aplicar desde ese archivo en el archivo de nivel superior build.gradle
así:
// Load dependencies
apply from: 'gradleScript/dependencies.gradle'
y en el module1/build.gradle
como tal:
// Module build file
dependencies {
// ...
compile supportDependencies.appCompat
compile supportDependencies.design
compile firebaseDependencies.crash
}
Otro enfoque
Se puede lograr un enfoque menos detallado para centralizar las versiones de las dependencias de la biblioteca declarando el número de versión como una variable una vez, y usándolo en todas partes.
En el espacio de trabajo root build.gradle
agregue esto:
ext.v = [
supportVersion:'24.1.1',
]
Y en cada módulo que use la misma biblioteca agregue las bibliotecas necesarias
compile "com.android.support:support-v4:${v.supportVersion}"
compile "com.android.support:recyclerview-v7:${v.supportVersion}"
compile "com.android.support:design:${v.supportVersion}"
compile "com.android.support:support-annotations:${v.supportVersion}"
Estructura de directorio para recursos específicos de sabor
Diferentes tipos de compilaciones de aplicaciones pueden contener diferentes recursos. Para crear un recurso de sabor específico, cree un directorio con el nombre en minúsculas de su sabor en el directorio src
y agregue sus recursos de la misma manera que lo haría normalmente.
Por ejemplo, si tuviera un Development
sabor y quisiera proporcionar un ícono de src/development/res/drawable-mdpi
distinto, crearía un directorio src/development/res/drawable-mdpi
y dentro de ese directorio crearía un archivo ic_launcher.png
con su ícono específico de desarrollo.
La estructura del directorio se verá así:
src/
main/
res/
drawable-mdpi/
ic_launcher.png <-- the default launcher icon
development/
res/
drawable-mdpi/
ic_launcher.png <-- the launcher icon used when the product flavor is 'Development'
(Por supuesto, en este caso, también crearías íconos para drawable-hdpi, drawable-xhdpi, etc. ).
¿Por qué hay dos archivos build.gradle en un proyecto de Android Studio?
<PROJECT_ROOT>\app\build.gradle
es específico para el módulo de la aplicación .
<PROJECT_ROOT>\build.gradle
es un "archivo de compilación de nivel superior" donde puede agregar opciones de configuración comunes a todos los subproyectos / módulos.
Si usa otro módulo en su proyecto, como biblioteca local tendrá otro archivo build.gradle
: <PROJECT_ROOT>\module\build.gradle
En el archivo de nivel superior puede especificar propiedades comunes como el bloque de buildscript o algunas propiedades comunes.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
classpath 'com.google.gms:google-services:3.0.0'
}
}
ext {
compileSdkVersion = 23
buildToolsVersion = "23.0.1"
}
En la app\build.gradle
usted define solo las propiedades para el módulo:
apply plugin: 'com.android.application'
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
}
dependencies {
//.....
}
Ejecutando un script de shell desde gradle
Un script de shell es una forma muy versátil de ampliar su compilación a básicamente cualquier cosa que se pueda imaginar.
Como ejemplo, aquí hay un script simple para compilar archivos protobuf y agregar los archivos java de resultados al directorio de origen para una compilación adicional:
def compilePb() {
exec {
// NOTICE: gradle will fail if there's an error in the protoc file...
executable "../pbScript.sh"
}
}
project.afterEvaluate {
compilePb()
}
El script de shell 'pbScript.sh' para este ejemplo, ubicado en la carpeta raíz del proyecto:
#!/usr/bin/env bash
pp=/home/myself/my/proto
/usr/local/bin/protoc -I=$pp \
--java_out=./src/main/java \
--proto_path=$pp \
$pp/my.proto \
--proto_path=$pp \
$pp/my_other.proto
Depurando tus errores de Gradle
El siguiente es un extracto de Gradle: ¿Qué es un valor de salida distinto de cero y cómo puedo solucionarlo? , verlo para la discusión completa.
Digamos que está desarrollando una aplicación y obtiene un error de Gradle que parece que, en general, se verá así.
:module:someTask FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':module:someTask'.
> some message here... finished with non-zero exit value X
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: Y.ZZ secs
Busca tu problema aquí en StackOverflow, y la gente dice que debes limpiar y reconstruir tu proyecto, o habilitar MultiDex , y cuando lo intentas, simplemente no está solucionando el problema.
Hay formas de obtener más información , pero la salida de Gradle en sí misma debería apuntar al error real en las pocas líneas sobre ese mensaje entre: module:someTask FAILED
y el último :module:someOtherTask
que pasó. Por lo tanto, si hace una pregunta sobre su error, edite sus preguntas para incluir más contexto al error.
Entonces, obtienes un "valor de salida distinto de cero". Bueno, ese número es un buen indicador de lo que debes tratar de arreglar. Aquí hay algunos que ocurren con más frecuencia.
-
1
es solo un código de error general y el error es probable en la salida de Gradle -
2
parece estar relacionado con la superposición de dependencias o la configuración errónea del proyecto. -
3
parece ser por incluir demasiadas dependencias, o un problema de memoria.
Las soluciones generales para lo anterior (después de intentar limpiar y reconstruir el proyecto) son:
-
1
- Abordar el error que se menciona. En general, este es un error en tiempo de compilación, lo que significa que parte del código de su proyecto no es válido. Esto incluye tanto XML como Java para un proyecto de Android. -
2
y3
: muchas respuestas aquí le dicen que habilite multidex . Si bien puede solucionar el problema, es muy probable que sea una solución. Si no entiende por qué lo está utilizando (vea el enlace), probablemente no lo necesite. Las soluciones generales implican reducir su uso excesivo de las dependencias de la biblioteca (como todos los Servicios de Google Play, cuando solo necesita usar una biblioteca, como Mapas o Iniciar sesión, por ejemplo).
Especificar diferentes ID de aplicación para tipos de compilación y sabores de producto
Puede especificar diferentes ID de aplicación o nombres de paquetes para cada buildType
o productFlavor
utilizando el atributo de configuración applicationIdSuffix:
Ejemplo de sufijo del applicationId
para cada buildType
:
defaultConfig {
applicationId "com.package.android"
minSdkVersion 17
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
debuggable false
}
development {
debuggable true
applicationIdSuffix ".dev"
}
testing {
debuggable true
applicationIdSuffix ".qa"
}
}
Nuestra applicationIds
resultante sería ahora:
- com.package.android para el
release
- com.package.android. dev para
development
- com.package.android. qa para la
testing
Esto también se puede hacer para productFlavors
:
productFlavors {
free {
applicationIdSuffix ".free"
}
paid {
applicationIdSuffix ".paid"
}
}
Las applicationIds
resultantes serían:
- com.package.android. Gratis para el sabor
free
- com.package.android. pagado por el sabor
paid
Firmar APK sin exponer la contraseña del keystore
Puede definir la configuración de firma para firmar el apk en el archivo build.gradle
usando estas propiedades:
-
storeFile
: el archivo de almacén de claves -
storePassword
: la contraseña del almacén de claves -
keyAlias
: un nombre de alias de clave -
keyPassword
: una contraseña de alias de clave
En muchos casos, es posible que deba evitar este tipo de información en el archivo build.gradle
.
Método A: configure la firma de liberación utilizando un archivo keystore.properties
Es posible configurar build.gradle
su aplicación para que lea la información de configuración de firma de un archivo de propiedades como keystore.properties
.
Configurar la firma de esta manera es beneficioso porque:
- Su información de configuración de firma es independiente de su archivo
build.gradle
- No tiene que intervenir durante el proceso de firma para proporcionar contraseñas para su archivo de almacén de claves
- Puede excluir fácilmente el archivo
keystore.properties
del control de versiones
Primero, cree un archivo llamado keystore.properties
en la raíz de su proyecto con contenido como este (reemplazando los valores con los suyos):
storeFile=keystore.jks
storePassword=storePassword
keyAlias=keyAlias
keyPassword=keyPassword
Ahora, en el archivo build.gradle
su aplicación, configure el bloque de signingConfigs
configuración de la siguiente manera:
android {
...
signingConfigs {
release {
def propsFile = rootProject.file('keystore.properties')
if (propsFile.exists()) {
def props = new Properties()
props.load(new FileInputStream(propsFile))
storeFile = file(props['storeFile'])
storePassword = props['storePassword']
keyAlias = props['keyAlias']
keyPassword = props['keyPassword']
}
}
}
}
Eso es todo lo que hay en ello, pero no olvide excluir tanto su archivo de almacén de claves como su archivo de keystore.properties
del control de versiones .
Un par de cosas a anotar:
- La ruta de
storeFile
especificada en el archivokeystore.properties
debe ser relativa al archivobuild.gradle
su aplicación. Este ejemplo asume que el archivo de almacén de claves está en el mismo directorio que el archivobuild.gradle
la aplicación. - Este ejemplo tiene el archivo
keystore.properties
en la raíz del proyecto. Si lo coloca en otro lugar, asegúrese de cambiar el valor enrootProject.file('keystore.properties')
a su ubicación, en relación con la raíz de su proyecto.
Método B: utilizando una variable de entorno
Lo mismo se puede lograr también sin un archivo de propiedades, lo que hace que la contraseña sea más difícil de encontrar:
android {
signingConfigs {
release {
storeFile file('/your/keystore/location/key')
keyAlias 'your_alias'
String ps = System.getenv("ps")
if (ps == null) {
throw new GradleException('missing ps env variable')
}
keyPassword ps
storePassword ps
}
}
La variable de entorno "ps"
puede ser global, pero un enfoque más seguro puede ser agregándolo a la shell de Android Studio solamente.
En Linux, esto se puede hacer editando la Desktop Entry
Android Studio
Exec=sh -c "export ps=myPassword123 ; /path/to/studio.sh"
Puede encontrar más detalles en este tema .
Versiones de sus compilaciones a través del archivo "version.properties"
Puedes usar Gradle para incrementar automáticamente la versión de tu paquete cada vez que lo construyas. Para ello, cree un archivo version.properties
en el mismo directorio que su build.gradle
con el siguiente contenido:
VERSION_MAJOR=0
VERSION_MINOR=1
VERSION_BUILD=1
(Cambiando los valores para mayor y menor como mejor le parezca). Luego, en tu build.gradle
agrega el siguiente código a la sección de android
:
// Read version information from local file and increment as appropriate
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
def versionMajor = versionProps['VERSION_MAJOR'].toInteger()
def versionMinor = versionProps['VERSION_MINOR'].toInteger()
def versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1
// Update the build number in the local file
versionProps['VERSION_BUILD'] = versionBuild.toString()
versionProps.store(versionPropsFile.newWriter(), null)
defaultConfig {
versionCode versionBuild
versionName "${versionMajor}.${versionMinor}." + String.format("%05d", versionBuild)
}
}
Se puede acceder a la información en Java como una cadena BuildConfig.VERSION_NAME
para completar {major}. { BuildConfig.VERSION_NAME
}. { BuildConfig.VERSION_CODE
} y como un entero BuildConfig.VERSION_CODE
solo para el número de compilación.
Cambiar el nombre del apk de salida y agregar el nombre de la versión:
Este es el código para cambiar el nombre del archivo de la aplicación de salida (.apk). El nombre se puede configurar asignando un valor diferente a newName
android {
applicationVariants.all { variant ->
def newName = "ApkName";
variant.outputs.each { output ->
def apk = output.outputFile;
newName += "-v" + defaultConfig.versionName;
if (variant.buildType.name == "release") {
newName += "-release.apk";
} else {
newName += ".apk";
}
if (!output.zipAlign) {
newName = newName.replace(".apk", "-unaligned.apk");
}
output.outputFile = new File(apk.parentFile, newName);
logger.info("INFO: Set outputFile to "
+ output.outputFile
+ " for [" + output.name + "]");
}
}
}
Deshabilite la compresión de imágenes para un tamaño de archivo APK más pequeño
Si está optimizando todas las imágenes manualmente, desactive APT Cruncher para un tamaño de archivo APK más pequeño.
android {
aaptOptions {
cruncherEnabled = false
}
}
Habilitar Proguard usando gradle
Para habilitar las configuraciones de Proguard para su aplicación, necesita habilitarla en su archivo de nivel de módulo. minifyEnabled
establecer el valor de minifyEnabled
en true
.
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
El código anterior aplicará sus configuraciones de Proguard contenidas en el SDK de Android predeterminado combinado con el archivo "proguard-rules.pro" en su módulo a su apk liberado.
Habilitar el soporte experimental del complemento NDK para Gradle y AndroidStudio
Habilite y configure el complemento experimental de Gradle para mejorar el soporte NDK de AndroidStudio. Comprueba que cumples los siguientes requisitos:
- Gradle 2.10 (para este ejemplo)
- Android NDK r10 o posterior
- Android SDK con herramientas de compilación v19.0.0 o posterior
Configurar el archivo MyApp / build.gradle
Edite la línea dependencies.classpath en build.gradle desde, por ejemplo,
classpath 'com.android.tools.build:gradle:2.1.2'
a
classpath 'com.android.tools.build:gradle-experimental:0.7.2'
(v0.7.2 era la última versión en el momento de la redacción. Verifique la última versión usted mismo y adapte su línea en consecuencia)
El archivo build.gradle debería verse similar a esto:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle-experimental:0.7.2'
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Configurar el archivo MyApp / app / build.gradle
Edite el archivo build.gradle para que se vea similar al siguiente ejemplo. Sus números de versión pueden parecer diferentes.
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion 19
buildToolsVersion "24.0.1"
defaultConfig {
applicationId "com.example.mydomain.myapp"
minSdkVersion.apiLevel 19
targetSdkVersion.apiLevel 19
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles.add(file('proguard-android.txt'))
}
}
ndk {
moduleName "myLib"
/* The following lines are examples of a some optional flags that
you may set to configure your build environment
*/
cppFlags.add("-I${file("path/to/my/includes/dir")}".toString())
cppFlags.add("-std=c++11")
ldLibs.addAll(['log', 'm'])
stl = "c++_static"
abiFilters.add("armeabi-v7a")
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
Sincronice y verifique que no haya errores en los archivos de Gradle antes de continuar.
Probar si el plugin está habilitado
Primero asegúrese de haber descargado el módulo NDK de Android. Luego cree una nueva aplicación en AndroidStudio y agregue lo siguiente al archivo ActivityMain:
public class MainActivity implements Activity {
onCreate() {
// Pregenerated code. Not important here
}
static {
System.loadLibrary("myLib");
}
public static native String getString();
}
La parte getString()
debe resaltarse en rojo diciendo que no se pudo encontrar la función JNI correspondiente. Mueva el mouse sobre la función de llamada hasta que aparezca una bombilla roja. Haga clic en la bombilla y seleccione create function JNI_...
Esto debería generar un archivo myLib.c en el directorio myApp / app / src / main / jni con la llamada a la función JNI correcta. Debería verse similar a esto:
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_example_mydomain_myapp_MainActivity_getString(JNIEnv *env, jobject instance)
{
// TODO
return (*env)->NewStringUTF(env, returnValue);
}
Si no se ve así, entonces el complemento no se ha configurado correctamente o el NDK no se ha descargado
Mostrar todas las tareas del proyecto Gradle
gradlew tasks -- show all tasks
Android tasks
-------------
androidDependencies - Displays the Android dependencies of the project.
signingReport - Displays the signing info for each variant.
sourceSets - Prints out all the source sets defined in this project.
Build tasks
-----------
assemble - Assembles all variants of all applications and secondary packages.
assembleAndroidTest - Assembles all the Test applications.
assembleDebug - Assembles all Debug builds.
assembleRelease - Assembles all Release builds.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
classes - Assembles main classes.
clean - Deletes the build directory.
compileDebugAndroidTestSources
compileDebugSources
compileDebugUnitTestSources
compileReleaseSources
compileReleaseUnitTestSources
extractDebugAnnotations - Extracts Android annotations for the debug variant into the archive file
extractReleaseAnnotations - Extracts Android annotations for the release variant into the archive file
jar - Assembles a jar archive containing the main classes.
mockableAndroidJar - Creates a version of android.jar that's suitable for unit tests.
testClasses - Assembles test classes.
Build Setup tasks
-----------------
init - Initializes a new Gradle build. [incubating]
wrapper - Generates Gradle wrapper files. [incubating]
Documentation tasks
-------------------
javadoc - Generates Javadoc API documentation for the main source code.
Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'LeitnerBoxPro'.
components - Displays the components produced by root project 'LeitnerBoxPro'. [incubating]
dependencies - Displays all dependencies declared in root project 'LeitnerBoxPro'.
dependencyInsight - Displays the insight into a specific dependency in root project 'LeitnerBoxPro'.
help - Displays a help message.
model - Displays the configuration model of root project 'LeitnerBoxPro'. [incubating]
projects - Displays the sub-projects of root project 'LeitnerBoxPro'.
properties - Displays the properties of root project 'LeitnerBoxPro'.
tasks - Displays the tasks runnable from root project 'LeitnerBoxPro' (some of the displayed tasks may belong to subprojects)
.
Install tasks
-------------
installDebug - Installs the Debug build.
installDebugAndroidTest - Installs the android (on device) tests for the Debug build.
uninstallAll - Uninstall all applications.
uninstallDebug - Uninstalls the Debug build.
uninstallDebugAndroidTest - Uninstalls the android (on device) tests for the Debug build.
uninstallRelease - Uninstalls the Release build.
Verification tasks
------------------
check - Runs all checks.
connectedAndroidTest - Installs and runs instrumentation tests for all flavors on connected devices.
connectedCheck - Runs all device checks on currently connected devices.
connectedDebugAndroidTest - Installs and runs the tests for debug on connected devices.
deviceAndroidTest - Installs and runs instrumentation tests using all Device Providers.
deviceCheck - Runs all device checks using Device Providers and Test Servers.
lint - Runs lint on all variants.
lintDebug - Runs lint on the Debug build.
lintRelease - Runs lint on the Release build.
test - Run unit tests for all variants.
testDebugUnitTest - Run unit tests for the debug build.
testReleaseUnitTest - Run unit tests for the release build.
Other tasks
-----------
assembleDefault
clean
jarDebugClasses
jarReleaseClasses
transformResourcesWithMergeJavaResForDebugUnitTest
transformResourcesWithMergeJavaResForReleaseUnitTest
Eliminar "no alineado" apk automáticamente
Si no necesita archivos apk generados automáticamente con sufijo unaligned
(que probablemente no necesite), puede agregar el siguiente código al archivo build.gradle
:
// delete unaligned files
android.applicationVariants.all { variant ->
variant.assemble.doLast {
variant.outputs.each { output ->
println "aligned " + output.outputFile
println "unaligned " + output.packageApplication.outputFile
File unaligned = output.packageApplication.outputFile;
File aligned = output.outputFile
if (!unaligned.getName().equalsIgnoreCase(aligned.getName())) {
println "deleting " + unaligned.getName()
unaligned.delete()
}
}
}
}
Desde aqui
Ignorando la variante de construcción
Por algunas razones, es posible que desee ignorar las variantes de compilación. Por ejemplo: tiene un sabor de producto 'simulado' y lo usa solo para fines de depuración, como pruebas de unidad / instrumentación.
Ignoremos la variante mockRelease de nuestro proyecto. Abra el archivo build.gradle y escriba:
// Remove mockRelease as it's not needed.
android.variantFilter { variant ->
if (variant.buildType.name.equals('release') && variant.getFlavors().get(0).name.equals('mock')) {
variant.setIgnore(true);
}
}
Viendo arbol de dependencias
Usa las dependencias de la tarea. Dependiendo de cómo estén configurados los módulos, puede ser ./gradlew dependencies
o ver las dependencias del uso de la aplicación del módulo ./gradlew :app:dependencies
El siguiente ejemplo del archivo build.gradle
dependencies {
compile 'com.android.support:design:23.2.1'
compile 'com.android.support:cardview-v7:23.1.1'
compile 'com.google.android.gms:play-services:6.5.87'
}
Producirá el siguiente gráfico:
Parallel execution is an incubating feature.
:app:dependencies
------------------------------------------------------------
Project :app
------------------------------------------------------------
. . .
_releaseApk - ## Internal use, do not manually configure ##
+--- com.android.support:design:23.2.1
| +--- com.android.support:support-v4:23.2.1
| | \--- com.android.support:support-annotations:23.2.1
| +--- com.android.support:appcompat-v7:23.2.1
| | +--- com.android.support:support-v4:23.2.1 (*)
| | +--- com.android.support:animated-vector-drawable:23.2.1
| | | \--- com.android.support:support-vector-drawable:23.2.1
| | | \--- com.android.support:support-v4:23.2.1 (*)
| | \--- com.android.support:support-vector-drawable:23.2.1 (*)
| \--- com.android.support:recyclerview-v7:23.2.1
| +--- com.android.support:support-v4:23.2.1 (*)
| \--- com.android.support:support-annotations:23.2.1
+--- com.android.support:cardview-v7:23.1.1
\--- com.google.android.gms:play-services:6.5.87
\--- com.android.support:support-v4:21.0.0 -> 23.2.1 (*)
. . .
Aquí puede ver que el proyecto incluye directamente com.android.support:design
versión 23.2.1, que a su vez trae com.android.support:support-v4
con la versión 23.2.1. Sin embargo, com.google.android.gms:play-services
sí mismo depende del mismo support-v4
pero con una versión anterior 21.0.0, que es un conflicto detectado por gradle.
(*)
se utilizan cuando gradle se salta el subárbol porque esas dependencias ya estaban listadas anteriormente.
Use gradle.properties para central versionnumber / buildconfigurations
Puede definir la información de configuración central en
- un archivo de inclusión de Gradle separado. Centralización de dependencias a través del archivo "dependencies.gradle"
- un archivo de propiedades autónomas que versiona sus compilaciones a través del archivo "version.properties"
o hazlo con el archivo raíz gradle.properties
la estructura del proyecto
root
+- module1/
| build.gradle
+- module2/
| build.gradle
+- build.gradle
+- gradle.properties
configuración global para todos los submódulos en gradle.properties
# used for manifest
# todo increment for every release
appVersionCode=19
appVersionName=0.5.2.160726
# android tools settings
appCompileSdkVersion=23
appBuildToolsVersion=23.0.2
uso en un submódulo
apply plugin: 'com.android.application'
android {
// appXXX are defined in gradle.properties
compileSdkVersion = Integer.valueOf(appCompileSdkVersion)
buildToolsVersion = appBuildToolsVersion
defaultConfig {
// appXXX are defined in gradle.properties
versionCode = Long.valueOf(appVersionCode)
versionName = appVersionName
}
}
dependencies {
...
}
Nota: Si desea publicar su aplicación en la tienda de aplicaciones F-Droid, tiene que usar números mágicos en el archivo de gradle porque, de lo contrario, el robot f-droid no puede leer la versión actual para detectar / verificar los cambios de versión.
Mostrar información de firma
En algunas circunstancias (por ejemplo, la obtención de una clave API de Google) debe encontrar la huella digital del almacén de claves. Gradle tiene una tarea conveniente que muestra toda la información de firma, incluidas las huellas digitales del almacén de claves:
./gradlew signingReport
Esta es una salida de muestra:
:app:signingReport
Variant: release
Config: none
----------
Variant: debug
Config: debug
Store: /Users/user/.android/debug.keystore
Alias: AndroidDebugKey
MD5: 25:08:76:A9:7C:0C:19:35:99:02:7B:00:AA:1E:49:CA
SHA1: 26:BE:89:58:00:8C:5A:7D:A3:A9:D3:60:4A:30:53:7A:3D:4E:05:55
Valid until: Saturday 18 June 2044
----------
Variant: debugAndroidTest
Config: debug
Store: /Users/user/.android/debug.keystore
Alias: AndroidDebugKey
MD5: 25:08:76:A9:7C:0C:19:35:99:02:7B:00:AA:1E:49:CA
SHA1: 26:BE:89:58:00:8C:5A:7D:A3:A9:D3:60:4A:30:53:7A:3D:4E:05:55
Valid until: Saturday 18 June 2044
----------
Variant: debugUnitTest
Config: debug
Store: /Users/user/.android/debug.keystore
Alias: AndroidDebugKey
MD5: 25:08:76:A9:7C:0C:19:35:99:02:7B:00:AA:1E:49:CA
SHA1: 26:BE:89:58:00:8C:5A:7D:A3:A9:D3:60:4A:30:53:7A:3D:4E:05:55
Valid until: Saturday 18 June 2044
----------
Variant: releaseUnitTest
Config: none
----------
Definiendo tipos de compilación
Puede crear y configurar tipos de compilación en el archivo build.gradle
nivel de build.gradle
dentro del bloque android {}
.
android { ... defaultConfig {...} buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { applicationIdSuffix ".debug" } } }