Android工作室,Gradle和NDK

我对这个完整的gradle和Android Studio支持非常新颖。 我设法将我的Android项目转换为使用导出选项的Gradle。

但是我正在寻找一些文档或开始如何将NDK构build集成到gradle构build过程中。

如果可能的话,我还需要某种“后”阶段,将构build二进制文件(.so文件)复制到资产目录。

我们在1.3版本中发布了第一个集成版本: http : //tools.android.com/tech-docs/android-ndk-preview

即使1.3成为最终版本,整合也将保持预览。 到目前为止,还没有ETA(截至2015年7月10日)。

更多信息在这里: http : //tools.android.com/tech-docs/android-ndk-preview

更新:与NDK支持的Android Studio现在是: http : //tools.android.com/tech-docs/android-ndk-preview

用脚本构build下面的gradle解决scheme应该是可行的:

我正在使用我的构build脚本,并添加到我的文件(似乎工作0.8+ ):这似乎相当于下面的解决scheme(但看起来更好的gradle文件):

  android { sourceSets { main { jniLibs.srcDirs = ['native-libs'] jni.srcDirs = [] //disable automatic ndk-build } } } 

不幸的是,如果目录不存在或不包含任何.so文件,则内部版本不会失败。

随着Android Studio的更新到1.0,NDK工具链支持得到了极大的改善( 注意:请阅读我的更新在这篇文章的底部看到使用新的实验Gradle插件和Android Studio 1.5 )。

Android Studio和NDK的集成已经足够好了,所以你只需要在你的模块的build.gradle中创build一个ndk {}模块,并将你的源文件设置到(module)/ src / main / jni目录中,完成了!

没有更多的ndk生成从命令行。

我已经在我的博客文章写在这里: http : //www.sureshjoshi.com/mobile/android-ndk-in-android-studio-with-swig/

要点是:

这里有两件事你需要知道。 默认情况下,如果您有要加载到Android应用程序的外部库,默认情况下会在(模块)/ src / main / jniLibs中查找它们。 你可以通过在模块的build.gradle中设置sourceSets.main.jniLibs.srcDirs来改变它。 你将需要一个子目录,每个架构的目标库(例如,x86,arm,mips,arm64-v8a等)

NDK工具链默认编译的代码将位于(module)/ src / main / jni中,与上面类似,您可以通过在模块的build.gradle中设置sourceSets.main.jni.srcDirs来更改它

并把它放到你的模块的build.gradle中:

 ndk { moduleName "SeePlusPlus" // Name of C++ module (ie libSeePlusPlus) cFlags "-std=c++11 -fexceptions" // Add provisions to allow C++11 functionality stl "gnustl_shared" // Which STL library to use: gnustl or stlport } 

这是编译C ++代码的过程,从那里你需要加载它,并创build包装 – 但从你的问题来看,你已经知道如何做,所以我不会重新哈希。

另外,我在这里放置了这个例子的Github仓库: http : //github.com/sureshjoshi/android-ndk-swig-example

更新:2015年6月14日

当Android Studio 1.3发布时,通过JetBrains CLion插件应该可以更好地支持C ++。 我目前正在假设这将允许Android Studio中的Java和C ++开发; 但是我想我们仍然需要使用Gradle NDK部分,正如我上面所说的那样。 此外,我认为仍然需要编写Java < – > C ++包装文件,除非CLion会自动执行这些文件。

更新:2016年1月5日

我已经更新了我的博客和Github回购(在开发分支)使用Android Studio 1.5和最新的实验Gradle插件(0.6.0-alpha3)。

http://www.sureshjoshi.com/mobile/android-ndk-in-android-studio-with-swig/ http://github.com/sureshjoshi/android-ndk-swig-example

现在NDK部分的Gradle构build如下所示:

 android.ndk { moduleName = "SeePlusPlus" // Name of C++ module (ie libSeePlusPlus) cppFlags.add("-std=c++11") // Add provisions to allow C++11 functionality cppFlags.add("-fexceptions") stl = "gnustl_shared" // Which STL library to use: gnustl or stlport } 

另外,非常棒的是,Android Studio为C ++自动完成 – Java生成的使用“native”关键字的包装器:

C ++自动完成的示例 -  Java包装

然而,这并不是完全乐观的…如果你使用SWIG来包装一个库来自动生成代码,然后尝试使用native关键字自动生成,它会把代码放在你的Swig _wrap中的错误位置.cxx文件…所以你需要把它移动到“extern C”块中:

C ++  -  Java包装移动到正确的位置

更新:2017年10月15日

如果我没有提到Android Studio 2.2开始通过Gradle和CMake实现对NDK工具链的本地支持(无双关语言)支持,我会感到失望。 现在,当你创build一个新项目时,只需selectC ++支持,你就可以开始。

您仍然需要生成自己的JNI图层代码,或者使用上面提到的SWIG技术,但Android项目中的C ++脚手架现在是微不足道的。

CMakeLists文件(放置C ++源文件的位置)中的更改将被Android Studio拾取,并且会自动重新编译任何关联的库。

在Google IO 2015中,Google宣布了Android Studio 1.3中的完整NDK集成。

现在已经没有预览,并且提供给所有人: https : //developer.android.com/studio/projects/add-native-code.html

老的回答:如果您的项目源中有jni目录,Gradle会自动调用ndk-build

这是工作在Android Studio 0.5.9(金丝雀build设)。

  1. 下载NDK
  2. ANDROID_NDK_HOME添加到您的环境variables,或将ndk.dir=/path/to/ndk到您的Android Studio项目的local.properties中。 这允许Android studio自动运行ndk。
  3. 下载最新的gradle示例项目来查看ndk项目的示例。 (他们在页面的底部)。 一个好的示例项目是ndkJniLib
  4. 从NDK示例项目中复制gradle.build 。 它会看起来像这样。 这个gradle.build为每个架构创build一个不同的apk。 您必须使用build variants窗格来select您想要的体系结构。 构建变体窗格

     apply plugin: 'android' dependencies { compile project(':lib') } android { compileSdkVersion 19 buildToolsVersion "19.0.2" // This actual the app version code. Giving ourselves 100,000 values [0, 99999] defaultConfig.versionCode = 123 flavorDimensions "api", "abi" productFlavors { gingerbread { flavorDimension "api" minSdkVersion 10 versionCode = 1 } icecreamSandwich { flavorDimension "api" minSdkVersion 14 versionCode = 2 } x86 { flavorDimension "abi" ndk { abiFilter "x86" } // this is the flavor part of the version code. // It must be higher than the arm one for devices supporting // both, as x86 is preferred. versionCode = 3 } arm { flavorDimension "abi" ndk { abiFilter "armeabi-v7a" } versionCode = 2 } mips { flavorDimension "abi" ndk { abiFilter "mips" } versionCode = 1 } fat { flavorDimension "abi" // fat binary, lowest version code to be // the last option versionCode = 0 } } // make per-variant version code applicationVariants.all { variant -> // get the version code of each flavor def apiVersion = variant.productFlavors.get(0).versionCode def abiVersion = variant.productFlavors.get(1).versionCode // set the composite code variant.mergedFlavor.versionCode = apiVersion * 1000000 + abiVersion * 100000 + defaultConfig.versionCode } } 

请注意,这将忽略您的Android.mk和Application.mk文件。 作为解决方法,您可以告诉gradle禁用atuomatic ndk-build调用,然后手动指定ndk源的目录。

 sourceSets.main { jniLibs.srcDir 'src/main/libs' // use the jni .so compiled from the manual ndk-build command jni.srcDirs = [] //disable automatic ndk-build call } 

另外,你可能会明确地在你的gradle构build脚本中调用ndk-build,因为你只是禁用了自动调用。

 task ndkBuild(type: Exec) { commandLine 'ndk-build', '-C', file('src/main/jni').absolutePath } tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn ndkBuild } 

我发现“gradle 1.11 com.android.tools.build:gradle:0.9.+”现在支持预编译ndk,你可以把* .so放在dir src / main / jniLibs中。 当build立gradle将打包ndk到正确的地方。

这是我的项目

项目:
 | --src
 |  -  |  - 主
 |  -  |  -  | --java
 |  -  |  -  | --jniLibs
 |  -  |  -  |  -  | --armeabi
 |  -  |  -  |  -  |  -  |  -  so文件
 | --libs
 |  -  | --other.jar

正如Xavier所说,如果您使用gradle 0.7.2+版本,您可以将预编译器放在/ src / main / jniLibs /

取自: https : //groups.google.com/d/msg/adt-dev/nQobKd2Gl_8/ctDp9viWaxoJ

截至目前(Android Studio v0.8.6),它非常简单。 以下是创build“Hello world”types应用程序的步骤:

  1. 下载Android NDK,并把根文件夹放在一个理智的地方 – 也许在SDK文件夹的相同位置。

  2. 将以下内容添加到local.properties文件中: ndk.dir=<path-to-ndk>

  3. 将下面的内容添加到defaultConfig闭包中的build.gradle文件中,在versionName行之后: ndk { moduleName="hello-world" }

  4. 在您的应用程序模块的main目录中,创build一个名为jni的新文件夹。

  5. 在该文件夹中,创build一个名为hello-world.c的文件,您将在下面看到这个文件。

  6. 有关如何在hello-world.c调用方法(或函数?)的示例,请参阅下面的Activity代码示例。


hello-world.c

 #include <string.h> #include <jni.h> jstring Java_me_mattlogan_ndktest_MainActivity_stringFromJNI(JNIEnv* env, jobject thiz) { return (*env)->NewStringUTF(env, "Hello world!"); } 

MainActivity.java

 public class MainActivity extends Activity { static { System.loadLibrary("hello-world"); } public native String stringFromJNI(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String testString = stringFromJNI(); TextView mainText = (TextView) findViewById(R.id.main_text); mainText.setText(testString); } } 

build.gradle

 apply plugin: 'com.android.application' android { compileSdkVersion 20 buildToolsVersion "20.0.0" defaultConfig { applicationId "me.mattlogan.ndktest" minSdkVersion 15 targetSdkVersion 20 versionCode 1 versionName "1.0" ndk { moduleName "hello-world" } } buildTypes { release { runProguard false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) } 

在这里find一个非常类似的应用程序的完整源代码(减去NDK)。

如果你使用unix,最新版本(0.8)增加了ndk-build。 以下是如何添加它:

 android.ndk { moduleName "libraw" } 

它期望在'src / main / jni'下findJNI,否则你可以用下面的方法定义它:

 sourceSets.main { jni.srcDirs = 'path' } 

截至2014年1月28日,版本为0.8的版本在Windows上打破,您必须禁用该版本:

 sourceSets.main { jni.srcDirs = [] //disable automatic ndk-build call (currently broken for windows) } 

https://groups.google.com/d/msg/adt-dev/nQobKd2Gl_8/Z5yWAvCh4h4J中显示了一个优雅的解决方法。;

基本上你创build一个包含“lib / armeabi / yourlib.so”的jar,然后在构build中包含jar。

在另一个(封闭的)线程中给出一个很好的答案来自动化易于编译的.so文件的打包。 要做到这一点,我必须改变这一行:

 from fileTree(dir: 'libs', include: '**/*.so') 

成:

 from fileTree(dir: 'src/main/libs', include: '**/*.so') 

没有这个改变, .so文件没有find,因此打包它们的任务将永远不会运行。

@plaisthos的答案在最新的gradle版本中打破了,但仍然有办法做到这一点。 在项目目录的根目录下创build一个native-libs目录,并将所有的lib拷贝到这个目录中。

将以下行添加到您的build.gradle。 build立和快乐。

 task copyNativeLibs(type: Copy) { from(new File(project(':<your project>').getProjectDir(), 'native-libs')) { include '**/*.so' } into new File(buildDir, 'native-libs') } tasks.withType(Compile) { compileTask -> compileTask.dependsOn copyNativeLibs } clean.dependsOn 'cleanCopyNativeLibs' 

这是我使用从gradle使用android-ndk构build的代码。 为此,在gradle.properties添加ndk目录path。 添加ndkdir=/home/user/android-ndk-r9d ,并将所有jni文件放在src/main/中的native文件夹中,如下面的代码所示。 它将创build与本地库,您可以正常使用的System.loadLibrary("libraryname");

 dependencies { compile fileTree(dir: "$buildDir/native-libs", include: '*.jar') } task ndkBuild(type: Exec) { commandLine "$ndkdir/ndk-build", "--directory", "$projectDir/src/main/native", '-j', Runtime.runtime.availableProcessors(), "APP_PLATFORM=android-8", "APP_BUILD_SCRIPT=$projectDir/src/main/native/Android.mk", "NDK_OUT=$buildDir/native/obj", "NDK_APP_DST_DIR=$buildDir/native/libs/\$(TARGET_ARCH_ABI)" } task nativeLibsToJar(type: Jar, description: 'create a jar with native libs') { destinationDir file("$buildDir/native-libs") baseName 'native-libs' from fileTree(dir: "$buildDir/native/libs", include: '**/*.so') into 'lib/' } tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn nativeLibsToJar } nativeLibsToJar.dependsOn 'ndkBuild' 

我已经使用下面的代码来编译本机Dropbox库,我正在使用Android Studio v1.1。

 task nativeLibsToJar(type: Zip) { destinationDir file("$buildDir/native-libs") baseName 'native-libs' extension 'jar' from fileTree(dir: 'src/main/libs', include: '**/*.so') into 'lib/' } tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn(nativeLibsToJar) } 

我用ndk.dir=/usr/shareData/android-ndk-r11b // ndkpath

在android studio项目中的local.properties文件中。 并添加这一行:
android.useDeprecatedNdk=true

在android studio项目中的gradle.properties文件中。

更多信息在这里: http : //tools.android.com/tech-docs/android-ndk-preview

为了扩大纳克索斯所说的(感谢纳克索斯让我朝着正确的方向发展!),我从最近公布的NDK例子中学到了很多东西,并在这里发表了一个类似问题的答案。

如何用Android Gradle插件0.7configurationNDK

本文详细介绍了如何将预build的本地库链接到各种体系结构的应用程序,以及如何将NDK支持直接添加到build.gradle脚本的信息。 在大多数情况下,你不应该需要围绕邮编和复制工作了。

以下是我用于在Android Studio项目中获取NDK的步骤。 我使用这个教程来帮助我https://software.intel.com/en-us/videos/using-the-ndk-with-android-studio

为了使用NDK,你必须添加一个NDK行到local.properties。 所以在你的sdk.dir下添加

 ndk.dir=C\:\\MyPathToMyNDK\ndk 

在我的应用程序build.gradle我有以下代码

  ndk { moduleName "myLib" ldLibs "log" stl "gnustl_shared" cFlags "-std=c++11 -frtti -fexceptions -pthread" } 

moduleName是你想给你的本地代码的名字。 我相信这是共享库将被称为。 ldLibs允许我login到LogCat,stl是你想要导入的stl。 有很多选项,与Eclipse NDK相同。 ( http://www.kandroid.org/ndk/docs/CPLUSPLUS-SUPPORT.html

cFlags对我来说还是一定的黑魔法。 我还没有find所有选项和他们给我的一个很好的来源。 在StackOverflow中search任何你需要的东西,那就是我find它的地方。 我知道c ++ 11允许我使用新的c ++ 11标准。

这里是我如何从本地代码login到LogCat的例子

 __android_log_print(ANDROID_LOG_DEBUG, "TestApp", "Adding - String %d has a field name of %s and a value of %s", i, lKeyUTF8.c_str(), lValueUTF8.c_str()); 

从eclipseconfiguration项目在android工作室 :你必须导入eclipse ndk项目到android studio没有导出到gradle,它的工作原理,也需要添加path的ndk在local.properties ,如果显示错误,然后添加

 sourceSets.main { jniLibs.srcDir 'src/main/libs' jni.srcDirs = [] //disable automatic ndk-build callenter code here } 

build.gradle文件,然后使用terminal创buildjni文件夹和文件,运行它将工作

现在Android Studio处于稳定的频道,运行android-ndk样本非常简单。 这些示例使用ndk实验性插件 ,并且比从Android NDK联机文档链接到的更新。 一旦你知道他们的工作,你可以研究build.gradle,local.properties和gradle-wrapper.properties文件,并相应地修改你的项目。 以下是让他们工作的步骤。

  1. 转到设置,外观和行为,系统设置,Android SDK,selectSDK Tools标签,并检查列表底部的Android NDK版本1.0.0。 这将下载NDK。

  2. 指向新下载的NDK的位置。 请注意,它将被放置在sdk / ndk-bundle目录中。 通过select文件,项目结构,SDK位置(左侧)以及在Android NDK位置下提供path来完成此操作。 这将添加一个ndk条目到local.properties类似于这样的:

    Mac / Linux:ndk.dir = / Android / sdk / ndk-bundle
    Windows:ndk.dir = C:\ Android \ sdk \ ndk-bundle

我已经用这种方法成功构build和部署了存储库中的所有项目,除了gles3gni,native-codec和builder。 我正在使用以下内容:

Android Studio 1.3 build AI-141.2117773
2015年7月28日发布的android-ndk样本(上面的链接)
SDK工具24.3.3
NDK r10e解压缩到C:\ Android \ sdk \ ndk-bundle
Gradle 2.5
Gradle插件0.2.0
Windows 8.1 64位

NDK构build和gradle(基本)

通常使用NDK构build和正确指定Android.mk的ndkBuildpath或CMakeLists.txt的cmakepath一样简单。 我推荐在早期的Android.mk上使用CMake,因为Android Studio的C / C ++支持基于CLion,它使用CMake作为它的项目格式。 这在我的经验中倾向于使IDE在大型项目上更有响应。 在您的项目中编译的所有东西都将被自动构build并复制到APK中。

 apply plugin: 'com.android.library' android { compileSdkVersion 19 buildToolsVersion "25.0.2" defaultConfig { minSdkVersion 19 targetSdkVersion 19 ndk { abiFilters 'armeabi', 'armeabi-v7a', 'x86' // 64-bit support requires an Android API level higher than 19; Namely 21 and higher //abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' } externalNativeBuild { cmake { arguments '-DANDROID_TOOLCHAIN=clang', '-DANDROID_PLATFORM=android-19', '-DANDROID_STL=gnustl_static', '-DANDROID_ARM_NEON=TRUE' } } } externalNativeBuild { cmake { path 'src/main/jni/CMakeLists.txt' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) } 

将预build库添加到项目中(高级)

NDK构build中的静态库(.a)将自动包含在内,但是需要将预先构build的dynamic库(.so)放置在jniLibs 。 这可以使用sourceSets进行configuration,但是您应该采用标准。 包含预build库时,您build.gradle任何其他命令。

jniLibs的布局

您可以在Android Gradle插件用户指南中find关于结构的更多信息。

 |--app: |--|--build.gradle |--|--src: |--|--|--main |--|--|--|--java |--|--|--|--jni |--|--|--|--|--CMakeLists.txt |--|--|--|--jniLibs |--|--|--|--|--armeabi |--|--|--|--|--|--.so Files |--|--|--|--|--armeabi-v7a |--|--|--|--|--|--.so Files |--|--|--|--|--x86 |--|--|--|--|--|--.so Files 

然后,您可以validation生成的APK包含您的.so文件,通常在build/outputs/apk/ ,使用unzip -l myApp.apk列出内容。

build立共享库

如果您在NDK中构build共享库,则不需要进一步操作。 它将被正确捆绑在APK中。

只需将这些行添加到应用程序build.gradle

 dependencies { ... compile fileTree(dir: "$buildDir/native-libs", include: 'native-libs.jar') } task nativeLibsToJar(type: Zip, description: 'create a jar archive of the native libs') { destinationDir file("$buildDir/native-libs") baseName 'native-libs' extension 'jar' from fileTree(dir: 'libs', include: '**/*.so') into 'lib/armeabi/' } tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn(nativeLibsToJar) } 

现在我可以加载这么成功!

1.将.so文件添加到此path

 Project: 

| –src | – | –main | – | – | –java | – | – | –jniLibs | – | – | – | –armeabi | – | – | – | – | – so文件

2.将此代码添加到gradle.build

 android { splits { abi { enable true reset() include 'x86', 'x86_64', 'arm64-v8a', 'armeabi-v7a', 'armeabi' universalApk false } } 

}

3. System.loadLibrary("yousoname");

  1. goodluck给你,这与gradle 1.2.3没关系
  1. 如果您的项目从eclipse导出,请在gradle文件中添加以下代码:

     android { sourceSets{ main{ jniLibs.srcDir['libs'] } } } 

2.如果你在Android studio中创build一个项目:

在src / main /中创build一个名为jniLibs的文件夹,并将* .so文件放在jniLibs文件夹中。

并在您的gradle文件中复制代码如下:

 android { sourceSets{ main{ jniLibs.srcDir['jniLibs'] } } } 

虽然我相信SJOSH(甲骨文)有最完整的答案,但SWIG项目是一个特殊的情况,有趣而有用的,但对于大多数已经在标准的基于SDKant的项目+ NDK。 我们都希望现在最有可能使用Android工作室,或者希望有更多的CI友好的移动版本构build工具链,理论上可以提供这种工具链。

我已经发布了我的方法,从某处借用(我发现了这个,但贴了应用程序build.gradle的要点: https ://gist.github.com/truedat101/c45ff2b69e91d5c8e9c7962d4b96e841)。 简而言之,我build议如下:

  • 不要将您的项目升级到最新的gradle版本
  • 在您的项目根目录中使用com.android.tools.build:gradle:1.5.0
  • 在您的应用程序项目中使用com.android.application
  • 确保gradle.properties有:android.useDeprecatedNdk = true(万一抱怨)
  • 使用上述方法确保您创buildAndroid.mk文件的时间和精力不会被丢弃。 您可以控制构build哪个目标拱。 这些说明对于Windows用户来说是很友好的,他们理论上应该能够在没有特殊问题的情况下在Windows上进行开发。

Android的Gradle在我看来一直是一团糟,就像我喜欢借用的Maven概念和一个项目的目录结构一样。 这NDKfunction已经“快到”近3年以上。