JNI
最近在学习Android,其中需要使用到c的库,这个时候就要使用到JNI
机制了,简单来说,就是可以通过这个机制,让java代码可以调用本地c语言编写的代码,将c语言编写的代码打包成动态库,然后,在java代码中使用native
关键字修饰方法,再将so文件加载进JVM即可,那么废话不多说,下面来看看这个demo吧。
编写java程序
package com.bwzfy;
public class App {
private native void print();
public static void main(String[] args) {
new App().print();
}
static {
System.loadLibrary("App");
}
}
这个java程序很简单吧,就是在App这个类加载之前,将动态库加载进到JVM内存中,注意了。System.loadLibrary("App");
这行代码里面的App是动态库的名字,正常在linux中,动态库的名字是libxxx.so。如果我们的目标程序打包成动态库的话,那名字就是libApp.so。前面的lib
和后缀.so
都是固定死的,所以我们加载动态库的时候只需要写中间那部分就可以了。
使用javah命令编译出.h文件
首先使用javac命令,将上面的源代码编译成class文件
javac App.java
此时此刻,我们会在App.java这个文件的目录下看到App.class文件,这里有个坑,不建议把App.class文件和App.java文件放在一个目录下。浪费了我很多时间,可以参考https://blog.youkuaiyun.com/weixin_45414277/article/details/109364327。
我这里将App.class文件单独放置到了一个目录下。
然后这个时候使用javah命令将class文件编译成.h文件。
javah -jni -cp /opt/project/hightlight/classes com.bwzfy.App
我们可以在当前自己所在目录下看到这么一个文件
编写对应c文件
我这里就是这个hello.c文件代码如下:
#include <jni.h>
#include <stdio.h>
#include "com_bwzfy_App.h"
JNIEXPORT void JNICALL Java_com_bwzfy_App_print
(JNIEnv *jni, jobject jo){
printf("hello world 114514");
}
JNI的gcc编译c文件成动态库
随后我们需要将编写好的本地c程序打包成动态库的形式,命令如下(根据自己的实际情况作修改)。
gcc -I $JAVA_HOME/include/ -I $JAVA_HOME/include/linux/ hello.c -shared -fPIC -o libApp.so
java启动,并指定so路径
最后就可以启动java程序了,这里注意需要指定一下java程序从哪里获取这个动态库,可以在启动的时候使用-Djava.library.path
来指定jvm从哪里加载动态库,我们只需要把刚才生成的动态库放置到这个目录下即可。
启动命令如下:
java -Djava.library.path=/opt/project/highlight/lib -cp ./classes com.bwzfy.App
运行结果: