转载自http://mysuperbaby.iteye.com/blog/915425
Java调用Native模块
Hello-JNI这个示例的结构很简单:首先我们使用Eclipse新建一个OPhone应用的Java工程,并添加一个 com.example.hellojni.HelloJni的类。这个类实际上是一个Activity,稍后我们会创建一个TextView,并显示一 些文字在上面。
- /*Anativemethodthatisimplementedbythe
- *'hello-jni'nativelibrary,whichispackaged
- *withthisapplication.
- */
- publicnativeStringstringFromJNI();
- */
- nativeStringstringFromJNI();
#include<string.h>
#include<jni.h>
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv*env,
jobjectthiz){
return(*env)->NewStringUTF(env,"HellofromJNI!");
}
#include<jni.h>
"HellofromJNI!");
}
从上面Native函数的命名上我们可以了解到JNI函数的命名规则: Java代码中的函数声明需要添加
native关键 字;Native的对应函数名要以“Java_”开头,后面依次跟上Java的“package名”、“class名”、“函数名”,中间以下划线“_” 分割,在package名中的“.”也要改为“_”。此外,关于函数的参数和返回值也有相应的规则。对于Java中的基本类型如
int、
double、
char等,在Native端都有相对应的类型来表示,如
jint、
jdouble、
jchar等;其他的对象类型则统统由
jobject来表示(
String是个例外,由于其使用广泛,故在Native代码中有
jstring这个类型来表示,正如在上例中返回值
String对应到Native代码中的返回值
jstring)。而对于Java中的数组,在Native中由
jarray对应,具体到基本类型和一般对象类型的数组则有
jintArray等和
jobjectArray分别对应(
String数组在这里没有例外,同样用
jobjectArray表示)。还有一点需要注意的是,在JNI的Native函数中,其前两个参数
JNIEnv*和
jobject是必需的——前者是一个
JNIEnv结构体的指针,这个结构体中定义了很多JNI的接口函数指针,使开发者可以使用JNI所定义的接口功能;后者指代的是调用这个JNI函数的Java对象,有点类似于C++中的
this指针。在上述两个参数之后,还需要根据Java端的函数声明依次对应添加参数。在上例中,Java中声明的JNI函数没有参数,则Native的对应函数只有类型为
JNIEnv*和
jobject的两个参数。
static{
System.loadLibrary("hello-jni");
System.loadLibrary("hello-jni");
}
注意这里调用的共享库名遵循Linux对库文件的命名惯例,因为OPhone的核心实际上是Linux系统——上例中,实际加载的库文件应为 “libhello-jni.so”,在引用时遵循命名惯例,不带“lib”前缀和“.so”的扩展名。对于没有按照上述惯例命名的Native库,在加 载时仍需要写成完整的文件名。
TextViewtv=newTextView(this);
tv.setText(stringFromJNI());
setContentView(tv);
tv.setText(stringFromJNI());
setContentView(tv);
Native调用Java模块
从OPhone的系统架构来看,JVM和Native系统库位于内核之上,构成OPhone Runtime;更多的系统功能则是通过在其上的Application Framework以Java API的形式提供的。因此,如果希望在Native库中调用某些系统功能,就需要通过JNI来访问Application Framework提供的API。
packagecom.example.hellojni;
classSayHello{
publicStringsayHelloFromJava(StringnativeMsg){
Stringstr=nativeMsg+"ButshowninJava!";
returnstr;
}
classSayHello{
Stringstr=nativeMsg+"ButshowninJava!";
}
接下来要实现的就是在Native代码中调用这个
SayHello类中的sayHelloFromJava方法。
一般来说,要在Native代码中访问Java对象,有如下几个步骤:
1.得到该Java对象的类定义。JNI定义了
jclass这个类型来表示Java的类的定义,并提供了FindClass接口,根据类的完整的包路径即可得到其
jclass。
2.根据
jclass创建相应的对象实体,即
jobject。在Java中,创建一个新对象只需要使用
new关键字即可,但在Native代码中创建一个对象则需要两步:首先通过JNI接口GetMethodID得到该类的构造函数,然后利用NewObject接口构造出该类的一个实例对象。
3.访问
jobject中的成员变量或方法。访问对象的方法是先得到方法的Method ID,然后使用Call<
Type>Method 接口调用,这里Type对应相应方法的返回值——返回值为基本类型的都有相对应的接口,如CallIntMethod;其他的返回值(包括String) 则为CallObjectMethod。可以看出,创建对象实质上是调用对象的一个特殊方法,即构造函数。访问成员变量的步骤一样:首先 GetFieldID得到成员变量的ID,然后Get/Set<
Type>Field读/写变量值。
jstringhelloFromJava(JNIEnv*env){
jstringstr=NULL;
jclassclz=(*env)->FindClass(env,"com/example/hellojni/SayHello");
jmethodIDctor=(*env)->GetMethodID(env,clz,"<init>","()V");
jobjectobj=(*env)->NewObject(env,ctor);
jmethodIDmid=(*env)->GetMethodID(env,"sayHelloFromJava","(Ljava/lang/String;)Ljava/lang/String;");
if(mid){
jstringjmsg=(*env)->NewStringUTF(env,"I'mborninnative.");
str=(*env)->CallObjectMethod(env,obj,mid,jmsg);
}
returnstr;
jstringstr=NULL;
"()V");
"(Ljava/lang/String;)Ljava/lang/String;");
"I'mborninnative.");
可以看到,上述代码和前面讲到的步骤完全相符。这里提一下编程时要注意的要点:1、FindClass要写明Java类的完整包路径,并将 “.”以“/”替换;2、GetMethodID的第三个参数是方法名(对于构造函数一律用“<init>”表示),第四个参数是方法的“签 名”,需要用一个字符串序列表示方法的参数(依声明顺序)和返回值信息。由于篇幅所限,这里不再具体说明如何根据方法的声明构造相应的“签名”,请参考 JNI的相关文档。
原文链接:https://www.f2er.com/cocos2dx/341077.html