r17b - JNI y Gradle en Android Studio
jni java android (6)
Gradle Build Tools 2.2.0+ - Lo más cerca que al NDK se lo ha llamado ''magia''
Al tratar de evitar experimental y francamente harto del NDK y de todos sus hackers, me complace que salió 2.2.x de Gradle Build Tools y ahora simplemente funciona. La clave es el argumento ndkBuild
ruta ndkBuild
en un Android.mk
o cambiar ndkBuild
por cmake
y apuntar el argumento de ruta en un CMakeLists.txt
construcción CMakeLists.txt
.
android {
compileSdkVersion 19
buildToolsVersion "25.0.2"
defaultConfig {
minSdkVersion 19
targetSdkVersion 19
ndk {
abiFilters ''armeabi'', ''armeabi-v7a'', ''x86''
}
externalNativeBuild {
cmake {
cppFlags ''-std=c++11''
arguments ''-DANDROID_TOOLCHAIN=clang'',
''-DANDROID_PLATFORM=android-19'',
''-DANDROID_STL=gnustl_static'',
''-DANDROID_ARM_NEON=TRUE'',
''-DANDROID_CPP_FEATURES=exceptions rtti''
}
}
}
externalNativeBuild {
cmake {
path ''src/main/jni/CMakeLists.txt''
}
//ndkBuild {
// path ''src/main/jni/Android.mk''
//}
}
}
Para obtener más detalles, consulte la página de Google sobre cómo agregar código nativo .
Después de configurar esto correctamente, puede ./gradlew installDebug
y listo. También deberás ser consciente de que el NDK se está moviendo a clang ya que gcc ahora está obsoleto en el NDK de Android.
Android Studio Clean and Build Integration: DEPRECATED
Las otras respuestas señalan la forma correcta de evitar la creación automática de archivos Android.mk
, pero no logran el paso adicional de integrarse mejor con Android Studio. He agregado la capacidad de limpiar y compilar desde la fuente sin necesidad de ir a la línea de comandos. Su archivo local.properties
necesitará tener ndk.dir=/path/to/ndk
apply plugin: ''com.android.application''
android {
compileSdkVersion 14
buildToolsVersion "20.0.0"
defaultConfig {
applicationId "com.example.application"
minSdkVersion 14
targetSdkVersion 14
ndk {
moduleName "YourModuleName"
}
}
sourceSets.main {
jni.srcDirs = [] // This prevents the auto generation of Android.mk
jniLibs.srcDir ''src/main/libs'' // This is not necessary unless you have precompiled libraries in your project.
}
task buildNative(type: Exec, description: ''Compile JNI source via NDK'') {
def ndkDir = android.ndkDirectory
commandLine "$ndkDir/ndk-build",
''-C'', file(''src/main/jni'').absolutePath, // Change src/main/jni the relative path to your jni source
''-j'', Runtime.runtime.availableProcessors(),
''all'',
''NDK_DEBUG=1''
}
task cleanNative(type: Exec, description: ''Clean JNI object files'') {
def ndkDir = android.ndkDirectory
commandLine "$ndkDir/ndk-build",
''-C'', file(''src/main/jni'').absolutePath, // Change src/main/jni the relative path to your jni source
''clean''
}
clean.dependsOn ''cleanNative''
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn buildNative
}
}
dependencies {
compile ''com.android.support:support-v4:20.0.0''
}
El directorio src/main/jni
supone una disposición estándar del proyecto. Debe ser el pariente de esta ubicación del archivo build.gradle
en el directorio jni
.
Gradle - para aquellos que tienen problemas
También verifique esta respuesta de desbordamiento de pila .
Es realmente importante que la versión gradle y la configuración general sean correctas. Si tienes un proyecto anterior, recomiendo crear uno nuevo con el último Android Studio y ver lo que Google considera el proyecto estándar. Además, usa gradlew
. Esto protege al desarrollador de una discrepancia en la versión de Gradle. Finalmente, el plugin de gradle debe estar configurado correctamente.
¿Y preguntas cuál es la última versión del plugin Gradle? Verifique la página de herramientas y edite la versión en consecuencia.
Producto final - /build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
// Running ''gradle wrapper'' will generate gradlew - Getting gradle wrapper working and using it will save you a lot of pain.
task wrapper(type: Wrapper) {
gradleVersion = ''2.2''
}
// Look Google doesn''t use Maven Central, they use jcenter now.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath ''com.android.tools.build:gradle:1.2.0''
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
Asegúrese de que gradle wrapper
genera el archivo gradle/wrapper
subdirectorio gradle/wrapper
. Este es un gran problema.
ndkDirectory
Esto ha aparecido varias veces, pero android.ndkDirectory
es la forma correcta de obtener la carpeta después de 1.1. Migración de proyectos de Gradle a la versión 1.0.0 . Si está utilizando una versión experimental o antigua del complemento, su millaje puede variar.
Estoy tratando de agregar código nativo a mi aplicación. Tengo todo en ../main/jni
como estaba en mi proyecto de Eclipse. He agregado ndk.dir=...
a mis local.properties
. Todavía no he hecho nada más (no estoy seguro de qué más se necesita realmente, así que si me he perdido algo, házmelo saber). Cuando intento y construyo obtengo este error:
Execution failed for task '':app:compileDebugNdk''.
> com.android.ide.common.internal.LoggedErrorException: Failed to run command:
/Users/me/android-ndk-r8e/ndk-build NDK_PROJECT_PATH=null
APP_BUILD_SCRIPT=/Users/me/Project/app/build/ndk/debug/Android.mk APP_PLATFORM=android-19
NDK_OUT=/Users/me/Project/app/build/ndk/debug/obj
NDK_LIBS_OUT=/Users/me/Project/app/build/ndk/debug/lib APP_ABI=all
Error Code:
2
Output:
make: *** No rule to make target `/Users/me/Project/webapp/build/ndk/debug//Users/me/Project/app/src/main/jni/jni_part.cpp'',
needed by `/Users/me/Project/app/build/ndk/debug/obj/local/armeabi-v7a/objs/webapp//Users/me/Project/app/src/main/jni/jni_part.o''.
Stop.
¿Que necesito hacer?
Android.mk:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# OpenCV
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
include .../OpenCV-2.4.5-android-sdk/sdk/native/jni/OpenCV.mk
LOCAL_MODULE := native_part
LOCAL_SRC_FILES := jni_part.cpp
LOCAL_LDLIBS += -llog -ldl
include $(BUILD_SHARED_LIBRARY)
Application.mk:
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi armeabi-v7a
APP_PLATFORM := android-8
Android Studio 2.2 salió con la capacidad de usar ndk-build y cMake. Sin embargo, tuvimos que esperar hasta 2.2.3 para el soporte de Application.mk. Lo intenté, funciona ... sin embargo, mis variables no aparecen en el depurador. Todavía puedo consultarlos a través de la línea de comandos.
Debes hacer algo como esto:
externalNativeBuild{
ndkBuild{
path "Android.mk"
}
}
defaultConfig {
externalNativeBuild{
ndkBuild {
arguments "NDK_APPLICATION_MK:=Application.mk"
cFlags "-DTEST_C_FLAG1" "-DTEST_C_FLAG2"
cppFlags "-DTEST_CPP_FLAG2" "-DTEST_CPP_FLAG2"
abiFilters "armeabi-v7a", "armeabi"
}
}
}
Ver http://tools.android.com/tech-docs/external-c-builds
NB: la anidación adicional de externalNativeBuild
dentro de defaultConfig
fue un cambio radical introducido con Android Studio 2.2 Preview 5 (8 de julio de 2016). Vea las notas de la versión en el enlace de arriba.
En el módulo build.gradle, en el campo de la tarea, aparece un error a menos que use:
def ndkDir = plugins.getPlugin(''com.android.application'').sdkHandler.getNdkFolder()
Veo gente usando
def ndkDir = android.plugin.ndkFolder
y
def ndkDir = plugins.getPlugin(''com.android.library'').sdkHandler.getNdkFolder()
pero ninguno de esos funcionó hasta que lo cambié al plugin que en realidad estaba importando.
En mi caso, estoy en Windows y seguir la respuesta de Cameron de arriba solo funciona si usa el nombre completo de ndk-build que es ndk-build.cmd . Debo limpiar y reconstruir el proyecto , luego reiniciar el emulador antes de hacer funcionar la aplicación (de hecho, importé la muestra HelloJni de NDK a Android Studio). Sin embargo, asegúrese de que la ruta a NDK no contenga espacio .
Finalmente, mi build.gradle está completo como se muestra a continuación:
apply plugin: ''com.android.application''
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
applicationId "com.example.hellojni"
minSdkVersion 4
targetSdkVersion 4
ndk {
moduleName "hello-jni"
}
testApplicationId "com.example.hellojni.tests"
testInstrumentationRunner "android.test.InstrumentationTestRunner"
}
sourceSets.main {
jni.srcDirs = [] // This prevents the auto generation of Android.mk
// sourceSets.main.jni.srcDirs = []
jniLibs.srcDir ''src/main/libs'' // This is not necessary unless you have precompiled libraries in your project.
}
task buildNative(type: Exec, description: ''Compile JNI source via NDK'') {
def ndkDir = android.plugin.ndkFolder
commandLine "$ndkDir/ndk-build.cmd",
''-C'', file(''src/main/jni'').absolutePath, // Change src/main/jni the relative path to your jni source
''-j'', Runtime.runtime.availableProcessors(),
''all'',
''NDK_DEBUG=1''
}
task cleanNative(type: Exec, description: ''Clean JNI object files'') {
def ndkDir = android.plugin.ndkFolder
commandLine "$ndkDir/ndk-build.cmd",
''-C'', file(''src/main/jni'').absolutePath, // Change src/main/jni the relative path to your jni source
''clean''
}
clean.dependsOn ''cleanNative''
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn buildNative
}
}
dependencies {
compile ''com.android.support:support-v4:21.0.3''
}
Mi problema en OSX fue la versión gradle. Gradle estaba ignorando mi Android.mk. Entonces, para anular esta opción, y usar mi marca, he ingresado a esta línea:
sourceSets.main.jni.srcDirs = []
dentro de la etiqueta de android
en build.gradle
.
¡He perdido mucho tiempo en esto!
gradle admite la compilación de ndk generando otro archivo Android.mk con rutas absolutas a sus fuentes. NDK admite rutas absolutas desde r9 en OSX, r9c en Windows, por lo que necesita actualizar su NDK a r9 +.
Puede encontrarse con otros problemas ya que el soporte NDK de gradle es preliminar. Si es así, puede desactivar la compilación ndk de gradle estableciendo:
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir ''src/main/libs''
}
para poder llamar a ndk-build usted mismo e integrar libs desde libs /.
Por cierto, ¿tiene algún problema compilando para x86? Veo que no lo ha incluido en su APP_ABI.