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

android Java部分代码:








​01​

​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++部分代码:








​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​

​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就可以了。