JNI и Gradle в Android Studio

Я пытаюсь добавить собственный код в свое приложение. У меня все есть ../main/jni как это было в моем проекте Eclipse. я добавил ndk.dir=... к моему local.properties, Я еще ничего не делал (я не уверен, что еще требуется, поэтому, если я что-то пропустил, дайте мне знать). Когда я пытаюсь собрать, я получаю эту ошибку:

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.

Что мне нужно сделать?

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

6 ответов

Решение

Gradle Build Tools 2.2.0+ - самый близкий NDK когда-либо назывался "магическим"

Пытаясь избежать экспериментального и откровенно сытого по горло NDK и всей его хакерской атакой, я счастлив, что вышел 2.2.x из Gradle Build Tools, и теперь он просто работает. Ключ является externalNativeBuild и указывая ndkBuild аргумент пути в Android.mk или изменить ndkBuild в cmake и указать аргумент пути на 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'
        //}
    }
}

Для более подробной информации посетите страницу Google по добавлению нативного кода.

После правильной настройки вы можете ./gradlew installDebug и уходи. Вам также нужно знать, что NDK переходит на лязг, поскольку gcc теперь не поддерживается в Android NDK.

Android Studio Интеграция чистоты и сборки - УСТАРЕЛО

Другие ответы указывают на правильный способ предотвращения автоматического создания Android.mk файлы, но они не проходят дополнительный этап интеграции с Android Studio. Я добавил возможность на самом деле чистить и строить из исходного кода без необходимости переходить в командную строку. Ваш local.properties файл нужно будет иметь 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'
}

src/main/jni Каталог предполагает стандартную компоновку проекта. Это должен быть родственник из этого build.gradle расположение файла в jni каталог.

Gradle - для тех, у кого проблемы

Также проверьте этот ответ переполнения стека.

Очень важно, чтобы ваша версия Gradle и общие настройки были правильными. Если у вас есть старый проект, я настоятельно рекомендую создать новый с последней версией Android Studio и посмотреть, что Google считает стандартным проектом. Также используйте gradlew, Это защищает разработчика от несоответствия версии Gradle. Наконец, плагин Gradle должен быть настроен правильно.

И вы спрашиваете, какая последняя версия плагина gradle? Проверьте страницу инструментов и отредактируйте версию соответственно.

Конечный продукт - /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()
    }
}

Удостовериться gradle wrapper генерирует gradlew файл и gradle/wrapper подкаталог. Это большая ошибка.

ndkDirectory

Это подходило несколько раз, но android.ndkDirectory правильный способ получить папку после 1.1. Миграция Gradle проектов до версии 1.0.0. Если вы используете экспериментальную или древнюю версию плагина, ваш пробег может отличаться.

gradle поддерживает компиляцию ndk, генерируя другой файл Android.mk с абсолютными путями к вашим источникам. NDK поддерживает абсолютные пути, начиная с r9 в OSX, r9c в Windows, поэтому вам нужно обновить NDK до r9+.

Вы можете столкнуться с другими проблемами, так как поддержка NDK gradle является предварительной. Если это так, вы можете отключить компиляцию ndk из Gradle, установив:

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

чтобы иметь возможность вызывать ndk-build и интегрировать библиотеки из libs/.

Кстати, у вас есть какие-либо проблемы с компиляцией для x86? Я вижу, вы не включили его в свой APP_ABI.

В моем случае я в Windows, и следование ответу Камерона выше работает только в том случае, если вы используете полное имя ndk-build, которое называется ndk-build.cmd. Я должен очистить и перестроить проект, а затем перезапустить эмулятор, прежде чем заставить приложение работать (на самом деле я импортировал образец HelloJni из NDK в Android Studio). Однако убедитесь, что путь к NDK не содержит места.

Наконец, мой build.gradle полностью перечислен ниже:

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

В Android Studio 2.2 появилась возможность использовать ndk-build и cMake. Однако нам пришлось подождать до 2.2.3 для поддержки Application.mk. Я пробовал, это работает... хотя, мои переменные не отображаются в отладчике. Я все еще могу запросить их через командную строку, хотя.

Вам нужно сделать что-то вроде этого:

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

Смотрите http://tools.android.com/tech-docs/external-c-builds

NB: дополнительная вложенность externalNativeBuild внутри defaultConfig было принципиально новое изменение в Android Studio 2.2 Preview 5 (8 июля 2016 г.). Смотрите примечания к выпуску по ссылке выше.

Моя проблема на OSX это была версия gradle. Градл игнорировал мой Android.mk. Итак, чтобы переопределить эту опцию и использовать вместо этого мой make, я ввел эту строку:

sourceSets.main.jni.srcDirs = []

внутри android отметить в build.gradle,

Я потратил много времени на это!

В модуле build.gradle в поле задачи я получаю ошибку, если не использую:

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

Я вижу людей, использующих

def ndkDir = android.plugin.ndkFolder

а также

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

но ни один из них не работал, пока я не изменил его на плагин, который я фактически импортировал.

Другие вопросы по тегам