76

我正在尝试将本机代码添加到我的应用程序中。我拥有一切,../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.

我需要做什么?

安卓.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)

应用程序.mk:

APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi armeabi-v7a
APP_PLATFORM := android-8
4

6 回答 6

124

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

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

正确设置后,您就可以./gradlew installDebug出发了。您还需要注意 NDK 正在转向 clang,因为 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 - 对于那些有问题的人

还要检查这个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()
    }
}

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

ndk目录

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

于 2014-11-01T21:18:17.980 回答
74

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

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

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

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

顺便说一句,您在为 x86 编译时有任何问题吗?我看到你没有将它包含在你的 APP_ABI 中。

于 2014-01-14T10:40:19.580 回答
8

就我而言,我在 Windows 上,并且只有在您使用 ndk-build 的全名(即ndk-build.cmd )时,才可以按照上面 Cameron 的答案进行操作。我必须清理并重建项目,然后在让应用程序运行之前重新启动模拟器(实际上我将示例 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'
}
于 2015-03-09T14:59:59.977 回答
7

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

注意:externalNativeBuild inside的额外嵌套defaultConfig是 Android Studio 2.2 Preview 5(2016 年 7 月 8 日)引入的一项重大更改。请参阅上述链接中的发行说明。

于 2016-06-16T15:31:43.817 回答
6

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

sourceSets.main.jni.srcDirs = []

android标签内build.gradle

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

于 2014-02-26T02:39:38.757 回答
2

在模块 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()

但在我将其更改为我实际导入的插件之前,这些都不起作用。

于 2015-06-26T22:10:07.783 回答