JNI 的一般开发流程
1 定义好本地的 native 方法
2 javah 命令生成 .h 头文件
3 拷贝 xxx.h、jni_md.h、jni.h 到 VS 的工程目录并添加依赖进来
4 实现我们头文件中的 native 方法
5 生成 dll 动态,java 引入 dll 动态库运行即可
生成的 .h 文件参数详解1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22/* DO NOT EDIT THIS FILE - it is machine generated */
/* Header for class com_darren_ndk12_NdkSimple */
// 用来打一个标记,c在编译的时候会把头文件 copy 到你引入的地方,不管是重复引用还是相互引用都只会 copy 一次
// 不管是 c 还是 c++ 统一都是采用 c 的编译方式,因为在c里面是不允许函数重载的,但是在 c++ 里面可以
extern "C" {
/*
* Class: com_darren_ndk12_NdkSimple
* Method: getSingnaturePassword
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_darren_ndk12_NdkSimple_getSingnaturePassword
(JNIEnv *, jobject);
}
实现类详解1
2
3
4
5
6
7
8
9
10
11
12
13
14// 实现我们的 native 方法
// JNIEXPORT JNI 一个关键字,不能少(编译能通过),标记为该方法可以被外部调用
// jstring : 代表 java 中的 String
// JNICALL: 也是一个关键字,可以少的 jni call
// JNIEnv: 这个是 c 和 java 相互调用的桥梁,所有 function 搞清
// jobject: java传递下来的对象,就是本项目中 JniSimple java 对象
// jclass: 静态函数的时候java传递下来的 class 对象,就是本项目中的 JniSimple.class
JNIEXPORT jstring JNICALL Java_com_darren_ndk12_NdkSimple_getSingnaturePassword
(JNIEnv * env, jobject jobj){
// JNIEnv * 其实已经是一个二级指针了,所以 -> 调用的情况下必须是一级指针 *取值
return (*env)->NewStringUTF(env,"940223");
}
JNIEnv是什么
在jni.h
里面有如下代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21/*
* JNI Native Method Interface.
*/
struct JNINativeInterface_;
struct JNIEnv_;
typedef JNIEnv_ JNIEnv;
typedef const struct JNINativeInterface_ *JNIEnv;
struct JNIEnv_ {
const struct JNINativeInterface_ *functions;
// ....
}
在实现的函数里面1
2
3
4
5JNIEXPORT jstring JNICALL Java_com_darren_ndk12_NdkSimple_getSingnaturePassword
(JNIEnv * env, jobject jobj){
// JNIEnv * 其实已经是一个二级指针了,所以 -> 调用的情况下必须是一级指针 *取值
return (*env)->NewStringUTF(env,"940223");
}
所以为什么在c
里面调用函数需要用(*env)->
,而c++
只需要用env->
JNIEnv
流程
手写JNIEnv
流程1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 定义一个结构体指针的别名
typedef const struct JNINativeInterface *JNIEnv;
// 模拟一个结构体
struct JNINativeInterface{
// 结构体的方法指针
char*(*NewStringUTF)(JNIEnv*,char*);
};
char* NewStringUTF(JNIEnv* env, char* c_str){
// c_str -> jstring
return c_str;
}
char* Java_com_darren_getSingnaturePassword(JNIEnv * env){
// JNIEnv * 其实已经是一个二级指针了,所以 -> 调用的情况下必须是一级指针 *取值
return (*env)->NewStringUTF(env, "940223");
}
void main(){
// 构建 JNIEnv* 对象
struct JNINativeInterface nativeInterface;
// 给结构方法指针进行复制(实现)
nativeInterface.NewStringUTF = NewStringUTF;
// 传给 Java_com_darren_ndk12_NdkSimple_getSingnaturePassword 的参数是 JNIEnv*
JNIEnv env = &nativeInterface;// 一级指针
JNIEnv* jniEnv = &env;// 二级指针
// 把 jniEnv 对象传给 Java_com_darren_ndk12_NdkSimple_getSingnaturePassword
char* jstring = Java_com_darren_getSingnaturePassword(jniEnv);
// jstring 通过 JNIEnv 传给 java 层
printf("jstring = %s",jstring);
getchar();
}