tutorial studio saber productflavors procesador now must flavors flavor configurar como belong arquitectura all android opencv gradle multiprocessor android-gradle

studio - Gradle android build para diferentes arquitecturas de procesador



flavor android (4)

Quiero construir 4 aplicaciones por separado para 4 arquitecturas diferentes de procesadores de CPU Android (armeabi armeabi-v7a x86 mips) usando Gradle.

Tengo librerías nativas OpenCV creadas para 4 arquitecturas de CPU en la carpeta libs .

libs -armeabi -armeabi-v7a -x86 -mips

Quiero que cada apk solo contenga la biblioteca OpenCV correspondiente a la arquitectura de CPU correcta.

El script de compilación actual es el siguiente:

apply plugin: ''android'' dependencies { compile fileTree(dir: ''libs'', include: ''*.jar'') compile project('':workspace:OpenCV4Android:sdk:java'') } android { compileSdkVersion 11 buildToolsVersion "18.1.0" sourceSets { main { manifest.srcFile ''AndroidManifest.xml'' java.srcDirs = [''src''] resources.srcDirs = [''src''] aidl.srcDirs = [''src''] renderscript.srcDirs = [''src''] res.srcDirs = [''res''] assets.srcDirs = [''assets''] } // Move the tests to tests/java, tests/res, etc... instrumentTest.setRoot(''tests'') debug.setRoot(''build-types/debug'') release.setRoot(''build-types/release'') flavorGroups "abi", "version" productFlavors { x86 { flavorGroup "abi" } arm { flavorGroup "abi" } mips { flavorGroup "abi" } } } }

¿Alguien puede ayudarme a resolver esto por favor?

Aclamaciones,


A partir de Android Gradle Plugin versión 13 ahora puede generar archivos APK separados utilizando el nuevo mecanismo de "división". Puedes leer sobre esto here .

La estructura de archivos predeterminada para colocar sus archivos .so es:

src -main -jniLibs -armeabi -arm.so -armeabi-v7a -armv7.so -x86 -x86.so -mips -mips.so

Tenga en cuenta que el nombre del archivo .so no es importante siempre que tenga la extensión .so.

Luego en tu archivo de compilación Gradle:

android { ... splits { abi { enable true reset() include ''x86'', ''armeabi-v7a'', ''mips'', ''armeabi'' universalApk false } } }

y

// map for the version code ext.versionCodes = [''armeabi-v7a'':1, mips:2, x86:3] import com.android.build.OutputFile android.applicationVariants.all { variant -> // assign different version code for each output variant.outputs.each { output -> output.versionCodeOverride = project.ext.versionCodes.get(output.getFilter(OutputFile.ABI)) * 1000000 + android.defaultConfig.versionCode } }

Tenga en cuenta que los códigos de versión anteriores en ext.versionCodes son en gran parte irrelevantes, aquí está para agregar un desplazamiento único para cada tipo de ABI, por lo que los códigos de versión no entran en conflicto.


ACTUALIZACIÓN: desde el momento de esta publicación, se ha avanzado mucho en el proceso de compilación de gradle, por lo tanto, esta respuesta podría no ser la mejor práctica recomendada y los nuevos cambios podrían incluso frenarla. Use su propio criterio

Para hacer eso, primero, debe colocar las bibliotecas nativas en la siguiente jerarquía de carpetas por separado

lib -armeabi -arm.so -*.so

-

lib -x86 -x86.so -*.so

luego comprime las carpetas lib (sin ''s'') (por ejemplo, arm.zip y x86.zip) y cambia el nombre de la extensión ''zip'' a ''jar'' (por ejemplo, arm.jar y x86.jar). Coloque estos frascos en las carpetas apropiadas (p. Ej., Armeabi / libs y x86 / libs). Ahora vamos a incluir las dependencias para cada sabor. Pero no podemos usar "compilar archivo ''...''". Tenemos que usar "flavorCompile file ''...''"

p.ej

flavorGroups ''abi'' productFlavors { arm { flavorGroup ''abi'' dependencies { armCompile files(''arm/libs/armeabi.jar'') } } x86 { flavorGroup ''abi'' dependencies { x86Compile files(''x86/libs/x86.jar'') } } }

====

Aquí hay un entorno más complejo. No solo tiene variantes de arquitectura de procesador sino que también tiene bibliotecas de depuración ( .jar, .so) para los procesadores. El ejemplo aquí tiene como Debug.jar para Arm debug y NonDebug.jar para Arm; y * .so para ambos, Arm y X86. Dicha configuración se puede lograr utilizando gradle ExtraPropertiesExtension Lea mi respuesta SO aquí, https://.com/a/19941684/319058 , para comprender cómo se pueden estructurar las carpetas de depuración.

android { compileSdkVersion 18 buildToolsVersion "19.0.0" final DEBUG_ROOT = "build-types/debug" final RELEASE_ROOT = "build-types/release" project.ext.set("projRoot", "") buildTypes { debug { project.projRoot = DEBUG_ROOT dependencies { debugCompile files(DEBUG_ROOT+"/libs/Debug.jar") } } release { project.projRoot = RELEASE_ROOT dependencies { releaseCompile files(RELEASE_ROOT+"/libs/NonDebug.jar") } runProguard true proguardFile ''proguard.cfg'' } } sourceSets { final PROJ_ROOT = project.ext.get("projRoot") final BUILD_TYPE_RES = PROJ_ROOT + "/res" main { manifest.srcFile ''src/main/AndroidManifest.xml'' java.srcDirs = [''src/main/java''] //resources.srcDirs = [''src/main''] //aidl.srcDirs = [''src/main''] //renderscript.srcDirs = [''src/main''] res.srcDirs = [''src/main/res'',BUILD_TYPE_RES] assets.srcDirs = [''src/main/assets''] } flavorGroups ''abi'' productFlavors { arm { flavorGroup ''abi'' final ARM_LIB_PATH = PROJ_ROOT + "/arm/libs/armeabi.jar" dependencies { armCompile files(ARM_LIB_PATH) } } x86 { flavorGroup ''abi'' final X86_LIB_PATH = PROJ_ROOT + "/x86/libs/x86.jar" dependencies { x86Compile files(X86_LIB_PATH) } } } // Move the tests to tests/java, tests/res, etc... instrumentTest.setRoot(''tests'') // Move the build types to build-types/<type> // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ... // This moves them out of them default location under src/<type>/... which would // conflict with src/ being used by the main source set. // Adding new build types or product flavors should be accompanied // by a similar customization. debug.setRoot(DEBUG_ROOT) release.setRoot(RELEASE_ROOT) }

}


La solución ABI APK dividida para gradle es la más simple que he encontrado hasta ahora. @withoutlass tiene una buena reseña aquí: https://.com/a/26129447/254573 Tuve que hacer referencia a la documentación de Android ya que esta es una característica nueva que aún puede cambiar: http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits

Sin embargo, terminé teniendo que abandonar esta implementación simple ya que necesitaba admitir compilaciones de gran tamaño y construcciones específicas de arquitectura. Es posible que se encuentre con este mismo problema si admite tanto la tienda de Google Play (que admite archivos APK específicos de la arquitectura) como la tienda de aplicaciones de Amazon (que solo admite APK de gran tamaño).

Es posible hacer esto con archivos APK divididos si puede agregar un componente de sabor, pero a partir de ahora no se admite la división + sabor: https://code.google.com/p/android/issues/detail?id=76469

Terminé usando abiFilter, mira el código de muestra a continuación:

android { flavorDimensions "abi" productFlavors { fat { flavorDimension "abi" ndk { abiFilters "x86", "armeabi-v7a", "armeabi" versionCode = 0; } } arm { flavorDimension "abi" ndk { abiFilter "armeabi" versionCode = 1; } } armv7a { flavorDimension "abi" ndk { abiFilter "armeabi-v7a" versionCode = 3; } } x86 { flavorDimension "abi" ndk { abiFilter "x86" versionCode = 6; } } } } // Each APK needs a different version code when submitted to Google, // bump the versionCode we set in defaultConfig android.applicationVariants.all { variant -> // Ugly hard coded flavorDimensions position // If you have more than one flavorDimension, make sure to target the position for "abi" def abiVersion = variant.productFlavors.get(0).versionCode variant.mergedFlavor.versionCode = abiVersion * 1000 + android.defaultConfig.versionCode }

Actualizar Usar universalApk establecido en true soluciona esta solución, simplemente agrega tiempo para compilar cada apk.

android { // Rest of Gradle file splits { abi { enable true reset() include ''armeabi'', ''armeabi-v7a'', ''x86'' universalApk true } } } //Ensures architecture specific APKs have a higher version code //(otherwise an x86 build would end up using the arm build, which x86 devices can run) ext.versionCodes = [armeabi:1, ''armeabi-v7a'':3, x86:6] android.applicationVariants.all { variant -> // assign different version code for each output variant.outputs.each { output -> int abiVersionCode = project.ext.versionCodes.get(output.getFilter(OutputFile.ABI)) ?: 0 output.versionCodeOverride = (abiVersionCode * 1000) + android.defaultConfig.versionCode } }


No tengo una respuesta gradle, pero creo que ahora tengo una respuesta genérica para cualquier herramienta de compilación de Android. Aquí está mi idea sobre cómo crear archivos APK por separado para cada arquitectura de procesador compatible:

  1. Cree su APK con las herramientas que use, que contengan todas las bibliotecas de códigos nativos que admita, por ejemplo, armeabi, armeabi-v7a, x86 y mips. Lo llamaré el archivo APK ''original''.

  2. Descomprima su APK original en una carpeta vacía, con cualquier utilidad de descomprimir / descomprimir, utilice mejor las herramientas de línea de comandos, de modo que pueda automatizarlo con un script de shell o un archivo por lotes más adelante.

  3. En la carpeta donde se descomprimió el APK original, elimine la subcarpeta META-INF (esta contiene las firmas, necesitaremos volver a firmar el APK después de todas las modificaciones, por lo que se debe eliminar el META-INF original).

  4. Cambie a la subcarpeta lib y elimine las subcarpetas de las arquitecturas de procesador que no desee en el nuevo archivo APK. Por ejemplo, deje solo la subcarpeta ''x86'' para crear una APK para los procesadores Intel Atom.

  5. Importante: cada APK para una arquitectura diferente debe tener un número diferente de ''versionCode'' en AndroidManifest.xml, y el código de versión para, por ejemplo, armeabi-v7a debe ser un poco más alto que el de armeabi (lea las instrucciones de Google para crear múltiples APK aquí: http://developer.android.com/google/play/publishing/multiple-apks.html ). Desafortunadamente, el archivo de manifiesto está en un formulario binario compilado dentro del APK. Necesitamos una herramienta especial para modificar el código de versión allí. Vea abajo.

  6. Una vez que el manifiesto se modifique con un nuevo código de versión y se eliminen los directorios y archivos innecesarios, vuelva a comprimir, firme y alinee su APK más pequeña (use las herramientas jarsigner y zipalign de Android SDK).

  7. Repite el proceso para todas las demás arquitecturas que necesites, creando archivos APK más pequeños con códigos de versión ligeramente diferentes (pero con el mismo nombre de versión).

El único problema pendiente es la forma de modificar ''versionCode'' en el archivo de manifiesto binario. No pude encontrar una solución para esto durante mucho tiempo, así que finalmente tuve que sentarme y poner mi propio código para hacer esto. Como punto de partida, tomé APKExtractor de Prasanta Paul, http://code.google.com/p/apk-extractor/ , escrito en Java. Soy de la vieja escuela y aún me siento más cómodo con C ++, así que mi pequeño programa de utilidad ''aminc'' escrito en C ++ ahora está en GitHub en:

https://github.com/gregko/aminc

Publiqué la solución completa de Visual Studio 2012, pero todo el programa es un único archivo .cpp que probablemente se puede compilar en cualquier plataforma. Y aquí hay un ejemplo del archivo .bat de Windows que uso para dividir mi apk "gorda" llamada atVoice.apk en 4 archivos más pequeños llamados atVoice_armeabi.apk, atVoice_armeabi-v7a.apk, atVoice_x86.apk y atVoice_mips.apk. De hecho, envío estos archivos a Google Play (mira mi aplicación en https://play.google.com/store/apps/details?id=com.hyperionics.avar ) y todo funciona perfectamente. También vea este proyecto Github de Jorge Suárez de Lis , quien publica un script similar para Linux.

@echo off REM My "fat" apk is named atVoice.apk. Change below to whatever or set from %1 set apkfile=atVoice del *.apk REM My tools build atVoice-release.apk in bin project sub-dir. REM Copy it here for splitting. copy ../bin/%apkfile%-release.apk %apkfile%.apk zip -d %apkfile%.apk META-INF/* REM ------------------- armeabi ------------------------ unzip %apkfile%.apk AndroidManifest.xml copy/y %apkfile%.apk %apkfile%.zip zip -d %apkfile%.zip lib/armeabi-v7a/* lib/x86/* lib/mips/* aminc AndroidManifest.xml 1 zip -f %apkfile%.zip ren %apkfile%.zip %apkfile%_armeabi.apk jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore d:/users/greg/.android/Hyperionics.keystore -storepass MyPass %apkfile%_armeabi.apk MyKeyName zipalign 4 %apkfile%_armeabi.apk %apkfile%_armeabi-aligned.apk del %apkfile%_armeabi.apk ren %apkfile%_armeabi-aligned.apk %apkfile%_armeabi.apk REM ------------------- armeabi-v7a --------------------- copy/y %apkfile%.apk %apkfile%.zip zip -d %apkfile%.zip lib/armeabi/* lib/x86/* lib/mips/* aminc AndroidManifest.xml 1 zip -f %apkfile%.zip ren %apkfile%.zip %apkfile%_armeabi-v7a.apk jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore d:/users/greg/.android/Hyperionics.keystore -storepass MyPass %apkfile%_armeabi-v7a.apk MyKeyName zipalign 4 %apkfile%_armeabi-v7a.apk %apkfile%_armeabi-v7a-aligned.apk del %apkfile%_armeabi-v7a.apk ren %apkfile%_armeabi-v7a-aligned.apk %apkfile%_armeabi-v7a.apk REM ------------------- x86 --------------------- copy/y %apkfile%.apk %apkfile%.zip zip -d %apkfile%.zip lib/armeabi/* lib/armeabi-v7a/* lib/mips/* aminc AndroidManifest.xml 9 zip -f %apkfile%.zip ren %apkfile%.zip %apkfile%_x86.apk jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore d:/users/greg/.android/Hyperionics.keystore -storepass MyPass %apkfile%_x86.apk MyKeyName zipalign 4 %apkfile%_x86.apk %apkfile%_x86-aligned.apk del %apkfile%_x86.apk ren %apkfile%_x86-aligned.apk %apkfile%_x86.apk REM ------------------- MIPS --------------------- copy/y %apkfile%.apk %apkfile%.zip zip -d %apkfile%.zip lib/armeabi/* lib/armeabi-v7a/* lib/x86/* aminc AndroidManifest.xml 10 zip -f %apkfile%.zip ren %apkfile%.zip %apkfile%_mips.apk jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore d:/users/greg/.android/Hyperionics.keystore -storepass MyPass %apkfile%_mips.apk MyKeyName zipalign 4 %apkfile%_mips.apk %apkfile%_mips-aligned.apk del %apkfile%_mips.apk ren %apkfile%_mips-aligned.apk %apkfile%_mips.apk del AndroidManifest.xml del %apkfile%.apk :done

Greg