android jni (2) java与c++相互调用

来源:互联网 发布:kali linux arp攻击 编辑:程序博客网 时间:2024/05/05 19:49

1、通过Eclipse创建一个android项目SimpleJniPrj,package="com.example.android.simplejni"。

SimpleJNI.java:
  1. package com.example.android.simplejni;

  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.widget.TextView;

  5. public class SimpleJNIextends Activity{
  6.    
  7.     /** Called when the activity is first created. */
  8.     @Override
  9.     public void onCreate(Bundle savedInstanceState){
  10.         super.onCreate(savedInstanceState);
  11.         TextView tv = new TextView(this);
  12.         Native t =new Native();
  13.         t.nativeInit();
  14.         int sum= t.nativeAdd(2, 3);
  15.         tv.setText("2 + 3 = "+ Integer.toString(sum));
  16.         tv.append("\n i = "+ Integer.toString(t.getCallbackResult()));
  17.         setContentView(tv);
  18.     }
  19. }

  20. class Native{
  21.     private int i=0;
  22.    
  23.     static {
  24.         // The runtime will add "lib" on the front and ".o" on the end of
  25.         // the name supplied to loadLibrary.
  26.         System.loadLibrary("simplejni");
  27.     }
  28.    
  29.     native void nativeInit();
  30.    
  31.     native int nativeAdd(int a,int b);
  32.    
  33.     public voidcallback(){
  34.         i++;
  35.         System.out.printf("java callback i=%d\n", i);
  36.     }
  37.    
  38.     public int getCallbackResult(){
  39.         return i;
  40.     }
  41. }
在上面的java文件中,实现了一个SimpleJNI Activity类和一个Native类。Native类实现了native库的加载、native方法的声明和callback方法(被C++调用)的实现。Simple类通过实例Native对象,调用Native类中的native方法。

2、在C++中实现native方法。实现native方法需要通过javah产生native方法的头文件,但是,这样生成的C++的native方法名称可读性差,不方便使用。利用通过System.loadLibrary加载native库时JNI_OnLoad将被调用的特性,通过实现JNI_OnLoad方法将自定义C++中的native方法注册到虚拟机中。从而实现对自主定义native方法名。
下面是关于native.cpp的描述:
  1. static JNINativeMethod methods[]= {
  2.   {"nativeInit","()V", (void*)init},
  3.   {"nativeAdd","(II)I", (void*)add},
  4. };

typedef struct {

const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;

JNINativeMethod是Java 和 C 函数的映射表结构体。第一个变量name是Java中函数的名字;第二个变量signature,用字符串是描述了函数的参数和返回值;第三个变量fnPtr是函数指针,指向C函数。其中,init和add为本地的方法,分别对应java中的nativeInit和nativeAdd方法。

  1. static jint
  2. add(JNIEnv *env, jobject thiz, jint a, jint b){
  3. int result = a+ b;
  4.     LOGI("%d + %d = %d", a, b, result);

  5.     jclass cls = env->GetObjectClass(thiz);
  6.     LOGI("cls=0x%x", cls);

  7.     jmethodID method_id = env->GetMethodID(cls,"callback", "()V");
  8.     LOGI("method_id=0x%x",method_id);

  9.     env->CallVoidMethod(thiz, method_id);

  10.     return result;
  11. }

  12. static void
  13. init(JNIEnv *env, jobject thiz){
  14.     gObject = env->NewWeakGlobalRef(thiz);
  15.     LOGI("gObject=0x%x",gObject);
  16. }

方法add实现了将两个参数a和b相加并返回结果,同时调用了java域的callback方法,而参数env表示java运行的环境,thiz表示在java域中调用此方法的对象实例。java通过调用init方法初始化native运行环境,比如在此存储一个全局的对象。

3、通过JNI_OnLoad方法注册自定义的native方法到虚拟机中。
  1. jint JNI_OnLoad(JavaVM* vm, void* reserved)
  2. {
  3.     UnionJNIEnvToVoid uenv;
  4.     uenv.venv =NULL;
  5.     jint result = -1;
  6.     JNIEnv* env =NULL;
  7.    
  8.     LOGI("JNI_OnLoad");
  9.    
  10.     setJavaVM(vm);

  11.     if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK){
  12.         LOGE("ERROR: GetEnv failed");
  13.         goto bail;
  14.     }
  15.     env = uenv.env;

  16.     if (registerNatives(env)!= JNI_TRUE){
  17.         LOGE("ERROR: registerNatives failed");
  18.         goto bail;
  19.     }
  20.     result = JNI_VERSION_1_4;
  21.    
  22. bail:
  23.     return result;
  24. }

static const char *classPathName = "com/example/android/simplejni/Native";

static int registerNatives(JNIEnv* env)
{
  if (!registerNativeMethods(env, classPathName,
                 methods, sizeof(methods) / sizeof(methods[0]))) {
    return JNI_FALSE;
  }

  return JNI_TRUE;
}


/*
* Register several native methods for one class.
*/
static int registerNativeMethods(JNIEnv* env, const char* className,
    JNINativeMethod* gMethods, int numMethods)
{
    jclass clazz;

    clazz = env->FindClass(className);
    if (clazz == NULL) {
        LOGE("Native registration unable to find class '%s'", className);
        return JNI_FALSE;
    }
    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
        LOGE("RegisterNatives failed for '%s'", className);
        return JNI_FALSE;
    }

    return JNI_TRUE;
 
 
4、使用NDK编译native.cpp生成的libsimplejni.so,并将其拷贝到java项目中的SimpleJNI\libs\armeabi中。最后编译java项目,并运行
 
 
来自http://blog.chinaunix.net/uid-7448773-id-310170.html

原创粉丝点击