【问题标题】:JNI and Gradle in Android StudioAndroid Studio 中的 JNI 和 Gradle
【发布时间】:2014-02-01 12:36:25
【问题描述】:

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

【问题讨论】:

标签: android java-native-interface gradle android-studio android-ndk-r7


【解决方案1】:

Gradle Build Tools 2.2.0+ - NDK 最接近被称为“魔术”

为了避免实验性的,坦率地说厌倦了 NDK 和它的所有hackery,我很高兴 Gradle Build Tools 的 2.2.x 出来了,现在它可以正常工作了。关键是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's page on adding native code

正确设置后,您可以./gradlew installDebug 并离开。您还需要注意,由于 gcc 现在在 Android NDK 中已弃用,因此 NDK 正在转向 clang。

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 answer

您的 gradle 版本和常规设置是否正确非常重要。如果您有一个较旧的项目,我强烈建议您使用最新的 Android Studio 创建一个新项目,看看 Google 认为标准项目是什么。另外,请使用gradlew。这可以保护开发人员免受 gradle 版本不匹配的影响。最后,gradle插件必须配置正确。

你问最新版本的 gradle 插件是什么? Check the tools page 并相应地编辑版本。

最终产品 - /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 之后获取文件夹的正确方法。 Migrating Gradle Projects to version 1.0.0。如果您使用的是实验版本或旧版本的插件,您的里程可能会有所不同。

【讨论】:

  • 我必须做的一个调整:在 android 块之外定义任务。否则 gradle 抱怨。
  • 您可以使用def ndkDir = android.plugin.ndkFolder 作为获取android插件引用的更简单方法。
  • 我看到与@UtkarshSinha 相同的问题或类似问题。任务带有灰色下划线,并显示以下消息:“无法推断参数类型”。 Gradle 是最新的(2.2.1),我相信问题出在其他地方,因为在 sourceSets.main 中,符号 jni 和 jniLibs 带有“无法解析符号”消息下划线。当我将任务移到 Android 块之外时,不会显示任何错误,但我认为这不正确。
  • 我必须添加 def ndkDir = plugins.getPlugin('com.android.application').sdkHandler.ndkFolder 才能工作
  • 你,先生,应该得到一块饼干!
【解决方案2】:

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 中。

【讨论】:

  • 好答案!你让我今天一整天都感觉很好! =)另一种解决方案,我只是还没有找到。
  • 我自己也遇到过同样的问题。我通过在 ./app/src/main/jni 目录中添加一个空的 .c 文件来解决它(我将文件命名为“utils.c”,但你可以随意调用它......)。从那以后,一切正常。我没有对 Gradle 设置文件进行任何更改。
  • 我应该把它放在哪个父母之下?我尝试了几个地方,我得到“无法解析符号:jni”。
  • 你应该把它放在android { }
  • 您可以从我的文章中获得更多详细信息:ph0b.com/android-studio-gradle-and-ndk-integration
【解决方案3】:

在我的情况下,我在 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'
}

【讨论】:

  • 文件扩展名!一定喜欢 Windows。
  • src/main/libs 里面是什么?如果它是另一个子目录,例如 armeabi
  • 我可能添加的 .so 文件列表,在我过去的项目中,它是用于 android 的 opencv 库。
  • 可以通过环境变量NDK_ROOT_DIRCTORY找到NDK目录。如果 Android Studio 忽略了该值,那么您应该提交错误报告。
【解决方案4】:

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

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

【讨论】:

  • 您能否详细说明“虽然,我们不得不等到 2.2.3 才能获得 Application.mk 支持”?是 Preview3,还是..?
  • @SebastianRoth :是的,它是预览版 3。截至 2015 年 8 月 8 日,Android Studio 2.2 Beta 已经发布,它提供了对外部原生构建的支持。
【解决方案5】:

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

sourceSets.main.jni.srcDirs = []

build.gradle 中的android 标记内。

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

【讨论】:

  • 我不明白,因为@CameronLowellPalmer 指定了这个。或者 gradle 是否以与 sourceSets.main.jni.srcDirs = [] 不同的方式解释 sourceSets.main { jni.srcDirs = [] }?我相信您的问题出在其他地方,而您不小心修复了它。
  • @OliverHausler 这两个语句是等价的。
【解决方案6】:

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

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

【讨论】:

  • 可以通过环境变量NDK_ROOT_DIRCTORY找到NDK目录。如果 Android Studio 忽略了该值,那么您应该提交错误报告。
猜你喜欢
  • 2013-05-16
  • 1970-01-01
  • 1970-01-01
  • 2014-01-22
  • 2017-02-24
  • 1970-01-01
  • 1970-01-01
  • 2013-10-11
  • 1970-01-01
相关资源
最近更新 更多