Android Studio中的JNI和Gradle

时间:2014-01-13 16:51:05

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

我正在尝试将原生代码添加到我的应用中。我拥有../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 个答案:

答案 0 :(得分:116)

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然后离开。您还需要注意NDK正在转向clang,因为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'
}

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子目录。这是一个很大的问题。

ndkDirectory

这已多次出现,但android.ndkDirectory是在1.1之后获取文件夹的正确方法。 Migrating Gradle Projects to version 1.0.0。如果你使用插件的实验版或古代版,你的里程可能会有所不同。

答案 1 :(得分:72)

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 /.

中的lib 不过,你有什么问题为x86编译吗?我发现你没有把它包含在你的APP_ABI中。

答案 2 :(得分:7)

在我的情况下,我在Windows上并按照上面的Cameron的回答只有在使用ndk-build的全名 ndk-build.cmd 时才有效。我必须清理并重建项目,然后重新启动模拟器才能使应用程序正常工作(实际上我是从NDK将示例HelloJni导入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'
}

答案 3 :(得分:5)

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

  

sourceSets.main.jni.srcDirs = []

android内的build.gradle标记内的

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

答案 4 :(得分: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"
    }
  } 
}

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

NB: externalNativeBuilddefaultConfig的额外嵌套是Android Studio 2.2 Preview 5(2016年7月8日)引入的重大变化。请参阅上面链接中的发行说明。

答案 5 :(得分:1)

在模块build.gradle中,在任务字段中,除非我使用:

,否则会出现错误
def ndkDir = android.plugin.ndkFolder

我看到人们使用

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

[2015-06-26 20:37:36 +0000] [11] [ERROR] Exception in worker process:
Traceback (most recent call last):
  File "/app/.heroku/python/lib/python2.7/site-packages/gunicorn/arbiter.py", line 507, in spawn_worker
    worker.init_process()
  File "/app/.heroku/python/lib/python2.7/site-packages/gunicorn/workers/base.py", line 118, in init_process
    self.wsgi = self.app.wsgi()
    self.callable = self.load()
  File "/app/.heroku/python/lib/python2.7/site-packages/gunicorn/app/base.py", line 67, in wsgi
  File "/app/.heroku/python/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py", line 65, in load
    return self.load_wsgiapp()
  File "/app/.heroku/python/lib/python2.7/site-packages/gunicorn/app/wsgiapp.py", line 52, in load_wsgiapp
    return util.import_app(self.app_uri)
  File "/app/.heroku/python/lib/python2.7/site-packages/gunicorn/util.py", line 355, in import_app
    __import__(module)
  File "/app/prompt/wsgi.py", line 4, in <module>
    from whitenoise.django import DjangoWhiteNoise
  File "/app/.heroku/python/lib/python2.7/site-packages/whitenoise/django.py", line 14, in <module>
    from django.contrib.staticfiles.storage import staticfiles_storage
  File "/app/.heroku/python/lib/python2.7/site-packages/django/contrib/staticfiles/storage.py", line 12, in <module>
    from django.core.cache import (
  File "/app/.heroku/python/lib/python2.7/site-packages/django/core/cache/__init__.py", line 34, in <module>
    if DEFAULT_CACHE_ALIAS not in settings.CACHES:
  File "/app/.heroku/python/lib/python2.7/site-packages/django/conf/__init__.py", line 48, in __getattr__
  File "/app/.heroku/python/lib/python2.7/site-packages/django/conf/__init__.py", line 42, in _setup
    self._setup(name)
    % (desc, ENVIRONMENT_VARIABLE))
ImproperlyConfigured: Requested setting CACHES, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.
    worker.init_process()

但直到我将其更改为我实际导入的插件时,这些都没有工作。