Gradle Android Build System Problemas de NDK
Voy a ser el primero en admitir que no soy muy experto en Gradle y el nuevo sistema de compilación de Android, pero, por desgracia, tuve que pasar a él (de ant) debido a la edición 21479 ( https://code.google .com / p / android / issues / detail? Id = 21479 ) y el comentario "Esto no se arreglará.Nos estamos centrando en terminar el sistema de compilación basado en Gradle que reemplazará a Ant." Por desgracia, no pude conseguir las cosas para construir de nuevo después de agregar la biblioteca de publicidad Millenium Media. Esto era además de la biblioteca OpenCV de Android, la biblioteca de cifrado de Chilkat y la biblioteca de soporte v4, pero la biblioteca de MMedia era la que rompía todo.
Por lo tanto, pensé, una buena razón para migrar a la nueva Gradle basado en sistema de construcción. Desafortunadamente, a pesar de dejar un sistema de construcción de hormigón roto, el nuevo sistema no parece estar terminado todavía; Particularmente el soporte ndk.
- Correspondencia de plantillas en Android usando openCV
- ¿Cómo instalar OpenCV Manager en un emulador?
- Cómo detectar la pupila del ojo circularmente en opencv
- Android UnsatisfiedLinkError con OpenCV 2.4.2
- OpenCV se bloquea después de un corto período de tiempo en la aplicación para Android
La aplicación en la que estoy trabajando utiliza OpenCV para el procesamiento de imágenes y un par de operaciones funcionan demasiado lentamente a menos que estén compiladas en nativo (MUCHOS movimientos de memoria y comparaciones que son demasiado lentas en el límite de JNI). Por lo tanto, en lugar de tratar de pasar los datos hacia atrás y hacia adelante entre la VM y el código nativo, dejo todas estas cosas en el lado nativo y sólo tiene una llamada de la máquina virtual para obtener los resultados.
El primer problema fue obtener las cosas ndk para compilar. No pude conseguir los ajustes en el cierre del ndk para trabajar así que tuve que recurrir a usar el comando ndk-build y ejecutarlo como una tarea:
task ndkBuild(type: Exec) { String MainDirectory = System.getProperty("user.dir") + '/app/src/main' println "Main app directory for NDK build " + MainDirectory if (Os.isFamily(Os.FAMILY_WINDOWS)) { commandLine 'gradle-ndk-build.cmd', MainDirectory, '-j' } else { commandLine 'gradle-ndk-build', MainDirectory, '-j' } } tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn ndkBuild }
Esto funciona perfectamente; Compila el código ndk y genera la biblioteca .so sin error. Desafortunadamente, no pondrá el archivo resultante .so en el paquete final. Pone todas las otras bibliotecas nativas en bien, pero no esta – no idea de por qué sin embargo.
He encontrado un montón de presuntos arreglos para este problema, tales como:
tasks.withType(com.android.build.gradle.tasks.PackageApplication) { pkgTask -> pkgTask.jniFolders = new HashSet<File>() pkgTask.jniFolders.add(new File(buildDir, 'native-libs')) }
Pero agregar esto sólo resulta en un archivo apk con NO librerías nativas en absoluto. He visto que otras personas tienen el mismo problema (como https://groups.google.com/forum/#!msg/adt-dev/QbDHM41QT2E/J4jHCC_RuIEJ ), pero he probado todas las soluciones propuestas y ninguna de ellas trabaja para mi.
Como no cambio el código nativo muy a menudo, acabo de hacer un hack para copiar la librería nativa generada (libndklib.so) desde app / src / main / libs a / app / src / main / jni después de haber sido Compilado; Entonces termina en el paquete apk. Obviamente, esto es un poco desagradable como, si alguien toma este código, se preguntarán por qué sus cambios en el código nativo nunca aparecen en la aplicación.
Por lo tanto, mis preguntas son: ¿Hay algo que puedo ejecutar en el script gradle que se ejecutará después de ejecutar el comando ndk (gradle-ndk-build) que copiará los archivos generados desde app / src / main / Libs / armeabi / libndklib.so a /app/src/main/jni/armeabi/libndklib.so (para cada una de las arquitecturas – armeabi, armeabi-v7, x86, mips) para que termine en el paquete apk?
O
¿Hay alguna manera de hacer el cierre de Ndk Gradle manejar el siguiente ndk hacer archivos correctamente: Application.mk
APP_STL := gnustl_static APP_CPPFLAGS := -frtti -fexceptions APP_ABI := all APP_PLATFORM := android-8
Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) # OpenCV OPENCV_CAMERA_MODULES:=on OPENCV_INSTALL_MODULES:=on OPENCV_LIB_TYPE:=SHARED include /home/myname/tools/OpenCV-2.4.8-android-sdk/sdk/native/jni/OpenCV.mk LOCAL_MODULE := ndklib LOCAL_SRC_FILES := ndklib.cpp motion.cpp LOCAL_LDLIBS += -lm -llog include $(BUILD_SHARED_LIBRARY) # Add prebuilt chilkat library include $(CLEAR_VARS) LOCAL_MODULE := lib-chilkat LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libchilkatemail.so include $(PREBUILT_SHARED_LIBRARY)
Miré la fuente de Gradle para el plug-in pero no pude ver muchas de estas directivas soportadas.
O
¿Puedo añadir algún tipo de hack que se ejecuta al final del script Gradle que sólo fuerza la copia apropiada de libndklib.so (para la arquitectura correcta) en el apk generado? Puedo vivir con este último hasta que el material ndk esté terminado para el complemento de Android para la compilación gradle.
========================================
Editar – Después de la respuesta de ph0b Este es el archivo build.gradle final con el mod propuesto en él. Crea el .apk perfectamente build.gradle (en el directorio de la aplicación)
buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.9.+' } } apply plugin: 'android' import org.apache.tools.ant.taskdefs.condition.Os android { compileSdkVersion 19 buildToolsVersion "19.0.3" signingConfigs { debug { storeFile file("dbgkeystore") storePassword "nopass" keyAlias "mainkeyname" keyPassword "nopass" } release { storeFile file("keystore") storePassword "xxxxxxxx" keyAlias "mainkeyname" keyPassword "yyyyyyyy" } } // Autoincrement the version properties file // ****************************************** def versionPropsFile = file('version.properties') def code = 1 def majorversion = 1 def minorversion = 1 defaultConfig { versionCode code versionName "${majorversion}.${minorversion}.${code}" minSdkVersion 10 targetSdkVersion 19 } buildTypes { release { runProguard true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' signingConfig signingConfigs.release } debug { runProguard false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' packageNameSuffix ".debug" versionNameSuffix "-debug" signingConfig signingConfigs.debug } } sourceSets { main { jni.srcDirs = [] // jniLibs.srcDir 'src/main/jni' // - Doesn't work, leaves out the .so files generated by ndk-build jniLibs.srcDir 'src/main/libs' } } flavorDimensions "version", "abi" productFlavors { pro { flavorDimension "version" packageName "org.somedomainname.myAppPro1" } lite { flavorDimension "version" packageName "org.somedomainname.myAppLite1" } arm { flavorDimension "abi" ndk { abiFilter "armeabi" } if (versionPropsFile.canRead()){ def Properties versionProps = new Properties() versionProps.load(new FileInputStream(versionPropsFile)) code = versionProps['VERSION_CODE'].toInteger() + 1 versionProps['VERSION_CODE']=code.toString() versionProps.store(versionPropsFile.newWriter(), null) versionCode code versionName "${majorversion}.${minorversion}.${code}" } else { throw new GradleException("Could not read version.properties!") } } armv7 { flavorDimension "abi" ndk { abiFilter "armeabi-v7a" } if (versionPropsFile.canRead()){ def Properties versionProps = new Properties() versionProps.load(new FileInputStream(versionPropsFile)) code = versionProps['VERSION_CODE'].toInteger() + 1 versionProps['VERSION_CODE']=code.toString() versionProps.store(versionPropsFile.newWriter(), null) versionCode code versionName "${majorversion}.${minorversion}.${code}" } else { throw new GradleException("Could not read version.properties!") } } x86 { flavorDimension "abi" ndk { abiFilter "x86" } if (versionPropsFile.canRead()){ def Properties versionProps = new Properties() versionProps.load(new FileInputStream(versionPropsFile)) code = versionProps['VERSION_CODE'].toInteger() + 1 versionProps['VERSION_CODE']=code.toString() versionProps.store(versionPropsFile.newWriter(), null) versionCode code versionName "${majorversion}.${minorversion}.${code}" } else { throw new GradleException("Could not read version.properties!") } } } lintOptions { checkReleaseBuilds false // Or, if you prefer, you can continue to check for errors in release builds, // but continue the build even when errors are found: abortOnError false } repositories { mavenCentral() flatDir { dirs '/home/myname/maindrive/work/dynamic/android/UtilLib/aarlib' } } dependencies { compile 'com.android.support:appcompat-v7:+' compile fileTree(dir: 'libs', include: ['*.jar']) // Note: org.somedomainname.UtilLib on the depency below is ignored when usng flatdir compile 'org.somedomainname.UtilLib:library:1.0.0@aar' } task ndkBuild(type: Exec) { String MainDirectory = System.getProperty("user.dir") + '/app/src/main' println '************************************************************************' println "Main app directory for NDK build " + MainDirectory println '************************************************************************' if (Os.isFamily(Os.FAMILY_WINDOWS)) { commandLine 'gradle-ndk-build.cmd', MainDirectory, '-j' } else { commandLine 'gradle-ndk-build', MainDirectory, '-j' } } tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn ndkBuild } android.applicationVariants.all { variant -> variant.assemble.doLast { rename_and_moveout_apk(variant) } } // allprojects { // tasks.withType(Compile) { // options.compilerArgs << "-Xlint:deprecation" // } // } def rename_and_moveout_apk(targetVariant) { // replace output apk name to <product>-<version>-<buildtype>-<githash>.apk def versionSuffix = targetVariant.buildType.versionNameSuffix ? targetVariant.buildType.versionNameSuffix : "" def versionName = targetVariant.mergedFlavor.versionName + versionSuffix; if (targetVariant.zipAlign) { def apkFinal = targetVariant.outputFile; def apkFinalNewName = "myApp-" + apkFinal.name.replace(targetVariant.buildType.name, versionName); copy { from "$apkFinal" into "$rootProject.projectDir/apk_release" rename ("$apkFinal.name", "$apkFinalNewName") println "*************** Renaming zipalign apk file from: ${apkFinal.name} to ${apkFinalNewName}" } } }
Gradle-ndk-build (versión modificada de ndk-build usada para depurar los parámetros)
#!/bin/bash export NDK_PROJECT_PATH=$1 export NDK_PROJECT_DIRECTORY=$1 bash -c "ndk-build"
Estructura del Directorio
------ apk_release ------ app -- -- ---- src -- ------ lite -- -- -- ---- java -- -- -- ---- org -- -- -- ---- somedomainname -- -- -- ---- myApp -- ------ main -- -- ------ assets -- -- ------ java -- -- -- -- ---- org -- -- -- ------ chilkatsoft -- -- -- -- ---- somedomainname -- -- -- -- ---- myApp -- -- ------ jni -- -- -- ------ armeabi -- -- -- ------ armeabi-v7a -- -- -- ------ mips -- -- -- -- ---- x86 -- -- ------ libs -- -- -- ------ armeabi -- -- -- ------ armeabi-v7a -- -- -- ------ mips -- -- -- -- ---- x86 -- -- ------ obj -- -- -- -- ---- local -- -- -- ------ armeabi -- -- -- -- -- ---- objs -- -- -- -- -- ---- ndklib -- -- -- ------ armeabi-v7a -- -- -- -- -- ---- objs -- -- -- -- -- ---- ndklib -- -- -- ------ mips -- -- -- -- -- ---- objs -- -- -- -- -- ---- ndklib -- -- -- -- ---- x86 -- -- -- -- ---- objs -- -- -- -- ---- ndklib -- -- -- ---- res -- -- ------ drawable -- -- ------ drawable-hdpi -- -- ------ drawable-ldpi -- -- ------ drawable-mdpi -- -- ------ drawable-xhdpi -- -- ------ drawable-xxhdpi -- -- ------ layout -- -- ------ raw -- -- ------ values -- -- -- ---- xml -- -- ---- pro -- -- ---- java -- -- ---- somedomainname -- -- ---- myApp
- Cómo leer el valor de cada píxel como valores RGB del objeto Mat m en OpenCV
- OpenCV Android: ¿Cómo dibujar puntos clave coincidentes con las imágenes comparadas?
- make: *** No se han especificado objetivos y no se ha encontrado ningún makefile. Detener
- Error: Programa "/ NDK-build" no se encuentra en PATH
- Explicitamente liberando Mat con opencv 2.0
- Convertir código OpenCV de C ++ a Java
- Android OpenCV: dibujo de partidos con feature2d
- ANDROID - detección de color usando openCV - cómo?
Gradle buscará automáticamente los archivos jniLibs/ABI/
dentro de jniLibs/ABI/
.
Puede cambiar este comportamiento para que use su directorio normal de libs
estableciéndolo dentro del archivo build.gradle :
android { sourceSets.main { jniLibs.srcDir 'src/main/libs' } }