总结一下 C 如何 通过 JNI 层调用 Java 的静态和非静态方法
对于:JNIEXPORT void JNICALL Java_com_example_TestNative_sayHello(JNIEnv * env, jobject thiz, jstring paramString)这样一个函数
固定参数:
JNIEnv *env:JNIEnv代表java环境,通过*env这个指针,就可以让我们对java层的代码进行操作,比如创建java类的对象,调用java对象的方法,获取java对象的属性等等
这个指针会被JNI传递到本地方法的实现函数中来对java端的代码进行操作。
jobject thiz:分配给这个类的类加载器
函数参数:
jstring paramString:这是sayHello函数的具体参数,在外部调用的时候必须给sayHello函数一个参数,如:sayHello(“Hello JNI”);
调用java过程中(重点是调用java中的某些类的某些方法)
主要分下面几个步骤:
1.获取jclass
JNIEnv类中有如下几个简单的函数可以取得jclass
jclass FindClass(const char* clsName) 根据类名来查找一个类,完整类名
jclass GetObjectClass(jobject obj) 根据一个对象,获取该对象的类
jclass GetSuperClass(jclass obj) 获取一个类的父类
FindClass:根据类名来查找,需要注意的是:这里的类名是某个类的完整路径。
如:String这个类 jclass cls_string= (*env)->FindClass(“java/lang/String”);
在用的时候 需要把 . 换成 /
2.获取类中方法的ID或类属性的ID
JNI在jni.h头文件中定义了
jmethodID和
jfieldID类表示Java端的方法和属性
JNIEnv获取相应的jmethodID和
fieldID
的方法:
GetMethodID/GetStaticMethodID 获取一个实例的方法ID/一个静态的方法ID
GetFieldID/GetStaticMethodID 获取一个实例的域的ID/一个静态的域的ID
GetMethodID原型:
jmethodID (JNICALL *GetMethodID)
(JNIEnv *env, jclass clazz, const char *name, const char *sig);
第一个参数默认的*env
第二个参数是获取到的类
第三个参数是你要获取的某一个方法的名字
第四个参数是“签名”,引用这个签名的作用是对这一函数参数和返回值的描述,对于同一个函数,java是允许对它进行重载的,这时候就必须引入签名来区分他们。
3.调用方法
JNI同样提供了调用java方法的函数
JNIEnv去调用相应java方法的方法有:
Call<type>Method/CallStatic<type>Method 这里的<type>是要调用的那个方法的返回值类型
大致有
CallVoidMethod CallStaticVoidMethod
CallIntMethod CallStaticIntMethod
CallBooleanMethod CallStaticBooleanMethod
CallByteMethod CallStaticByteMethod
如:(*env)->CallVoidMethod(env, obj, jm_id,
parameter);
参数一
默认的*env
参数二是获取到的类
参数三是要调用的方法的ID
参数四这一方法的参数
方法的签名:
形如:(参数1类型签名参数2类型签名……参数n类型签名)返回值类型签名
签名分两部分:参数 & 返回值
类型的表述方式有如下对应关系:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
类型
相应的签名
boolean
Z
byte
B
char
C
short
S
int
I
long
J
float
F
double
D
void
V
object
L用
/分隔包的完整类名:
Ljava
/
lang
/
String
;
Array
[签名
[
I
[
Ljava
/
lang
/
Object
;
Method
(参数
1类型签名
参数
2类型签名···
)返回值类型签名
|
注:
1.object类型的每一个参数最后都得加上”;“
2.方法参数或者返回值为java中的对象时,签名中必须以“L”加上其路径,不过此路径必须以“/”分开,自定义的对象也使用本规则
例如说 java.lang.String为“java/lang/String”,com.nedu.jni.helloword.Student为”Lcom /nedu/jni/helloword/Student;”
3.方法参数或者返回值为数组类型时,请前加上[
例如[I表示 int[],[[[D表示 double[][][],即几维数组就加几个[

实例:
1
2
3
4
5
6
|
void
f1
(
)
(
)
V
int
f2
(
int
,
long
)
(
IJ
)
I
boolean
f3
(
int
[
]
)
(
[
I
)
B
double
f4
(
String
,
int
)
(
Ljava
/
lang
/
String
;
I
)
D
void
f5
(
int
,
String
[
]
,
char
)
(
I
[
Ljava
/
lang
/
String
;
C
)
V
byte
[
]
f6
(
int
,
String
,
String
)
(
ILjava
/
lang
/
String
;
Ljava
/
lang
/
String
)
[
B
|
下面以几个实例来重点介绍下方法的签名的书写方式
a、调用某一个类的构造函数:
1
2
3
4
5
6
7
8
|
SecureRandom
localSecureRandom
=
new
SecureRandom
(
)
;
//获取类:
jclass
jc_SecureRandom
=
(
*
env
)
->
FindClass
(
env
,
"java/security/SecureRandom"
)
;
//获取构造函数的ID,构造函数的名称都是“<init>”;
//签名:形如"()V" 括号里是参数类型,括号外是返回值类型,这里无参数,返回值是Void
jmethodID
jm_constructor
=
(
*
env
)
->
GetMethodID
(
env
,
jc_SecureRandom
,
"<init>"
,
"()V"
)
;
//调用:
jobject
jo_SecureRandom
=
(
*
env
)
->
NewObject
(
env
,
jc_SecureRandom
,
jm_constructor
)
;
|
b、调用String类的getBytes方法:
1
2
3
4
5
6
7
8
9
|
//获取类:
jclass
jc_string
=
(
*
env
)
->
FindClass
(
env
,
"java/lang/String"
)
;
//获取方法ID:
jmethodID
jm_getBytes
=
(
*
env
)
->
GetMethodID
(
env
,
jc_string
,
"getBytes"
,
"()[B"
)
;
//参数为空,返回值为byte[]
//调用:
jbyteArray
jb_paramString
=
(
jbyteArray
)
(
*
env
)
->
CallObjectMethod
(
env
,
paramString
,
jm_getBytes
)
;
|
c、调用Cipher类的
getInstance方法:
1
2
3
4
5
6
7
8
9
10
11
|
//获取类:
jclass
jc_Cipher
=
(
*
env
)
->
FindClass
(
env
,
"javax/crypto/Cipher"
)
;
//获取方法ID:
jmethodID
jm_Cipher_getInstance
=
(
*
env
)
->
GetStaticMethodID
(
env
,
jc_Cipher
,
"getInstance"
,
"(Ljava/lang/String;)Ljavax/crypto/Cipher;"
)
;
//参数是一个string, 返回值是一个Cipher
//调用:
jobject
jo_Cipher
=
(
*
env
)
->
CallStaticObjectMethod
(
env
,
jc_Cipher
,
jm_Cipher_getInstance
,
(
*
env
)
->
NewStringUTF
(
env
,
"DES"
)
)
;
|
实例一:
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
|
/* c/c++ string turn to java jstring */
jstring
charToJstring
(
JNIEnv*
env
,
const
char
*
pat
)
{
jclass
strClass
=
(
*
env
)
->
FindClass
(
env
,
"java/lang/String"
)
;
jmethodID
ctorID
=
(
*
env
)
->
GetMethodID
(
env
,
strClass
,
"<init>"
,
"([BLjava/lang/String;)V"
)
;
jbyteArray
bytes
=
(
*
env
)
->
NewByteArray
(
env
,
strlen
(
pat
)
)
;
(
*
env
)
->
SetByteArrayRegion
(
env
,
bytes
,
0
,
strlen
(
pat
)
,
(
jbyte*
)
pat
)
;
jstring
encoding
=
(
*
env
)
->
NewStringUTF
(
env
,
"UTF-8"
)
;
return
(
jstring
)
(
*
env
)
->
NewObject
(
env
,
strClass
,
ctorID
,
bytes
,
encoding
)
;
}
/* java jstring turn to c/c++ char* */
char
*
jstringToChar
(
JNIEnv*
env
,
jstring
jstr
)
{
char
*
pStr
=
NULL
;
jclass
jstrObj
=
(
*
env
)
->
FindClass
(
env
,
"java/lang/String"
)
;
jstring
encode
=
(
*
env
)
->
NewStringUTF
(
env
,
"utf-8"
)
;
jmethodID
methodId
=
(
*
env
)
->
GetMethodID
(
env
,
jstrObj
,
"getBytes"
,
"(Ljava/lang/String;)[B"
)
;
jbyteArray
byteArray
=
(
jbyteArray
)
(
*
env
)
->
CallObjectMethod
(
env
,
jstr
,
methodId
,
encode
)
;
jsize
strLen
=
(
*
env
)
->
GetArrayLength
(
env
,
byteArray
)
;
jbyte *
jBuf
=
(
*
env
)
->
GetByteArrayElements
(
env
,
byteArray
,
JNI_FALSE
)
;
if
(
jBuf
>
0
)
{
pStr
=
(
char
*
)
malloc
(
strLen
+
1
)
;
if
(
!
pStr
)
{
return
NULL
;
}
memcpy
(
pStr
,
jBuf
,
strLen
)
;
pStr
[
strLen
]
=
0
;
}
env
->
ReleaseByteArrayElements
(
byteArray
,
jBuf
,
0
)
;
return
pStr
;
}
|
实例二
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
|
#include <string.h>
#include <jni.h>
#include <stdio.h>
jbyteArray
decryto
(
JNIEnv *
env
,
jobject
jclazz
,
jbyteArray
paramArrayOfByte
,
jstring
paramString
)
{
jclass
jc_SecureRandom
=
(
*
env
)
->
FindClass
(
env
,
"java/security/SecureRandom"
)
;
jmethodID
jm_constructor
=
(
*
env
)
->
GetMethodID
(
env
,
jc_SecureRandom
,
"<init>"
,
"()V"
)
;
jobject
jo_SecureRandom
=
(
*
env
)
->
NewObject
(
env
,
jc_SecureRandom
,
jm_constructor
)
;
jclass
jc_DESKeySpec
=
(
*
env
)
->
FindClass
(
env
,
"javax/crypto/spec/DESKeySpec"
)
;
jmethodID
jm_DESKeySpec
=
(
*
env
)
->
GetMethodID
(
env
,
jc_DESKeySpec
,
"<init>"
,
"([B)V"
)
;
//DESKeySpec函数的参数是byte[] 返回值是void
jclass
jc_string
=
(
*
env
)
->
FindClass
(
env
,
"java/lang/String"
)
;
jmethodID
jm_getBytes
=
(
*
env
)
->
GetMethodID
(
env
,
jc_string
,
"getBytes"
,
"()[B"
)
;
//参数为空,返回值为byte[]
jbyteArray
jb_paramString
=
(
jbyteArray
)
(
*
env
)
->
CallObjectMethod
(
env
,
paramString
,
jm_getBytes
)
;
jobject
jo_DESKeySpec
=
(
*
env
)
->
NewObject
(
env
,
jc_DESKeySpec
,
jm_DESKeySpec
,
jb_paramString
)
;
//new DESKeySpec(ArrayOfByte);
jclass
jc_SecretKeyFactory
=
(
*
env
)
->
FindClass
(
env
,
"javax/crypto/SecretKeyFactory"
)
;
jmethodID
jm_getInstance
=
(
*
env
)
->
GetMethodID
(
env
,
jc_SecretKeyFactory
,
"getInstance"
,
"(Ljava/lang/String;)Ljavax/crypto/SecretKeyFactory;"
)
;
//getInstance的参数是string,返回值是一个SecretKeyFactory
jobject
jo_SecretKeyFactory
=
(
*
env
)
->
CallStaticObjectMethod
(
env
,
jc_SecretKeyFactory
,
jm_getInstance
,
(
*
env
)
->
NewStringUTF
(
env
,
"DES"
)
)
;
jmethodID
jm_generateSecret
=
(
*
env
)
->
GetMethodID
(
env
,
jc_SecretKeyFactory
,
"generateSecret"
,
"(Ljava/security/spec/KeySpec;)Ljavax/crypto/SecretKey;"
)
;
//generateSecret的参数是一个keyspec,返回值是一个secretKey
jobject
jo_SecretKey
=
(
*
env
)
->
CallObjectMethod
(
env
,
jc_SecretKeyFactory
,
jm_generateSecret
,
jo_DESKeySpec
)
;
jclass
jc_Cipher
=
(
*
env
)
->
FindClass
(
env
,
"javax/crypto/Cipher"
)
;
jmethodID
jm_Cipher_getInstance
=
(
*
env
)
->
GetStaticMethodID
(
env
,
jc_Cipher
,
"getInstance"
,
"(Ljava/lang/String;)Ljavax/crypto/Cipher;"
)
;
//参数是一个string, 返回值是一个Cipher
jobject
jo_Cipher
=
(
*
env
)
->
CallStaticObjectMethod
(
env
,
jc_Cipher
,
jm_Cipher_getInstance
,
(
*
env
)
->
NewStringUTF
(
env
,
"DES"
)
)
;
jmethodID
jm_Cipher_init
=
(
*
env
)
->
GetMethodID
(
env
,
jc_Cipher
,
"init"
,
"(ILjava/security/Key;Ljava/security/SecureRandom;)V"
)
;
(
*
env
)
->
CallVoidMethod
(
env
,
jc_Cipher
,
jm_Cipher_init
,
2
,
jo_SecretKey
,
jo_SecureRandom
)
;
jmethodID
jm_Cipher_doFinal
=
(
*
env
)
->
GetMethodID
(
env
,
jc_Cipher
,
"doFinal"
,
"([B)[B"
)
;
//参数是byte[] 返回值也是byte[]
jbyteArray
jb_Resultarr
=
(
*
env
)
->
CallObjectMethod
(
env
,
jc_Cipher
,
jm_Cipher_doFinal
,
paramArrayOfByte
)
;
//最终结果就保存在jb_Resultarr
return
jb_Resultarr
;
}
JNIEXPORT
jbyteArray
JNICALL
Java_com_qihoo_test_first_MainActivity_decry
(
JNIEnv *
env
,
jobject
thiz
,
jbyteArray
paramArrayOfByte
,
jstring
paramString
)
{
return
decryto
(
env
,
thiz
,
paramArrayOfByte
,
paramString
)
;
}
|
本文出自 0n1y3nd's Blog,转载时请注明出处及相应链接。
本文永久链接: http://0nly3nd.sinaapp.com/?p=277