studio ndk full developers descargar configurar android-ndk android-studio android-gradle

android-ndk - full - configurar ndk android studio



Cómo configurar NDK con Android Gradle plugin 0.7 (6)

El nuevo complemento gradle de Android (0.7) parece incluir un nuevo soporte para NDK, pero en la documentación hay poca o ninguna mención (la única referencia que encontré es una prueba llamada ndkSanAngeles ).

Parece que gradle está buscando el NDK, que he incluido en mi PATH. Sin embargo, la construcción del proyecto falla con

  • Qué salió mal: Error de ejecución para la tarea '': OGLTests: compileDefaultFlavorDebugNdk''. NDK no configurado

¿Cómo puedo configurar el NDK en gradle?

Mi build.gradle actual se ve así:

task nativeLibsToJar(type: Zip, description: ''create a jar with native libs'') { destinationDir file("$buildDir/native-libs") baseName ''native-libs'' extension ''jar'' from fileTree(dir: ''src/main/libs'', include: ''**/*.so'') from fileTree(dir: ''src/main/libs'', include: ''**/gdb*'') into ''lib/'' } tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn nativeLibsToJar } dependencies { compile fileTree(dir: "$buildDir/native-libs", include: ''*.jar'') } android { compileSdkVersion 19 buildToolsVersion ''19.0.0'' defaultConfig { minSdkVersion 14 targetSdkVersion 19 versionCode 1 versionName "0.1" } buildTypes { release { runProguard false } debug { // jniDebugBuild true runProguard false debuggable true } } productFlavors { defaultFlavor { proguardFile ''proguard-rules.txt'' } } }

Gracias.


Al revisar el código del complemento de Gradle, encontré lo siguiente que me ayudó a usar las bibliotecas nativas NDK y pre compiladas:

Para enlazar simplemente en bibliotecas nativas preconstruidas , simplemente agregue una sección ndk a su tarea. Por ejemplo, lo agregué a continuación en productFlavors. AbiFilter es el nombre de la carpeta en la que se almacenan las bibliotecas. AbiFilters significa que ambas libs de la lista separada por comas se agregarán a tu APK final (por lo que teóricamente podrías tener "armeabi", "armeabi-v7a", "x86" y " mips "todo en uno APK, y el O / S elegiría la arquitectura compatible lib en la instalación):

productFlavors { arm { ndk { abiFilters "armeabi", "armeabi-v7a" } } x86 { ndk { abiFilter "x86" } } }

En este ejemplo, la construcción del brazo creará una APK con las bibliotecas de brazo V5 y V7A, y la versión x86 creará una APK con solo libs x86. Esto buscará las bibliotecas nativas en el directorio de su proyecto jniLibs. El directorio jniLibs debe ser estructuras como el antiguo directorio jni, es decir:

[project]/[app]/src/main/jniLibs/armeabi/libmyNative.so [project]/[app]/src/main/jniLibs/armeabi-v7a/libmyNative.so [project]/[app]/src/main/jniLibs/x86/libmyNative.so

Luego puede cargarlo en Java de la siguiente manera:

static { loadLibrary("myNative"); }

Ahora, digamos que una biblioteca nativa depende de otra. DEBE (si establece su API mínima a la API 17 o inferior) cargar primero las bibliotecas dependientes:

static { loadLibrary("myDependency"); loadLibrary("myNative"); }

También puede colocar la sección ndk {} en su DefaultConfig o buildType (como depuración o versión o cualquier otra cosa que pueda usar). Por ejemplo:

buildTypes { debug { ndk { abiFilters "armeabi", "armeabi-v7a" } } }

Por precompilado, me refiero a libs de terceros que descargó o una biblioteca que ha creado utilizando la cadena de herramientas NDK o su propia cadena de herramientas ARM (no el script ndk-build en sí).

En la API 18, arreglaron un problema arquitectónico de larga data que impedía que el cargador de lib nativo cargara dependencias "de manera automática" porque desconocía el directorio lib de la aplicación (razones de seguridad, etc.). En API 18 y superior, si myNative depende de myDependency anterior, solo puede llamar a loadLibrary ("myNative") y el SO se encargará de cargar myDependency. No confíe en esto, sin embargo, hasta que la penetración en el mercado de los dispositivos con API 17 y menor se encuentre en un número bajo aceptable para usted.


Para crear Bibliotecas NDK explícitamente en la versión actual de Android Studio, puede hacer lo siguiente:

Establezca el valor ndk.dir en sus local.properties para apuntar a NDK home como se mencionó anteriormente. ¿Alguien sabe si puede usar env vars directamente en local.properties? :)

En su archivo build.gradle, agregue algo como esto a su tarea (de nuevo, puede ser defaultConfig, debug, release, productFlavor, etc.):

ndk { moduleName "myNDKModule" stl "stlport_shared" ldLibs "log", "z", "m" cFlags "-I/some/include/path" }

Esta es la estructura básica con los tipos admitidos actualmente (moduleName, stl, ldLibs y cFlags). Miré y no encontré más que esto. Existe un problema que creo con ldLibs porque agrega automáticamente "-l" al frente de cada campo de arriba. Sin embargo, puedes engañar (tuve que) diciendo: ldLibs "log -lz -lm -Wl, -whole-archive -l / path / to / someOtherLib -Wl, -no-whole-archive"

En esta línea, solo está etiquetando al final del primer parámetro para agregar parámetros que no comienzan con -l, de modo que puede continuar por el momento. En el caso anterior, estoy vinculando una biblioteca estática completa en mi módulo NDK para su uso desde dentro de Java. Le pedí al desarrollador de Google que agregue características adicionales para permitir esto o incluso la posibilidad de fusionar su propio archivo Android.mk en el proceso de compilación de NDK, pero como todo esto es nuevo, puede pasar un tiempo.

Actualmente, lo que sea que pongas en build.gradle borra el directorio temp build y lo recrea cada vez, así que a menos que quieras descargar y modificar el código fuente del plugin android gradle (que sería divertido), hay algunos "make due" ''s como esto se requiere para obtener sus cosas copiadas en la construcción. La secuencia de comandos gradle de Android que proporciona este soporte ndk en esencia genera un archivo Android.mk y crea usando el sistema NDK en un directorio temporal.

Desviados por un segundo. El moduleName debe coincidir con el archivo ac o cpp en su proyecto en el directorio jni como:

[project]/[app]/src/main/jni/myNDKModule.cpp

El valor stl debe establecerse en un valor de "stlport_shared" o "stlport_static" si desea usar las bibliotecas stlport para C ++. Puede dejar stl si no necesita soporte extendido de C ++. Recuerde que Android proporciona soporte básico de C ++ por defecto. Para otras bibliotecas compatibles de C ++, consulte las pautas de documentación de NDK en el NDK que descargó. Tenga en cuenta que al establecerlo en stlport_shared aquí, gradle copia libstlport_shared.so lib del directorio sources / cxx-stl / stlport / libs de su NDK en los directorios lib de su APK. También maneja la ruta de inclusión en el compilador (técnicamente, el gradle no hace todo esto, sino el sistema de compilación Android NDK). Así que no coloque su propia copia de stlport en su directorio jniLibs.

Por último, creo que cFlags es bastante obvio.

No puede configurar ANDROID_NDK_HOME en Mac OSX (ver a continuación), pero a partir de algunas investigaciones que he hecho aparece, tal vez esto todavía funciona en otros sistemas operativos. Sin embargo, se eliminará.

Quería comentar pero aún no tengo la reputación. Dennis, las variables de entorno se ignoran por completo, no solo se anulan. De hecho, no obtiene ninguna de sus variables de entorno. Por lo que puedo decir, Android Studio IDE crea su propio entorno con solo unas pocas variables de entorno específicas (compruebe System.getenv () e imprímalo desde un script de gradle).

Escribí esto como un error aquí porque el uso de vars de env se construye bien desde la línea de cmd:
https://code.google.com/p/android/issues/detail?id=65213

pero como puede ver, Google decidió que no querían que el IDE utilizara variables de entorno; Todavía estoy en la cerca con esa decisión. Me duele la vida tener que actualizar local.properties para apuntar a rutas absolutas que pueden cargarse en mis scripts de gradle, que todavía no he resuelto cómo hacerlo (pero que no han sido tan difíciles). Eso significa que obligo a los miembros de mi equipo a usar el mismo camino que yo, jugar con enlaces, hacer que todos los tipeen cada vez que retiran el repositorio, o agregar un script de automatización. Creo que es una mala decisión que le costará tiempo a los desarrolladores que dependen de los entornos, que pueden ser pequeños en el nivel micro, pero enormes en el nivel macro.

Groundloop, creo que el IDE se actualizará pronto con la posibilidad de agregar la ruta de la carpeta NDK a su proyecto, y generará automáticamente el archivo local.properties a partir de eso (al menos no tendría sentido si no hubieran pensado en esta).

Para obtener ejemplos más detallados de Google, estos son los ejemplos más recientes (búsqueda de jni o ndk): https://docs.google.com/viewer?a=v&pid=sites&srcid=YW5kcm9pZC5jb218dG9vbHN8Z3g6NDYzNTVjMjNmM2YwMjhhNA


APK de grasa multiplataforma usando NDK:

Por último, hay un inconveniente al usar gradle y no poder proporcionar su propio archivo Android.mk para que solo pueda vincular bibliotecas nativas de terceros desde una única arquitectura a su NDK. Nota: dije "enlace en". Puede construir los módulos NDK (moduleName arriba) en varias arquitecturas con el comando "abiFilters", y se colocarán en su aplicación de manera que el mismo APK se pueda usar en múltiples arquitecturas. Si necesita vincular sus libs de terceros o incluso tener diferentes valores para cFlags dependiendo de su arquitectura, no hay una manera simple.

Intenté lo siguiente y al principio pareció funcionar, pero luego descubrí que simplemente estaba compilando el NDK agregando todo junto desde las dos secciones de ndk (o algo así, de todos modos construyó varias bibliotecas de arquitectura):

android { compileSdkVersion 23 buildToolsVersion ''23.0.1'' defaultConfig { minSdkVersion 14 targetSdkVersion 23 versionCode 28 versionName "3.0" } buildTypes { def commonLibs = " -lfoo -lbar -lwhatever" def armV7LibsDir = "/whatever/armv7a/libs" def armX86LibsDir = "/whatever/x86/libs" def armV7IncDir = "/whatever/armv7a/include" def x86IncDir = "/whatever/x86/include" debug { ndk { cFlags = "-I" + armV7IncDir moduleName "myNativeCPPModule" stl "stlport_shared" abiFilter "armeabi-v7a" ldLibs "log -L" + armV7LibsDir + commonLibs } ndk { cFlags = "-I" + armX86IncDir moduleName "myNativeCPPModule" stl "stlport_shared" abiFilter "x86" ldLibs "log -L" + armX86LibsDir + commonLibs } } } }

Después de mucho dolor tratando de crear un binario gordo en una mansión limpia con gradle y libs nativas de terceros, finalmente llegué a la conclusión de que el soporte multi-arquitectura incorporado de Google Play para APK es realmente la mejor ruta para ir de todos modos, así que crea APK individuales para cada arquitectura.

Así que creé múltiples buildTypes, sin sabores de producto, y agregué el siguiente código para generar el código de versión para cada tipo.

// This is somewhat nasty, but we need to put a "2" in front of all ARMEABI-V7A builds, a "3" in front of 64-bit ARM, etc. // Google Play chooses the best APK based on version code, so if a device supports both X86 and // ARM, it will choose the X86 APK (preferred because Inky ARM running on an X86 with Houdini ARM Emulator crashes in our case) android.applicationVariants.all { variant -> if (variant.buildType.name.equals(''release'')) { variant.mergedFlavor.versionCode = 2000 + defaultConfig.versionCode } else if (variant.buildType.name.equals(''debug'')) { variant.mergedFlavor.versionCode = 2000 + defaultConfig.versionCode } else if (variant.buildType.name.equals(''debugArmV8a'')) { variant.mergedFlavor.versionCode = 3000 + defaultConfig.versionCode } else if (variant.buildType.name.equals(''releaseArmV8a'')) { variant.mergedFlavor.versionCode = 3000 + defaultConfig.versionCode } else if (variant.buildType.name.equals(''debugMips'')) { variant.mergedFlavor.versionCode = 5000 + defaultConfig.versionCode } else if (variant.buildType.name.equals(''releaseMips'')) { variant.mergedFlavor.versionCode = 5000 + defaultConfig.versionCode } else if (variant.buildType.name.equals(''debugMips64'')) { variant.mergedFlavor.versionCode = 6000 + defaultConfig.versionCode } else if (variant.buildType.name.equals(''releaseMips64'')) { variant.mergedFlavor.versionCode = 6000 + defaultConfig.versionCode } else if (variant.buildType.name.equals(''debugX86'')) { variant.mergedFlavor.versionCode = 8000 + defaultConfig.versionCode } else if (variant.buildType.name.equals(''releaseX86'')) { variant.mergedFlavor.versionCode = 8000 + defaultConfig.versionCode } else if (variant.buildType.name.equals(''debugX86_64'')) { variant.mergedFlavor.versionCode = 9000 + defaultConfig.versionCode } else if (variant.buildType.name.equals(''releaseX86_64'')) { variant.mergedFlavor.versionCode = 9000 + defaultConfig.versionCode } }

Ahora todo lo que tiene que hacer es establecer el valor de versionCode en su objeto DefaultConfig, como lo haría normalmente, y esto lo agrega al final de la cadena de versión específica de la arquitectura, en función del tipo de compilación. La cadena de versión permanece igual para todas las compilaciones pero varía el código para proporcionar un orden de precedencia desde ARM hasta X86_64. Es un poco hackoso o está codificado, pero hace el trabajo bien. Tenga en cuenta que esto le proporciona hasta 999 versiones, por lo que si necesita más, multiplique los números de arriba por 10, sin estar seguro de cuál es el valor máximo que puede poner para el código de la versión.

En mi caso, tenemos un sistema de compilación bastante complejo. Construimos CPython para 9 arquitecturas, 3 de las cuales son Android, luego construimos varias de nuestras propias bibliotecas y las vinculamos todas en una única biblioteca para cada arquitectura. Utilizamos las herramientas de compilación de línea de comando ndk, automake y python para compilar todo, en lugar de archivos Android.mk. Las bibliotecas finales se vinculan en un archivo JNI de interfaz cpp (llamado myNativeCPPModule). Un clic del botón, y todo está construido a la vez, muy agradable Android Studio.


Como se comentó anteriormente, agregar ndk.dir = en local.properties ayuda. Curiosamente, encontré que local.properties anula cualquier valor establecido para la variable de entorno ANDROID_NDK_HOME, incluso si no tiene ndk.dir configurado en local.properties . (al menos con el plugin android de gradle v 0.7.3).

Esto es confuso ya que Android Studio puede sobreescribir local.properties, y no parece proporcionar una forma de configurar ndk.dir :(


El estudio de Android sugiere incluir el camino a ndk en local.properties


Encontré la respuesta. Incluir ndk.dir=path/to/ndk en el archivo local.properties hizo el truco.

Actualización: en las últimas versiones de Android Studio, puede establecer el valor directamente en la estructura del proyecto> ubicación del SDK.


Pasé mucho tiempo configurando ndk en build.gradle. Tengo un buen blog para resolver mi problema.


también puede establecer la variable de entorno ANDROID_NDK_HOME