我对Gradle和Android Studio的支持非常陌生。通过导出选项,我成功将我的Android项目转换为Gradle。
但我正在寻找一些文档或起点,以了解如何将NDK构建集成到Gradle构建过程中。
如果可能,我还需要某种“后续”阶段,将构建二进制文件(.so文件)复制到资源目录中。
我对Gradle和Android Studio的支持非常陌生。通过导出选项,我成功将我的Android项目转换为Gradle。
但我正在寻找一些文档或起点,以了解如何将NDK构建集成到Gradle构建过程中。
如果可能,我还需要某种“后续”阶段,将构建二进制文件(.so文件)复制到资源目录中。
更新:现在支持NDK的Android Studio已经发布,访问http://tools.android.com/tech-docs/android-ndk-preview
如果您希望使用脚本进行构建,则下面的gradle解决方案应该可以工作:
我正在使用自己的构建脚本,并将以下内容添加到我的文件中(对于0.8+
版本似乎有效):这似乎等同于下面的解决方案(但在gradle文件中看起来更好):
android {
sourceSets {
main {
jniLibs.srcDirs = ['native-libs']
jni.srcDirs = [] //disable automatic ndk-build
}
}
}
如果目录不存在或者不包含.so
文件,构建过程将不幸地不会失败。
tasks.withType(com.android.build.gradle.tasks.PackageApplication) { it.jniFolders = [file("libs")] as Set }
感谢大家的帮助! - trnljni.srcDirs = [] //disable automatic ndk-build
非常重要,因为它将防止Android Studio重新构建C / C ++源代码。 我一直在尝试解决这个问题两天,直到看到您的帖子,这解决了我的问题。 我真的认为NDK构建最好由Android.mk命令行makefile单独构建,而不是由gradle脚本构建,因为C / C ++已经通过Makefile构建了40多年! - tongandk {
moduleName "SeePlusPlus" // Name of C++ module (i.e. 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++代码的过程,从那里开始,您需要加载它并创建包装器——但根据您的问题,您已经知道如何做到这一点,所以我不会重复讲述。android.ndk {
moduleName = "SeePlusPlus" // Name of C++ module (i.e. 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”关键字自动完成功能:
然而,并非完全没有问题... 如果您正在使用SWIG封装库以自动生成代码,然后尝试使用'native'关键字自动生成,它会把代码放在Swig _wrap.cxx文件的错误位置...因此需要将其移动到“extern C”块中:
如果不提及Android Studio 2.2开始基本上通过Gradle和CMake支持NDK工具链就会失职。现在,当您创建一个新项目时,只需选择C ++支持即可。
您仍需要生成自己的JNI层代码或使用我上面提到的SWIG技术,但现在Android项目中的C ++脚手架非常简单。
对CMakeLists文件(其中放置C ++源文件)进行更改将被Android Studio捕获,并自动重新编译任何相关库。
现在已经不是预览版了,对所有人都可用:https://developer.android.com/studio/projects/add-native-code.html
jni
目录,Gradle会自动调用ndk-build
。这适用于Android Studio 0.5.9(金丝雀版)。
要么将ANDROID_NDK_HOME
添加到环境变量中,要么在Android Studio项目的local.properties
中添加ndk.dir=/path/to/ndk
。这样Android Studio就可以自动运行ndk。
下载最新的gradle示例项目以查看一个NDK项目的示例(它们在页面底部)。一个好的示例项目是ndkJniLib
。
复制NDK示例项目中的gradle.build
。它看起来像这样。这个gradle.build
为每个架构创建了不同的apk。您必须使用build variants
窗格选择要使用的架构。
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禁用自动调用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构建脚本中显式调用ndk-build。
此外,您可能需要在Gradle构建脚本中明确调用ndk-build,因为您刚刚禁用了自动调用。
task ndkBuild(type: Exec) {
commandLine 'ndk-build', '-C', file('src/main/jni').absolutePath
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
tasks.all { task -> if (task.name.contains('Ndk')) task.enabled = false }
。 - sherpya正如Xavier所说,如果你使用的是gradle 0.7.2+,你可以将你的预构建库放置在/src/main/jniLibs/中。
引用自:https://groups.google.com/d/msg/adt-dev/nQobKd2Gl_8/ctDp9viWaxoJ
到目前为止(Android Studio v0.8.6),这非常简单。以下是创建“Hello world”类型应用程序的步骤:
下载Android NDK并将根文件夹放在一个合理的位置 - 可以与SDK文件夹放在同一位置。
将以下内容添加到您的local.properties
文件中:ndk.dir =
将以下内容添加到您的build.gradle文件中的defaultConfig
闭包内,在versionName
行后面:ndk { moduleName="hello-world" }
在应用程序模块的main
目录中,创建一个名为jni
的新文件夹。
在该文件夹中,创建一个名为hello-world.c
的文件,您将在下面看到它。
参见下面的示例Activity
代码,了解如何调用hello-world.c
中的方法(或函数?)。
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'])
}
Java_me_mattlogan_ndktest_MainActivity_stringFromJNI
更改为你自己的 :) - AbdulMomen عبدالمؤمن如果您使用的是Unix系统,则最新版本(0.8)已经添加了ndk-build。以下是如何添加它:
android.ndk {
moduleName "libraw"
}
sourceSets.main {
jni.srcDirs = 'path'
}
--disable-build
。sourceSets.main {
jni.srcDirs = [] //disable automatic ndk-build call (currently broken for windows)
}
在https://groups.google.com/d/msg/adt-dev/nQobKd2Gl_8/Z5yWAvCh4h4J中展示了一种优雅的解决方案。
基本上,您需要创建一个包含 "lib/armeabi/yourlib.so" 的 jar 文件,并将其包含在构建中。
@plaisthos的答案在最新版gradle中出现了问题,但仍有方法可以解决。
在您的项目目录根目录下创建一个native-libs
目录,并将所有库文件复制到此目录中。
将以下代码添加到您的build.gradle中。构建并愉快地使用吧。
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'