Android JNI使用方法(“动态注册”)

来源:互联网 发布:qq好友定位软件 编辑:程序博客网 时间:2024/05/22 02:15

此例示范了不适用JNI默认的接口绑定规则来实现C/C++方法的调用,此处称之为“动态注册”。


转自:http://www.open-open.com/lib/view/open1324909652374.html


经过几天的努力终于搞定了android JNI部分,下面将我的这个小程序和大家分享一下。android JNI是连接android Java部分和C/C++部分的纽带,完整使用JNI需要Java代码和C/C++代码。其中C/C++代码用于生成库文件,Java代码用于引用C /C++库文件以及调用C/C++方法。

android Java部分代码:

[cpp] view plaincopyprint?
  1. <span style="font-size: 18px;">jnitest.java 
  2.  
  3. package com.hello.jnitest; 
  4.  
  5.   
  6.  
  7. import android.app.Activity; 
  8.  
  9. import android.os.Bundle; 
  10.  
  11.   
  12.  
  13. public class jnitest extends Activity { 
  14.  
  15.     /** Called when the activity is first created. */ 
  16.  
  17.     @Override 
  18.  
  19.     public void onCreate(Bundle savedInstanceState) { 
  20.  
  21.         super.onCreate(savedInstanceState); 
  22.  
  23.         setContentView(R.layout.main); 
  24.  
  25.         Nadd test = new Nadd(); 
  26.  
  27.         setTitle("The Native Add Result is "+String.valueOf(test.nadd(10, 20))); 
  28.  
  29.     }  
  30.  
  31.  
  32. Nadd.java 
  33.  
  34. package com.hello.jnitest; 
  35.  
  36.   
  37.  
  38. public class Nadd { 
  39.  
  40. static
  41.  
  42. System.loadLibrary("hello_jni"); 
  43.  
  44.  
  45.   
  46.  
  47. public native int nadd(int a,int b); 
  48.  
  49. }</span> 


Java代码说明:
1)jnitest.java是一个activity的类对象,在该类对象中生成调用JNI函数的类对象,同时调用JNI方法,最后将JNI方法的结果显示到标题栏上;
2)Nadd.java是一个引用和声明JNI库和函数的类,其中System.loadLibrary();函数用来引用JNI库,默认JNI库放在 android系统的/system/lib/目录下;public nadd int nadd(int a, int b);为声明需要在java程序中使用的JNI库中的函数;
JNI中java部分的代码到此就结束了,总结一下在java代码中需要做两件事:
1)使用System.loadLibrary()函数来引用JNI库;
2)声明调用JNI库的函数且前面添加native关键字;


android C/C++部分代码:


[cpp] view plaincopyprint?
  1. <span style="font-size: 18px;">#define LOG_TAG"hello-JNI" 
  2. #include <stdio.h> 
  3. #include <stdlib.h> 
  4. #include <unistd.h> 
  5. #include <sys/types.h> 
  6. #include <sys/stat.h> 
  7. #include <fcntl.h> 
  8. #include <assert.h> 
  9. #include "jni.h" 
  10. #include "JNIHelp.h" 
  11. #include "android_runtime/AndroidRuntime.h" 
  12. static jint com_hello_jnitest_jnitest_nadd(JNIEnv *env, jobject obj, jint a, jint b) 
  13. return (a * b); 
  14. static JNINativeMethod gMethods[] = { 
  15. {"nadd", "(II)I", (void *)com_hello_jnitest_jnitest_nadd}, 
  16. }; 
  17. static int register_android_test_hello(JNIEnv *env) 
  18. return android::AndroidRuntime::registerNativeMethods(env,"com/hello/jnitest/Nadd", gMethods, NELEM(gMethods)); 
  19. jint JNI_OnLoad(JavaVM *vm, void *reserved) 
  20. JNIEnv *env = NULL; 
  21. if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) { 
  22. printf("Error GetEnv\n"); 
  23. return -1; 
  24. assert(env != NULL); 
  25. if (register_android_test_hello(env) < 0) { 
  26. printf("register_android_test_hello error.\n"); 
  27. return -1; 
  28. return JNI_VERSION_1_4; 
  29. }</span> 

JNI C/C++代码说明:
1)JNI_OnLoad()函数。该函数在Java程序调用System.loadLibrary()时,被调用执行,用于向JavaVM注册JNI函数等。在本例中首先通过参数JavaVM(Java虚拟机指针)获取当前应用程序所在的线程,即:JNIEnv。再通过调用 android::AndroidRuntime::registerNativeMethods()注册native实现的函数指针。
2)JNI函数和Java调用函数的映射关系。使用JNINativeMethod将java调用的函数名与JNI实现的函数名联系在一起;
3)JNI函数实现;

Android.mk代码:


[cpp] view plaincopyprint?
  1. LOCAL_PATH := $(call my-dir) 
  2. include $(CLEAR_VARS) 
  3. LOCAL_PRELINK_MODULE := false 
  4. LOCAL_SRC_FILES := \ 
  5. com_hello_jnitest.cpp 
  6. LOCAL_SHARED_LIBRARIES := \ 
  7. libandroid_runtime 
  8. LOCAL_MODULE := libhello_jni 
  9. include $(BUILD_SHARED_LIBRARY) 



需要注意的是:
1)JNI C/C++部分的代码需要在android源代码树上进行编译,编译完成后我的做法是直接将生成的.so通过adb push方法上传到android虚拟机的/system/lib/目录下;
2)java代码可以在eclipse下直接编译且在虚拟机上执行;

编译JNI C/C++部分代码(在android内核源代码根目录下):
#make libhello_jni
之后在out/target/product/generic/system/lib/目录下生成libhello_jni.so

上传libhello_jni.so到android虚拟机:
#adb push out/target/product/generic/system/lib/libhello_jni.so /system/lib
注意:此时有可能出现Out of Memory的错误提示。当出现如上错误提示时,需要使用#adb remount重新加载一下就可以了。
另外,也有可能直接使用eclipse启动android虚拟机时出现上述错误且使用#adb remount也出现的情况,此时需要手动启动android虚拟机,如:#emulator -avd xxx -partition-size 128,之后在使用#adb push就可以了。

0 0