天天看点

Android中关于JNI 的学习(零)简单的例子,简单地入门

android中jni的作用,就是让java能够去调用由c/c++实现的代码,为了实现这个功能,需要用到anrdoid提供的ndk工具包,在这里不讲如何配置了,好麻烦,配置了好久。。。

本质上,java去调用c/c++的代码其实就是去调用c/c++提供的方法,所以,第一步,我们要创建一个类,并且定义一个native方法,如下:

jnitest类:

可以看到,在这个方法的前面,用到了native关键字。

接着,我们要在命令行中编译这个java文件,得到一个class文件,如下:

Android中关于JNI 的学习(零)简单的例子,简单地入门

然后我们可以利用javah命令文件,生成一个c的头文件,其实javah这一步不是必需的,因为创建这个头文件,只是为了方便我们复制这个jni中对应的方法名称,因为这些名称实在太复杂了。 

在这里有一点要注意,javah命令要在包的根目录下调用,对应的类文件,必须是完整的类名,如上图所示,会先回到src目录,再调用javah命令。

这样我们就会在src文件夹下在产生一个头文件,如下图所示:

Android中关于JNI 的学习(零)简单的例子,简单地入门

我们可以看到其名称是com_lms_jni_jnitest.h,其实就是包名+类名,我们可以看看里面的内容:

我们可以看到,在这里面有一个方法,名称是java_com_lms_jni_jnitest_getteststring,够复杂吧,其实如果我们知道这个名称规则,并且知道如何去实现这样一个方法的话,我们是完全可以不生成这个头文件的,我们可以直接写出对应的c文件。

接下来,在jni文件中创建一个对应的c文件,名称是值得并无所谓,但为了统一,我们就把它叫jnitest.c吧,如下:

Android中关于JNI 的学习(零)简单的例子,简单地入门

在这里,我们也把com_lms_jni_jnitest.h也放到这里了,这个其实是没关系的,只是为了内容的协调和统一而已,一般情况下,我们会把所以由c/c++实现的文件都放在项目目录下一个叫 jni 的文件夹下面。

下面是在jnitest.c中实现native方法,getteststring,如下:

在这个c文件中,我们看到,并没有引用头文件com_lms_jni_jnitest.h,而只是引用了一般的c/c++库文件,比如stido.h和stdlib.h文件等,在这里注意到一点,我们还会引用jni.h文件,jni.h文件是jni编程中很重要的一个头文件,关于java中的数据类型跟jni中的数据类型的对应全部是在这个文件中定义的,后续会来看一下这个jni.h文件。

在上面jnitest.c文件中实现了方法之后,关于c/c++这边的实现其实也就实现了,那么接下来就是要将这个c文件编译成so文件由android来调用。

为什么是so文件呢,这是因为android本质上就是一个linux系统,所以其调用的jni库文件,都是so形式。

android提供的ndk库提供了ndk-build的命令来实现这个编译过程,但在此之前,我们要先创建一个android.mk文件,这是一个简单的小小的make文件,其内容如下:

在这里,我们会定义几个变量:

local_path:其值是call my-dir,而my-dir是个宏函数,会返回android.mk所在的路径,在这里,就是jni文件夹。

include $(clear_vars),这个命令会清除掉所有local开头的变量,比如local_module之类的,但有一个例外,就是其上面的local_path 。

local_module:要生成的so包名,也是android中java代码加载时的名称。

local_src_files:要进行编译的源文件,如在这里,有hwdemo.c和jnitest.c等。

include $(build_shared_library):表明生成一个动态链接库。

定义后这样一个android.mk文件之后,在命令行中调用ndk-build命令,如下:

Android中关于JNI 的学习(零)简单的例子,简单地入门

命令实行之后,我们可以在项目目录下看到libs中多了一个so库,如下:

Android中关于JNI 的学习(零)简单的例子,简单地入门

到这里,关于jni实现的就结束了,接下来就是如何在android中使用这个本地方法了。

我们创建了一个activity,在它里面只放置一个textview控件,它的布局如下:

然后在activity中,我们要加载这个so库,如下:

1)利用static静态代码块,加载so库文件,可以看到在这里,这个名称就是anrdoid.mk中定义的local_module值。

2)创建jnitest对象,调用其getteststring()方法,最终显示结果如下:

Android中关于JNI 的学习(零)简单的例子,简单地入门

到这里,通过一个简单的例子,我们明白了如何在android中利用jni来调用c/c++的方法了。

最后,我们总结一下这几个步骤:

1)创建java类文件,并定义native方法,如jnitest类。

2)利用javac生成class文件,然后回到src目录,利用javah生成c/c++头文件,在这里要注意,javah命令要在包的根目录下调用,对应的类文件,必须是完整的类名,如下:

在src目录:javah com.lms.jni.jnitest,在上面的截图,也可以看到javac之后,是回到src目录,再调用javah。

3)编写对应的c文件,如jnitest.c,在里面实现c/c++的方法,记得要放在jni文件夹下面。

4)编写android.mk文件,利用ndk-build命令生成so文件。

5)在android中利用static静态代码块,调用system.loadlibrary方法来加载so库文件。

6)在java逻辑中调用之前定义的jnitest类的方法。

结束。!