-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathtestjnilib.cpp
129 lines (113 loc) · 5.43 KB
/
testjnilib.cpp
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <jni.h>
#include <string>
#include "testjnilib.h"
//java中stringFromJNI
//extern “C” 指定以"C"的方式来实现native函数
extern "C"
//JNIEXPORT 宏定义,用于指定该函数是JNI函数。表示此函数可以被外部调用,在Android开发中不可省略
JNIEXPORT jstring
//JNICALL 宏定义,用于指定该函数是JNI函数。,无实际意义,但是不可省略
JNICALL
//以注意到jni的取名规则,一般都是包名 + 类名,jni方法只是在前面加上了Java_,并把包名和类名之间的.换成了_
Java_com_yc_testjnilib_NativeLib_stringFromJNI(JNIEnv *env, jobject /* this */) {
//JNIEnv 代表了JNI的环境,只要在本地代码中拿到了JNIEnv和jobject
//JNI层实现的方法都是通过JNIEnv 指针调用JNI层的方法访问Java虚拟机,进而操作Java对象,这样就能调用Java代码。
//jobject thiz
//在AS中自动为我们生成的JNI方法声明都会带一个这样的参数,这个instance就代表Java中native方法声明所在的
std::string hello = "Hello from C++";
//思考一下,为什么直接返回字符串会出现错误提示?
//return "hello";
return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_yc_testjnilib_NativeLib_getMd5(JNIEnv *env, jobject thiz, jstring str) {
std::string stringHello = "哈哈哈哈哈,逗比";
return env->NewStringUTF(stringHello.c_str());
}
extern "C"
JNIEXPORT void JNICALL
Java_com_yc_testjnilib_NativeLib_initLib(JNIEnv *env, jobject thiz, jstring version) {
printf("初始化: 初始化操作2", version);
}
jstring getNameFromJNI(JNIEnv *env, jobject /* this */) {
std::string hello = "Hello from C++ , yc lov txy";
return env->NewStringUTF(hello.c_str());
}
//JNIEnv是什么?
//JNIEnv代表Java调用native层的环境,一个封装了几乎所有的JNI方法的指针。其只在创建它的线程有效,不能跨线程传递,不同的线程的JNIEnv彼此独立。
//native 环境中创建的线程,如果需要访问JNI,必须调用AttachCurrentThread 进行关联,然后使用DetachCurrentThread 解除关联。
//JNI动态注册案例学习
//动态注册其实就是使用到了前面分析的so加载原理:在最后一步的JNI_OnLoad中注册对应的jni方法。这样在类加载的过程中就可以自动注册native函数。
//java路径
#define JNI_CLASS_NAME "com/yc/testjnilib/NativeLib"
/**
* 需要动态注册的方法
* 第一个参数:java中要注册的native方法名
* 第二个参数:方法的签名,括号内为参数类型,后面为返回类型
* 第三个参数:需要重新注册的方法名
*/
//研究下JNINativeMethod:
//JNI允许我们提供一个函数映射表,注册给Java虚拟机,这样JVM就可以用函数映射表来调用相应的函数。
//这样就可以不必通过函数名来查找需要调用的函数了。
//Java与JNI通过JNINativeMethod的结构来建立联系,它被定义在jni.h中,其结构内容如下:
//typedef struct {
// const char* name;
// const char* signature;
// void* fnPtr;
//} JNINativeMethod;
static JNINativeMethod gMethods[] = {
{"stringFromJNI", "()Ljava/lang/String;", (void *) Java_com_yc_testjnilib_NativeLib_stringFromJNI},
{"getNameFromJNI", "()Ljava/lang/String;", (void *) getNameFromJNI},
};
int register_dynamic_Methods(JNIEnv *env) {
std::string s = JNI_CLASS_NAME;
const char *className = s.c_str();
// 找到需要动态注册的java类
jclass clazz = env->FindClass(className);
if (clazz == NULL) {
return JNI_FALSE;
}
//注册JNI方法
//核心方法:RegisterNatives,jni注册native方法。
//参数1:Java对应的类。
//参数2:JNINativeMethod数组。
//参数3:JNINativeMethod数组的长度,也就是要注册的方法的个数。
//通过调用RegisterNatives函数将注册函数的Java类,以及注册函数的数组,以及个数注册在一起,这样就实现了绑定。
if (env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) < 0) {
return JNI_FALSE;
}
return JNI_TRUE;
}
//System.loadLibrary()执行时会调用此方法
extern "C"
//类加载时会调用到这里
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env = NULL;
//指定JNI版本:告诉VM该组件使用那一个JNI版本(若未提供JNI_OnLoad()函数,VM会默认该使用最老的JNI 1.1版),
//如果要使用新版本的JNI,例如JNI 1.6版,则必须由JNI_OnLoad()函数返回常量JNI_VERSION_1_6(该常量定义在jni.h中) 来告知VM。
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
assert(env != NULL);
if (!register_dynamic_Methods(env)) {
return JNI_ERR;
}
// 返回JNI使用的版本
return JNI_VERSION_1_6;
}
//JNI_OnUnload()的作用与JNI_OnLoad()对应,当VM释放JNI组件时会呼叫它,因此在该方法中进行善后清理,资源释放的动作最为合适。
extern "C"
JNIEXPORT void JNI_OnUnload(JavaVM *jvm, void *reserved) {
JNIEnv *env = NULL;
if (jvm->GetEnv((void **) (&env), JNI_VERSION_1_6) != JNI_OK) {
return;
}
std::string s = JNI_CLASS_NAME;
const char *className = s.c_str();
// 找到需要动态注册的java类
jclass clazz = env->FindClass(className);
if (clazz != NULL) {
env->UnregisterNatives(clazz);
}
}