http://zhidao.baidu.com/link?url=0BGq9nfwWoXaXi9-mL-btbxfTG1-OHyt7iR0Jqlg99aillKUrzHCNtEVmkgZJ5FNee1m3L2ngNSEFF2mALSO4PnRfAp7ccexR_G5Fe2Fv87
android JNI是连接android Java部分和C/C++部分的纽带,完整使用JNI需要Java代码和C/C++代码。其中C/C++代码用于生成库文件,Java代码用于引用C /C++库文件以及调用C/C++方法。
android Java部分代码:
jnitest.java 02 03 package com.hello.jnitest; 04 05 06 07 import android.app.Activity; 08 09 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 33 Nadd.java 34 35 package com.hello.jnitest; 36 37 38 39 public class Nadd { 40 41 static { 42 43 System.loadLibrary( "hello_jni" ); 44 45 } 46 47 48 49 public native int nadd( int a, int b); 50 51 } |
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++部分代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
01 #define LOG_TAG "hello-JNI" 02 #include <stdio.h> 03 #include <stdlib.h> 04 #include <unistd.h> 05 #include <sys/types.h> 06 #include <sys/stat.h> 07 #include <fcntl.h> 08 #include < assert .h> 09 #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 { 14 return (a * b); 15 } 16 static JNINativeMethod gMethods[] = { 17 { "nadd" , "(II)I" , ( void *)com_hello_jnitest_jnitest_nadd}, 18 }; 19 static int register_android_test_hello(JNIEnv *env) 20 { 21 return android::AndroidRuntime::registerNativeMethods(env, "com/hello/jnitest/Nadd" , gMethods, NELEM(gMethods)); 22 } 23 jint JNI_OnLoad(JavaVM *vm, void *reserved) 24 { 25 JNIEnv *env = NULL; 26 if (vm->GetEnv(( void **)&env, JNI_VERSION_1_4) != JNI_OK) { 27 printf ( "Error GetEnv\n" ); 28 return -1; 29 } 30 assert (env != NULL); 31 if (register_android_test_hello(env) < 0) { 32 printf ( "register_android_test_hello error.\n" ); 33 return -1; 34 } 35 return JNI_VERSION_1_4; 36 } |
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代码:
1
2
3
4
5
6
7
8
9
|
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就可以了。