环境:
- Android studio 2.1.2
- android-ndk-r10e
创建一个jni工程:
首先新建一个Android项目,刚刚建好的项目目录结构如下所示:
然后设置NDK路径,在local.properties文件中加入一行ndk.dir=你自己ndk所在路径
新建的项目默认是不包含jni的,因此我们要手动增加一个jni目录
如图,我们在app目录下面创建一个jni目录,这个jni目录存放C、C++代码和mk文件。因为在NDK编译的时候,会去jni目录下面找mk文件,根据mk文件执行编译。
在创建jni目录的时候我们选择改变默认的路径,让jni目录在app目录之下。
创建好jni目录之后,在jni目录添加mk文件,包括Android.mk和Application.mk,编译脚本基本都是在Android.mk文件里面,Application.mk里面可以设置一些编译选项,比如ABI,STL库设置等等。
接下来我们就可以编写代码了。找到MainActivity类文件(在app/src/main/java目录下),在MainActivity类里面添加jni接口
public native String getStringFromJni();
注意:jni接口需要用native关键字声明
java中接口定义好之后,我们要在底层实现。也就是用C或者C++实现我们在MainActivity类里面定义的getStringFromJni方法。
- 在app/jni目录下增加hello.cpp文件,在里面写getStringFromJni方法的实现
#include <jni.h>
extern "C"
{
jstring Java_com_example_www_hellojni_MainActivity_getStringFromJni(JNIEnv* jni, jobject obj)
{
return jni->NewStringUTF("Hello jni!");
}
}//extern "C"
如图方法名称要遵循一定的规则,从左到右依次是Java_包名_类名_方法名,包名里面的“.”换成 “_” 按照这样的方式去命名,通过这样的规则,jni方法被调用的时候才可以找得到它具体的实现。
因为是C++代码,所以要加extern “C”,将C++代码按照C代码去编译。
- 然后我们需要编写mk脚本,打开Android.mk文件,在里面写入如下脚本:
LOCAL_PATH := $(call my-dir) #设置LOCAL_PATH为本文件所在路径
include $(CLEAR_VARS) #初始化LOC_ 变量
LOCAL_MODULE := hello-jni #设置so名称,该设置下将会编译产生libhello-jni.so文件,前面的lib和后面的.so是编译之后自动添加的
LOCAL_SRC_FILES := hello.cpp #需要编译的源文件,如果源文件不在app/jni目录下,需要加上路径
include $(BUILD_SHARED_LIBRARY) #执行动态库编译,如果是BUILD_SHARED_LIBRARY,就会编译静态库
以上脚本就会把hello.cpp编译为一个libhello-jni.so文件
- 接着编写Application.mk,一般我们可以设置ABI,如下:
APP_ABI := all #所有平台都编译
APP_ABI := armeabi-v7a mips x86 #只编译armeabi-v7a、mips、x86这三个平台
- 紧接着我们还要设置build.gradle,在app/build.gradle文件里写入下面代码:
android{
...
sourceSets {
main {
jniLibs.srcDir('libs')//生成的so文件在这个目录里面app/libs
}
}
}
task NDKBuildDebug(type: Exec) {
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def ndkDir = properties.getProperty('ndk.dir') + '/ndk-build.cmd'
commandLine ndkDir, 'V=0', '-j10', 'NDK_DEBUG=1', 'NDK_LOG=1'
}
project.afterEvaluate {
compileDebugNdk.dependsOn 'NDKBuildDebug'
}
- 最后我们要先载入动态库,然后再调用jni接口,MainActivity里面代码如下:
public class MainActivity extends AppCompatActivity {
static {
//Android.mk文件里面指定的模块名称 “LOCAL_MODULE := hello-jni”
System.loadLibrary("hello-jni");
}
public native String getStringFromJni();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView tv = new TextView(this);
tv.setText( getStringFromJni() );
setContentView(tv);
}
}
最后编译,运行。
这样一个简单的jni工程就建好了,希望对刚开始接触的朋友有所帮助。