cocos2dx调用android代码,android调用c

转载自http://mysuperbaby.iteye.com/blog/915425

Java调用Native模块
Hello-JNI这个示例的结构很简单:首先我们使用Eclipse新建一个OPhone应用的Java工程,并添加一个 com.example.hellojni.HelloJni的类。这个类实际上是一个Activity,稍后我们会创建一个TextView,并显示一 些文字在上面。
要在Java代码中使用Native模块,必须先对Native函数进行声明。在我们的例子中,打开HelloJni.java文件,可以看到如下的声明:
 
  1. /* A native method that is implemented by the  
  2.    * 'hello-jni' native library, which is packaged  
  3.    * with this application.  
  4.    */   
  5.   public   native  String  stringFromJNI();  
Java代码   收藏代码
  1. /* A native method that is implemented by the 
  2.    * 'hello-jni' native library, which is packaged 
  3.    * with this application. 
  4.    */  
  5.   public native String  stringFromJNI();  
  
从上述声明中我们可以知道,这个stringFromJNI()函数就是要在Java代码中调用的Native函数。接下来我们要创建一个hello-jni.c的C文件,内容很简单,只有如下一个函数:
 
 
  1. #include <string.h>  
  2. #include <jni.h>  
  3. jstring  
  4. Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,  
  5.                                                  jobject thiz ) {  
  6.         return  (*env)->NewStringUTF(env,  "Hello from JNI !" );  
  7. }  
Java代码   收藏代码
  1. #include <string.h>  
  2. #include <jni.h>  
  3. jstring  
  4. Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,  
  5.                                                  jobject thiz ) {  
  6.         return (*env)->NewStringUTF(env, "Hello from JNI !");  
  7. }  

 

从函数名可以看出,这个Native函数对应的正是我们在com.example.hellojni.HelloJni这个中声明的Native函数String stringFromJNI()的具体实现。
 
从上面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 的两个参数。
 
当然,要使用JNI函数,还需要先加载Native代码编译出来的动态库文件(在Windows上是.dll,在Linux上则为.so)。这个动作是通过如下语句完成的:
 
  1. static  {  
  2.     System.loadLibrary("hello-jni" );  
  3. }  
Java代码   收藏代码
  1. static {  
  2.     System.loadLibrary("hello-jni");  
  3. }  
 
注意这里调用的共享库名遵循Linux对库文件的命名惯例,因为OPhone的核心实际上是Linux系统——上例中,实际加载的库文件应为 “libhello-jni.so”,在引用时遵循命名惯例,不带“lib”前缀和“.so”的扩展名。对于没有按照上述惯例命名的Native库,在加 载时仍需要写成完整的文件名。
 
JNI函数的使用方法和普通Java函数一样。在本例中,调用代码如下:
 
  1. TextView tv =  new  TextView( this );  
  2. tv.setText( stringFromJNI() );  
  3. setContentView(tv);  
Java代码   收藏代码
  1. TextView tv = new TextView(this);  
  2. tv.setText( stringFromJNI() );  
  3. setContentView(tv);  
 
就可以在TextView中显示出来自于Native函数的字符串。怎么样,是不是很简单呢?
 
Native调用Java模块
从OPhone的系统架构来看,JVM和Native系统库位于内核之上,构成OPhone Runtime;更多的系统功能则是通过在其上的Application Framework以Java API的形式提供的。因此,如果希望在Native库中调用某些系统功能,就需要通过JNI来访问Application Framework提供的API。
 
JNI规范定义了一系列在Native代码中访问Java对象及其成员与方法的API。下面我们还是通过示例来具体讲解。首先,新建一个 SayHello 的类,代码如下:
 
  1. package  com.example.hellojni;  
  2. public   class  SayHello {  
  3.         public  String sayHelloFromJava(String nativeMsg) {  
  4.                String str = nativeMsg + " But shown in Java!" ;  
  5.                return  str;  
  6.         }  
  7. }  
Java代码   收藏代码
  1. package com.example.hellojni;  
  2. public class SayHello {  
  3.         public String sayHelloFromJava(String nativeMsg) {  
  4.                String str = nativeMsg + " But shown in Java!";  
  5.                return str;  
  6.         }  
  7. }  
 
接下来要实现的就是在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读/写变量值。
 
上面概要介绍了从Native代码中访问Java对象的过程,下面我们结合示例来具体看一下。如下是调用sayHelloFromJava方法的Native代码:
 
  1. jstring helloFromJava( JNIEnv* env ) {  
  2.        jstring str = NULL;  
  3.        jclass clz = (*env)->FindClass(env, "com/example/hellojni/SayHello" );  
  4.        jmethodID ctor = (*env)->GetMethodID(env, clz, "<init>" ,  "()V" );  
  5.        jobject obj = (*env)->NewObject(env, clz, ctor);  
  6.        jmethodID mid = (*env)->GetMethodID(env, clz, "sayHelloFromJava" ,  "(Ljava/lang/String;)Ljava/lang/String;" );  
  7.        if  (mid) {  
  8.               jstring jmsg = (*env)->NewStringUTF(env, "I'm born in native." );  
  9.               str = (*env)->CallObjectMethod(env, obj, mid, jmsg);  
  10.        }  
  11.        return  str;  
  12. }  
Java代码   收藏代码
  1. jstring helloFromJava( JNIEnv* env ) {  
  2.        jstring str = NULL;  
  3.        jclass clz = (*env)->FindClass(env, "com/example/hellojni/SayHello");  
  4.        jmethodID ctor = (*env)->GetMethodID(env, clz, "<init>""()V");  
  5.        jobject obj = (*env)->NewObject(env, clz, ctor);  
  6.        jmethodID mid = (*env)->GetMethodID(env, clz, "sayHelloFromJava""(Ljava/lang/String;)Ljava/lang/String;");  
  7.        if (mid) {  
  8.               jstring jmsg = (*env)->NewStringUTF(env, "I'm born in native.");  
  9.               str = (*env)->CallObjectMethod(env, obj, mid, jmsg);  
  10.        }  
  11.        return str;  
  12. }  
 
 
可以看到,上述代码和前面讲到的步骤完全相符。这里提一下编程时要注意的要点:1、FindClass要写明Java类的完整包路径,并将 “.”以“/”替换;2、GetMethodID的第三个参数是方法名(对于构造函数一律用“<init>”表示),第四个参数是方法的“签 名”,需要用一个字符串序列表示方法的参数(依声明顺序)和返回值信息。由于篇幅所限,这里不再具体说明如何根据方法的声明构造相应的“签名”,请参考 JNI的相关文档。
 
关于上面谈到的步骤再补充说明一下:在JNI规范中,如上这种使用NewObject创建的对象实例被称为“Local Reference”,它仅在创建它的Native代码作用域内有效,因此应避免在作用域外使用该实例及任何指向它的指针。如果希望创建的对象实例在作用 域外也能使用,则需要使用NewGlobalRef接口将其提升为“Global Reference”——需要注意的是,当Global Reference不再使用后,需要显式的释放,以便通知JVM进行垃圾收集。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值