tutorial - Usar Gradle para dividir bibliotecas externas en archivos dex separados para resolver el límite de Android Dalvik 64k métodos
proguard android studio tutorial (4)
¿Existe una forma proper/easy
de resolver el límite de métodos de 64k con Gradle?
Me refiero a alguna tarea personalizada de Gradle para usar archivos jar predefinidos para crear archivos dex separados, en lugar de una sola classes.dex
.
Gracias
Ivan
Estado actual
Actualmente, estoy luchando con GMS: trae 20k métodos para usar Analytics. Utilizo Proguard para quitar lo que no se necesita, pero aún así ... 72k métodos y contando ...
Puedo dividir classes.dex
en dos archivos usando el parámetro dx
--multi-dex . Lo logré editar manualmente
sdk/build-tools/android-4.4W/dx
y editar la última línea como esta:
exec java $javaOpts -jar "$jarpath" --multi-dex "$@"
Mi archivo APK ahora contiene __classes.dex__ and __classes2.dex__
.
Estoy intentando cargar dinámicamente el segundo archivo con algunos métodos:
Lamentablemente todavía no hay suerte. Realmente espero que algún gurú de Google / Facebook / Square pueda proporcionar una solución adecuada.
En caso de que gms fuera tu problema y estés usando gradle
A partir de gms versión 6.5 puede elegir bibliotecas API individuales
por ejemplo, para incluir solo la API de Maps:
compile ''com.google.android.gms:play-services-maps:6.5.87''
y aquí está la lista completa:
com.google.android.gms:play-services-base:6.5.87
com.google.android.gms:play-services-ads:6.5.87
com.google.android.gms:play-services-appindexing:6.5.87
com.google.android.gms:play-services-maps:6.5.87
com.google.android.gms:play-services-location:6.5.87
com.google.android.gms:play-services-fitness:6.5.87
com.google.android.gms:play-services-panorama:6.5.87
com.google.android.gms:play-services-drive:6.5.87
com.google.android.gms:play-services-games:6.5.87
com.google.android.gms:play-services-wallet:6.5.87
com.google.android.gms:play-services-identity:6.5.87
com.google.android.gms:play-services-cast:6.5.87
com.google.android.gms:play-services-plus:6.5.87
com.google.android.gms:play-services-appstate:6.5.87
com.google.android.gms:play-services-wearable:6.5.87
com.google.android.gms:play-services-all-wear:6.5.87
Soy el mantenedor de https://github.com/creativepsyco/secondary-dex-gradle/ y soy un gradle n00b, por lo tanto, elegí la ruta de los scripts de BASH, aunque creo que se puede hacer directamente en el archivo de compilación. O se puede refactorizar para que se ejecute como un complemento, podría hacerlo cuando esté a la altura de Gradle. Aquí está el motivo de mi lógica.
Para comprender cómo dividir el DEX, debe conocer el orden de tareas del sistema de compilación. Si está utilizando gradle, debe saber que hay una serie de tareas inyectadas dentro del ciclo de compilación.
Por ejemplo:
:sdk:processReleaseJavaRes UP-TO-DATE
:sdk:packageReleaseJar
:sdk:compileReleaseNdk UP-TO-DATE
:sdk:packageReleaseJniLibs UP-TO-DATE
:sdk:packageReleaseLocalJar UP-TO-DATE
:sdk:packageReleaseRenderscript UP-TO-DATE
:sdk:packageReleaseResources UP-TO-DATE
:sdk:bundleRelease
:app:prepareComAndroidSupportAppcompatV71910Library UP-TO-DATE
:app:prepareComFacebookAndroidFacebook3141Library UP-TO-DATE
:app:prepareDebugDependencies
:app:compileDebugAidl UP-TO-DATE
:app:compileDebugRenderscript UP-TO-DATE
:app:generateDebugBuildConfig UP-TO-DATE
:app:generateDebugAssets UP-TO-DATE
:app:mergeDebugAssets UP-TO-DATE
:app:generateDebugResValues UP-TO-DATE
:app:generateDebugResources UP-TO-DATE
:app:mergeDebugResources UP-TO-DATE
:app:processDebugManifest UP-TO-DATE
:app:processDebugResources UP-TO-DATE
:app:generateDebugSources UP-TO-DATE
:app:compileDebugJava
:app:preDexDebug
:app:dexDebug
:app:processDebugJavaRes UP-TO-DATE
:app:validateReleaseConfigSigning
:app:packageDebug
:app:zipalignDebug
:app:assembleDebug
Para realizar Dexing, debe ser capaz de inyectar su tarea personalizada entre las tareas dex * y process *. Si puedes hacer esto, entonces Múltiple DEXing se vuelve fácil.
El script Bash básicamente hace esto, si examina la tarea de depuración, básicamente:
- Obtenga el archivo Library Jar en dex, generalmente es específico de la compilación y existe en la carpeta
exploded-aar
para bibliotecas de Android y ejecuta la herramienta DEX en él - Copie esto en la carpeta de activos, que existe en la carpeta de libs final que se empacará dentro de la aplicación
- Todos los recursos de la biblioteca, etc. ya están fusionados, lo que significa que hay una necesidad de descomprimir y comprimir el archivo nuevamente.
En el script de construcción gradle
// For Debug simply remove the library from getting dex and create it
//----------------------- Extra Debug Step ----------------//
def libraryFiles = new ArrayList<?>()
def secondaryFile = new ArrayList<?>()
variant.dex.libraries.each {
File file ->
if (!file.absolutePath.contains("lib/unspecified/classes.jar")) {
libraryFiles.add(file)
} else {
secondaryFile.add(file)
}
}
variant.dex.libraries = libraryFiles
//----------------------- Extra Debug Step ----------------//
packagingTask.dependsOn variant.javaCompile
}
Esto elimina manualmente la biblioteca de dexed, para que pueda generarse a través del script bash.
Creo que puedes averiguar el dexing durante el proceso de lanzamiento de la misma manera. La otra cosa importante a tener en cuenta es que Proguard Task está controlado por el complemento android gradle y no se puede cambiar mucho al respecto. Problema con las reglas de Proguard:
- Cada pase de proguard es diferente, no queremos terminar en una situación en la que nuestros 2 DEX tengan asignaciones de proguard diferentes
- Esto nos deja en una situación en la que no podemos proteger nuestras bibliotecas, pero esto no es realmente deseable.
- Debe generar el archivo dex después de proguard para asegurarse de que las asignaciones sean las mismas. Gradle no tiene soporte para fusionar activos después de Proguard (Queremos poner los archivos dex en la carpeta de activos)
El otro pedazo importante de código reside en SecondaryDex.java que esencialmente carga el segundo archivo dex e inyecta la ruta del archivo DEX en la ruta de la clase de tiempo de ejecución. Puede optimizar esto y solo inyectar la ruta en lugar de leer el archivo DEX cada vez que se reanude la aplicación.
Hice el experimento secundario de Dex en Google Play Services (que agrega 20K métodos) y pude separarlo en un archivo DEX separado. De esta forma, mi archivo dex principal no se ve afectado por la cantidad de elementos en los servicios de Google Play.
Para comprender cómo funciona el ciclo de tareas de Gradle, puede BasePlugin.groovy origen de BasePlugin.groovy , puede ver que es difícil controlar algunos aspectos hasta que haya una API adecuada para acceder a los objetos variantes y crear tareas.
Un ejemplo de partición de proyecto y carga de diferentes archivos dex se puede encontrar aquí:
https://code.google.com/p/android-custom-class-loading-sample/
EDITAR: para Gradle ya tienes una respuesta
Carga de clases personalizadas en Dalvik con Gradle (Android New Build System)
Actualización para Android Gradle plugin 2.2.0: Ya no es posible acceder a la tarea dex
, pero a cambio se introdujo additionalParameters
como parte de dexOptions
. Úselo como
android {
dexOptions {
additionalParameters += ''--minimal-main-dex''
// additionalParameters += ''--main-dex-list=$projectDir/<filename>''.toString()
// additionalParameters += ''--set-max-idx-number=55000''
}
}
Actualización para Android Gradle plugin 0.14.0: ahora existe compatibilidad directa con varios dex a través de la nueva directiva multiDexEnabled true
(requiere build-tools 21.1.0, revisión de repositorio de soporte 8 y Android Studio 0.9).
Respuesta original: desde el complemento Gradle para Android 0.9.0, puede pasar el --multi-dex
a dx
agregando esto al archivo build.gradle
su aplicación:
afterEvaluate {
tasks.matching {
it.name.startsWith(''dex'')
}.each { dx ->
if (dx.additionalParameters == null) {
dx.additionalParameters = [''--multi-dex'']
} else {
dx.additionalParameters += ''--multi-dex''
}
// Add more additional parameters like this:
dx.additionalParameters += ''--main-dex-list=class-list.txt''
dx.additionalParameters += ''--minimal-main-dex''
}
}
Hasta ahora para la creación de múltiples archivos dex. Para usar realmente los archivos dex múltiples, eche un vistazo a https://github.com/casidiablo/multidex (que es una bifurcación de la próxima biblioteca de soporte de MultiDex de Google).