深入了解android平台的jni(一)

android中很多Java类都具有native接口,这些接口由本地实现,然后注册到系统中。

主要的JNI代码放在以下的路径中:frameworks/base/core/jni/,这个路径中的内容被编译成库libandroid_runtime.so,被放置在目标系统的/system/lib目录下。此外,android还有其他的JNI库。JNI中的各个文件,实际上就是普通的C++源文件.

如果要深入了解androidframework层,则必须AndroidNative层运行及开发机制.

这里先介绍一些native的基础知识

1、接口定义

_JNIEnv定义了一个虚拟机的接口,通过这个接口可以访问虚拟机的所有功能:

1)分配对象(AllocObject/NewObject),并且控制对象的引用计数(NewGlobalRef/DeleteGlobalRef/DeleteLocalRef/IsSameObject/NewLocalRef)。

2)获取类的定义(FindClass),并通过类的定义来获取获取类得方法和成员的ID(GetMethodID/GetFieldID)

3)通过方法ID调用类的普通方法(CallObjectMethod)和静态方法(CallStaticObjectMethod)

4)通过成员ID获取和设置类的普通成员(GetObjectField/SetObjectField)和静态成员(GetStaticObjectField/SetStaticObjectField)

下面是比较常用的方法:

1)查找该类:

jclassxxx=(*env)->FindClass(env,"Lclass_name;");

2)取得方法的id:

jmethodIDxxx=(*env)->GetMethodID(env,jclass,methodName,"(M)N");

3)查找需要调用的该类的方法:

jmethodIDxxx=(*env)->GetMethodID(env,jclass,"(M)N");

4)取得静态方法的id

jmethodIDxxx=(*env)->GetStaticMethodID(env,jclass,methodName,"(M)N")

5)初始化该类的实例:

jobjectxxx=(*env)->NewObject(env,jclass,jmethodID);

6)调用实例的某方法:

(*env)->CallObjectMethod(env,jobject,jmethodID,[parameter1,parameter2,...]);

7)释放实例:

(*env)->DeleteLocalRef(env,xxx);

8)取得成员变量的id

jfieldIDxxx=(*env)->GetFieldID(env,jclass,jfieldID,jfieldType)

9)取得静态成员变量的id

jfieldIDxxx=GetStaticFieldID(env,jclass,jfieldID,jfieldType)

JNIENV-java的运行环境

jobject-代表java的instance

jclass-代表java的类

2、函数与属性签名

在GetMethodID和GetFieldID这两个函数中,最后一个参数都是签名字符串,用来标示java函数和成员的唯一性。

因为java中存在重载函数,所以一个函数名不足以唯一指定一个函数,这时候就需要签名字符串来指定函数的参数列表和返回值类型了。

函数签名是一个字符串:"(M)N"

括号中的内容是函数的参数类型,括号后面表示函数的返回值。

3、JNI类型签名

"(M)N",这里的M和N指的是该函数的输入和输出参数的类型签名(TypeSignature)。

具体的每一个字符的对应关系如下

字符Java类型C类型

Vvoidvoid

Zjbooleanboolean

Ijintint

Jjlonglong

Djdoubledouble

Fjfloatfloat

Bjbytebyte

Cjcharchar

Sjshortshort

数组则以”["开始,用两个字符表示

[IjintArrayint[]

[FjfloatArrayfloat[]

[BjbyteArraybyte[]

[CjcharArraychar[]

[SjshortArrayshort[]

[DjdoubleArraydouble[]

[JjlongArraylong[]

[ZjbooleanArrayboolean[]

如果Java函数的参数是class,则以”L”开头,以”;”结尾,中间是用”/”隔开的包及类名。而其对应的C函数名的参数则为jobject

一个例外是String类,其对应的类为jstring

Ljava/lang/String;Stringjstring

Ljava/net/Socket;Socketjobject

如果JAVA函数位于一个嵌入类,则用$作为类名间的分隔符。

例如“(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z”

举例说明"(M)N"的含义,例如:

(I)V带一个int类型的参数,返回值类型为void

()D没有参数,返回double

本文欢迎转载,但请注明作者与出处:

作者:流星

出处:http://blog.sina.com.cn/staratsky

相关推荐