开发环境搭建
- Windows下Eclipse+NDK+Cygwin方式:NDK r7之前的版本,必须要安装Cygwin才能使用NDK。而在NDKr7开始,Google简化了这个过程,在Eclispe中为NDK提供了一个ndk-build.cmd的脚本,就可以直接利用这个脚本编译,而不用再安装Cygwin(Cygwin的作用就是在Windows下模拟Linux环境)了。只需要为Eclipse Android工程添加一个Builders,而为Eclipse配置的builder,其实就是在执行Cygwin,然后传递ndk-build作为参数,这样就能让Eclipse自动编译NDK了,这就简化了我们的开发流程。
- Windows下eclipse+NDKBundle+Ant:Windows下Eclipse使用ndk-build方式构建NDK开发环境
- Android Studio 2.3+CMake(AS NDK开发默认的编译脚本)方式
不得不感慨下,Google对NDK的支持越来越好,到上面提到的第三种方式时,NDK的开发,已经不需要你在环境方面麻烦了。使用CMake方式创建的支持DNK的项目大概长这样
这样方式下,在JNICall中新建一个本地方法然后“Make Project”,Gradle自动会使用CMake脚本创建本地方法对应的头文件到native-lib.cpp文件中。这样就可以将更多注意力放在业务相关的C/C++开发上面。
ndk-build脚本方式下通用开发流程
- 在类中定义native方法
public class JNIUnit {
public static native String getStringFormC();
}
- 使用javac命令或者AS的编译工程,生成.class文件
- 使用javah命令将生成.class文件 --> .h头文件
cd class文件所在目录
javah -jni 包名.类名(如com.ns.jnistudy.JNICall)
生成文件 com_ns_jnistudy_JNICall.h如下
/* DO NOT EDIT THIS FILE - it is machine generated */
_#include <jni.h>
...
extern "C" {
//注意到函数名完全按照:java_pacakege_class_mathod 形式来命名。
//Class: com_example_hellojni_HelloJni
//Method: stringFromJNI
//Signature: ()Ljava/lang/String;
JNIEXPORT jstring JNICALL Java_com_ns_jnistudy_JNICall_getStringFormC
(JNIEnv *, jobject);
...
}
...
- 将上述文件移动到的项目的jni目录下并实现.h文件对应的.c文件
JNIEXPORT jstring JNICALL Java_com_ns_jnistudy_JNICall_getStringFormC
(JNIEnv *, jobject){
return (*env)->NewStringUTF(env,"just have a test");
}
- 在jni目录下增加Android.mk和Application.mk文件,关于这两个文件的含义以及如何配置参见NDK编程--鸟瞰。
- 环境配置
在 file ->project structure 中增加 ndk的路径,或者在local.properties 中增加ndk路径。在 gradle.preperties 中增加android.useDeprecatedNdk=true
修改build.gradle在 defaultConfig 节增加如下配置
ndk {
moduleName "NdkJniDemo" //生成的so库的名字
abiFilters "armeabi", "armeabi-v7a", "x86"//ABI平台
}
配置完成之后,当程序构建时,Gradle(一种自动化构建工具,如完成编译,打包,测试等功能)so文件打包进APK中。 - cd到ndk目录下执行ndk-build命令(ndk-build把.c文件编译,链接生成各平台对应的.so文件)
- 在程序的入口处(Application或者MainActivity或定义本地方法的类中)
static {
System.loadLibrary("so库名字");
}
注意:第3步与第6步使用了javah和ndk-build命令,可以将命令配置成eclipse工具或将命令配置成Android Studio工具。
运行时Java通过JNI调用流程
- 当本地放在所在的类被第一次加载的时候,静态代码块会先行加载。
- 调用的时候通过本地方法调用so文件的C/C++实现
关于ndk-build与cmake:
NDK本身是用来Android下编译C/C++代码的一个编译器和库的集合。这两个家伙都是基于NDK的编译系统(编译脚本),使用项目里的Java代码,将本地代码编译到共享库中,两个门干的事同一件事,解决的是同一个问题。ndk-build是NDK的包含的编译系统,使用Android.mk;cmake使用CMakeLists.txt,在你的Module app的build.gradle中你可以看到这句话
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
那有哥们或者妹子就不同意了,既然都一样,该如何选呢?ok,这问题Google已经帮我们做选择了,AS默认是支持CMake。且CMake脚本在非Android开发者中很流行。CMake的主要便利在于你可以使用一套编译文件构建所有的目标平台(Android,Linux,Windows,IOS,etc)。
但是Google帮我们做了很多开发效率上的改进,但是们仍需要知道DNK开发背后的逻辑,这里以ndk-build脚本的角度来讲。
参考
NDK Official tutorials
Add C and C++ Code to Your Project
Android NDK--everything you need to know
windows下Eclipse+NDK bundle开发
windows下Android Studio+NDK bundle开发