JNI开发

java代码由于可以反编译,因此对于一些敏感逻辑,最好使用jni开发。

将开发好的so文件打包进jar文件,运行时从jar加载

基于Clion开发jnilib

1. 定义接口文件

1
2
3
4
5
6
7
8
9
10
11
package base.jni;

/**
* @author <a href=mailto:ktyi@iflytek.com>伊开堂</a>
* @date 2021/6/11
*/
public class MyService {

public native String hello(int times, String name);

}

2. 生成头文件

在编译出来的class文件的根目录(如:target/classes目录)执行如下目录,之后会在当前目录生成头文件

1
javah base.jni.MyService

头文件base_jni_MyService.h内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class base_jni_MyService */

#ifndef _Included_base_jni_MyService
#define _Included_base_jni_MyService
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: base_jni_MyService
* Method: hello
* Signature: (ILjava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_base_jni_MyService_hello
(JNIEnv *, jobject, jint, jstring);

#ifdef __cplusplus
}
#endif
#endif

2. 使用Clion创建新项目

项目类型选择C Excutable,保持C99

3. 复制JDK安装目录下的jni.hjni_md.h到Clion项目目录

1
2
cd /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/
cp include/jni.h include/darwin/jni_md.h ~/workspakce/clion_jni

4. 复制idea中的头文件base_jni_MyService.h到Clion,修改其内容中的#include <jni.h>#include “jni.h”

5. 新建base_jni_MyService.c并编译

1
2
3
4
5
6
7
8
9
10
//
// Created by Tonny Yi on 2021/6/11.
//

#include "base_jni_MyService.h"

JNIEXPORT jstring JNICALL Java_base_jni_MyService_hello
(JNIEnv *env, jobject, jint, jstring) {
return (*env)->NewStringUTF(env, "Hello...");
}

6. 编译库,库名称必须是lib*.jnilib格式

1
gcc base_jni_MyService.c -shared -fPIC -o libtest.jnilib

7. 复制编译后的库文件到java动态链接库,通过System.getProperty("java.library.path")可以获取链接库目录,也可以自行设置java.library.path的路径

1
cp libtest.jnilib ~/Library/Java/Extensions

也可以在运行代码时指定java.library.path

1
-Djava.library.path=E:\workspace\StudyJNI\lib

最后执行test

1
2
3
4
5
6
7
8
9
10
public class JniTest {
static {
System.loadLibrary("test");
}

public static void main(String[] args) {
System.out.println(new MyService().hello(32, "sss"));
}

}

基于IDEA开发so