web-dev-qa-db-fra.com

JNI et Gradle dans Android Studio

J'essaie d'ajouter 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 (je ne sais pas quoi d'autre est vraiment nécessaire, donc si j'ai oublié quelque chose, faites-le-moi savoir). Lorsque j'essaie de construire, j'obtiens cette erreur:

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.

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
74
fredley

Gradle Build Tools 2.2.0+ - Le plus proche que le NDK ait jamais été appelé "magie"

En essayant d'éviter les expérimentations et franchement marre du NDK et de tout son hackery, je suis heureux que la version 2.2.x de Gradle Build Tools soit sortie et qu'elle fonctionne maintenant. La clé est la externalNativeBuild et pointe ndkBuild argument de chemin sur un Android.mk ou change ndkBuild en cmake et pointe l'argument de chemin à un CMakeLists.txt construire un script.

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'
        //}
    }
}

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

Une fois que cela est configuré correctement, vous pouvez ./gradlew installDebug et vous pouvez partir. Vous devez également savoir que le NDK passe à clang, car gcc est maintenant obsolète dans le Android NDK.

Intégration d'Android Studio Clean et Build - DEPRECATED

Les autres réponses indiquent la manière correcte d’empêcher la création automatique de fichiers Android.mk, mais ne parviennent pas à intégrer l’intégration avec Android Studio. J'ai ajouté la possibilité de nettoyer et de compiler à partir des sources sans avoir à passer en ligne de commande. Votre fichier local.properties devra avoir 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'
}

Le répertoire src/main/jni suppose une présentation standard du projet. Ce doit être le rapport entre cet emplacement de fichier build.gradle et le répertoire jni.

Gradle - pour ceux qui ont des problèmes

Vérifiez également ceci réponse de débordement de pile .

Il est vraiment important que votre version et configuration générale soient correctes. Si vous avez un projet plus ancien, je vous recommande vivement de créer un nouveau projet avec le dernier Android Studio et de voir ce que Google considère comme le projet standard. Utilisez également gradlew. Cela protège le développeur d'une incompatibilité de version. Enfin, le plugin Gradle doit être configuré correctement.

Et vous demandez quelle est la dernière version du plugin Gradle? Consultez la page des outils et éditez 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 gradle wrapper génère le fichier gradlew et le sous-répertoire gradle/wrapper. Ceci est un gros gotcha.

ndkDirectory

Cela est arrivé un certain nombre de fois, mais Android.ndkDirectory est le moyen correct d’obtenir le dossier après la 1.1. Migration de projets Gradle vers la version 1.0. . Si vous utilisez une version expérimentale ou ancienne du plugin, votre kilométrage peut varier.

118

gradle prend en charge 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 r9 sous OSX, r9c sous Windows, vous devez donc mettre à niveau votre NDK vers r9 +.

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

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

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

d'ailleurs, vous avez un problème de compilation pour x86? Je vois que vous ne l'avez pas inclus dans votre APP_ABI.

72
ph0b

Dans mon cas, je suis sous Windows et je ne fais que suivre la réponse de Cameron ci-dessus si vous utilisez le nom complet du 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). Cependant, assurez-vous que le chemin d'accès à NDK ne contient pas d'espace.

Enfin, mon build.gradle est complet énuméré ci-dessous:

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'
}
7
Brian Ng

Mon problème sur OSX était la version suivante. Gradle ignorait mon Android.mk. Donc, afin de remplacer cette option et d’utiliser plutôt ma marque, j’ai saisi cette ligne:

sourceSets.main.jni.srcDirs = []

à l'intérieur de la balise Android dans build.gradle.

J'ai perdu beaucoup de temps à ce sujet!

5
Paschalis

Android Studio 2.2 est sorti avec la possibilité d'utiliser ndk-build et cMake. Cependant, nous avons dû attendre jusqu’à la 2.2.3 pour obtenir le support Application.mk. J'ai essayé, ça marche ... mais mes variables ne sont pas affichées dans le débogueur. Je peux quand même les interroger via la ligne de commande.

Vous devez faire quelque chose comme ça:

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 à l'intérieur de defaultConfig était un changement radical introduit avec Android Studio 2.2. Extrait 5 (8 juillet 2016). Voir les notes de version sur le lien ci-dessus.

5
Ronnie

Dans le module build.gradle, dans le champ de tâche, j'obtiens une erreur sauf si j'utilise:

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

Je vois des gens qui utilisent

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 plugin que j'importais réellement.

1
videogameboy76