Android Studio中的JNI和Gradle

fre*_*ley 74 java-native-interface android gradle android-ndk-r7 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.
Run Code Online (Sandbox Code Playgroud)

我需要做什么?

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)
Run Code Online (Sandbox Code Playgroud)

Application.mk:

APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi armeabi-v7a
APP_PLATFORM := android-8
Run Code Online (Sandbox Code Playgroud)

Cam*_*mer 118

Gradle Build Tools 2.2.0+ - 最接近的NDK被称为'魔术'

在试图避免实验性和坦率地厌倦了NDK及其所有hackery时,我很高兴Gradle Build Tools的2.2.x出现了,现在它正常工作.关键是externalNativeBuild,指着ndkBuild路径参数在Android.mk或更改ndkBuildcmake并在点的路径参数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'
        //}
    }
}
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请查看Google有关添加本机代码的页面.

在正确设置之后,你可以./gradlew installDebug离开你.您还需要注意NDK正在变为铿锵声,因为现在在Android NDK中不推荐使用gcc.

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'
}
Run Code Online (Sandbox Code Playgroud)

src/main/jni目录假定项目的标准布局.它应该是从此build.gradle文件位置到jni目录的相对位置.

Gradle - 对于有问题的人

同时检查此Stack Overflow应答.

您的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()
    }
}
Run Code Online (Sandbox Code Playgroud)

确保gradle wrapper生成gradlew文件和gradle/wrapper子目录.这是一个很大的问题.

ndkDirectory

这已经出现了很多次,但是android.ndkDirectory在1.1之后获取文件夹的正确方法.将Gradle项目迁移到版本1.0.0.如果您使用插件的实验版或古代版,您的里程可能会有所不同.

  • 我不得不添加`def ndkDir = plugins.getPlugin('com.android.application').sdkHandler.ndkFolder`让它工作 (3认同)
  • 我必须做的一个调整:在android块之外定义任务.否则gradle抱怨. (2认同)
  • 你,先生,值得一个饼干! (2认同)

ph0*_*h0b 72

gradle通过生成另一个带有源的绝对路径的Android.mk文件来支持ndk编译.自从OSX上的r9,Windows上的r9c以来,NDK支持绝对路径,因此您需要将NDK升级到r9 +.

你可能遇到其他麻烦,因为gradle的NDK支持是初步的.如果是这样,您可以通过设置来停用gradle中的ndk编译:

sourceSets.main {
    jni.srcDirs = []
    jniLibs.srcDir 'src/main/libs'
}
Run Code Online (Sandbox Code Playgroud)

能够自己调用ndk-build并从libs /集成libs.

顺便说一下,你有什么问题为x86编译?我发现你没有将它包含在你的APP_ABI中.

  • 我应该把这个放在哪个家长?我尝试了几个地方,我得到"无法解决符号:jni". (4认同)
  • 好答案!你让我今天一整天都感觉很好!=)另一个解决方案,我还没有找到. (2认同)

Bri*_* Ng 7

在我的情况下,我在Windows上并且遵循Cameron的回答只有在使用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'
}
Run Code Online (Sandbox Code Playgroud)


Pas*_*lis 5

我在OSX上的问题是gradle版本.Gradle忽略了我的Android.mk.所以,为了覆盖这个选项,改为使用我的make,我输入了这一行:

sourceSets.main.jni.srcDirs = []

里面的android标签build.gradle.

我浪费了很多时间在这上面!


小智 5

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"
    }
  } 
}
Run Code Online (Sandbox Code Playgroud)

请参阅http://tools.android.com/tech-docs/external-c-builds

注意:externalNativeBuild内部的额外嵌套defaultConfig是Android Studio 2.2 Preview 5(2016年7月8日)引入的一个重大变化.请参阅上面链接中的发行说明.