JNI et Gradle dans Android Studio

J’essaie d’append du code natif à mon application. J’ai tout dans ../main/jni comme dans mon projet Eclipse. J’ai ajouté ndk.dir=... à mon local.properties . Je n’ai encore rien fait d’autre (je ne suis pas sûr de savoir quoi d’autre est réellement nécessaire, alors si j’ai raté quelque chose, faites le moi savoir). Lorsque j’essaye de construire, j’obtiens cette erreur:

 Execution failed for task ':app:comstackDebugNdk'. > 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. 

Qu’est-ce que je dois faire?

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 

Gradle Build Tools 2.2.0+ – Le NDK étant le plus proche de la magie

En essayant d’éviter de façon expérimentale et franchement marre du NDK et de tous ses pirates, je suis heureux que le 2.2.x des outils de compilation de Gradle soit sorti et que ça fonctionne maintenant. La clé est le ndkBuild externalNativeBuild et le chemin ndkBuild sur un ndkBuild Android.mk ou changez ndkBuild en cmake et pointez l’argument path sur un CMakeLists.txt génération CMakeLists.txt .

 android { comstackSdkVersion 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' //} } } 

Pour plus de détails, consultez la page de Google sur l’ajout de code natif .

Une fois que cela est configuré correctement, vous pouvez ./gradlew installDebug et vous partez. Vous devrez également savoir que le NDK est en train de basculer puisque gcc est maintenant obsolète dans le NDK Android.

Android Studio Clean et Build Integration – DEPRECATED

Les autres réponses indiquent la manière correcte d’empêcher la création automatique de fichiers Android.mk , mais elles ne permettent pas de mieux s’intégrer à Android Studio. J’ai ajouté la possibilité de nettoyer et de construire à partir de sources sans avoir à se rendre sur la ligne de commande. Votre fichier local.properties devra avoir ndk.dir=/path/to/ndk

 apply plugin: 'com.android.application' android { comstackSdkVersion 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 precomstackd libraries in your project. } task buildNative(type: Exec, description: 'Comstack 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(JavaComstack) { comstackTask -> comstackTask.dependsOn buildNative } } dependencies { comstack 'com.android.support:support-v4:20.0.0' } 

Le répertoire src/main/jni suppose une présentation standard du projet. Il doit s’agir du fichier depuis cet build.gradle fichier build.gradle vers le répertoire jni .

Gradle – pour ceux qui ont des problèmes

Vérifiez également cette réponse Stack Overflow .

Il est très important que votre version de gradle et la configuration générale soient correctes. Si vous avez un projet plus ancien, je vous recommande vivement d’en créer un avec le dernier Android Studio et de voir ce que Google considère comme le projet standard. Aussi, utilisez gradlew . Cela protège le développeur d’une incompatibilité de version progressive. Enfin, le plugin gradle doit être configuré correctement.

Et vous demandez quelle est la dernière version du plug-in Gradle? Vérifiez la page des outils et modifiez la version en conséquence.

Produit 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() } } 

Assurez-vous que le gradle wrapper génère le fichier gradle/wrapper sous-répertoire gradle/wrapper . C’est un gros truc.

ndkDirectory

Cela s’est produit un certain nombre de fois, mais android.ndkDirectory est la manière correcte d’obtenir le dossier après 1.1. Migration de projets Gradle vers la version 1.0.0 . Si vous utilisez une version expérimentale ou ancienne du plug-in, votre kilométrage peut varier.

gradle supporte la compilation ndk en générant un autre fichier Android.mk avec des chemins absolus vers vos sources. NDK prend en charge les chemins absolus depuis la version 9 sous OSX, r9c sous Windows. Vous devez donc mettre à niveau votre NDK à r9 +.

Vous pouvez rencontrer d’autres problèmes car le support de NDK par gradle est préliminaire. Si oui, vous pouvez désactiver la compilation ndk à partir de gradle en définissant:

 sourceSets.main { jni.srcDirs = [] jniLibs.srcDir 'src/main/libs' } 

pour pouvoir appeler ndk-build vous-même et intégrer les libs de libs /.

btw, vous avez des problèmes à comstackr pour x86? Je vois que vous ne l’avez pas inclus dans votre APP_ABI.

Dans mon cas, je suis sous Windows et suivre la réponse de Cameron ci-dessus ne fonctionne que si vous utilisez le nom complet de ndk-build qui est ndk-build.cmd . Je dois nettoyer et reconstruire le projet , puis redémarrer l’émulateur avant de faire fonctionner l’application (en fait, j’ai importé l’exemple HelloJni de NDK dans Android Studio). Toutefois, assurez-vous que le chemin d’access à NDK ne contient pas d’espace .

Enfin, ma build.gradle est listée ci-dessous:

 apply plugin: 'com.android.application' android { comstackSdkVersion 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 precomstackd libraries in your project. } task buildNative(type: Exec, description: 'Comstack 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(JavaComstack) { comstackTask -> comstackTask.dependsOn buildNative } } dependencies { comstack 'com.android.support:support-v4:21.0.3' } 

Mon problème sur OSX était la version graduelle. Gradle ignorait mon Android.mk. Donc, pour remplacer cette option et utiliser ma marque à la place, je suis entré dans cette ligne:

sourceSets.main.jni.srcDirs = []

à l’intérieur de la balise android dans build.gradle .

J’ai perdu beaucoup de temps là-dessus!

Android Studio 2.2 est sorti avec la possibilité d’utiliser ndk-build et cMake. Cependant, nous avons dû attendre jusqu’à 2.2.3 pour le support d’Application.mk. Je l’ai essayé, ça marche … cependant, mes variables n’apparaissent pas dans le débogueur. Je peux toujours les interroger via la ligne de commande.

Vous devez faire quelque chose comme ceci:

 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" } } } 

Voir http://tools.android.com/tech-docs/external-c-builds

NB: L’imbrication supplémentaire de externalNativeBuild dans defaultConfig était un changement radical introduit avec Android Studio 2.2 Preview 5 (8 juillet 2016). Voir les notes de publication sur le lien ci-dessus.

Dans le module build.gradle, dans le champ de la tâche, j’obtiens une erreur à moins que j’utilise:

 def ndkDir = plugins.getPlugin('com.android.application').sdkHandler.getNdkFolder() 

Je vois des gens utilisant

 def ndkDir = android.plugin.ndkFolder 

et

 def ndkDir = plugins.getPlugin('com.android.library').sdkHandler.getNdkFolder() 

mais aucun de ceux-ci n’a fonctionné jusqu’à ce que je l’aie changé pour le plug-in que j’importais réellement.