1、通过Eclipse创建一个android项目SimpleJniPrj,package="com.example.android.simplejni"。
SimpleJNI.java:
- package com.example.android.simplejni;
- import android.app.Activity;
- import android.os.Bundle;
- import android.widget.TextView;
- public class SimpleJNI extends Activity {
-
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- TextView tv = new TextView(this);
- Native t = new Native();
- t.nativeInit();
- int sum = t.nativeAdd(2, 3);
- tv.setText("2 + 3 = " + Integer.toString(sum));
- tv.append("\n i = " + Integer.toString(t.getCallbackResult()));
- setContentView(tv);
- }
- }
- class Native{
- private int i=0;
-
- static {
- // The runtime will add "lib" on the front and ".o" on the end of
- // the name supplied to loadLibrary.
- System.loadLibrary("simplejni");
- }
-
- native void nativeInit();
-
- native int nativeAdd(int a, int b);
-
- public void callback(){
- i++;
- System.out.printf("java callback i=%d\n", i);
- }
-
- public int getCallbackResult(){
- return i;
- }
- }
在上面的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的描述:
- static JNINativeMethod methods[] = {
- {"nativeInit", "()V", (void*)init},
- {"nativeAdd", "(II)I", (void*)add},
- };
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;
JNINativeMethod是Java 和 C 函数的映射表结构体。第一个变量name是Java中函数的名字;第二个变量signature,用字符串是描述了函数的参数和返回值;第三个变量fnPtr是函数指针,指向C函数。其中,init和add为本地的方法,分别对应java中的nativeInit和nativeAdd方法。
- static jint
- add(JNIEnv *env, jobject thiz, jint a, jint b) {
- int result = a + b;
- LOGI("%d + %d = %d", a, b, result);
- jclass cls = env->GetObjectClass(thiz);
- LOGI("cls=0x%x", cls);
- jmethodID method_id = env->GetMethodID(cls, "callback", "()V");
- LOGI("method_id=0x%x",method_id);
- env->CallVoidMethod(thiz, method_id);
- return result;
- }
- static void
- init(JNIEnv *env, jobject thiz){
- gObject = env->NewWeakGlobalRef(thiz);
- LOGI("gObject=0x%x",gObject);
- }
方法add实现了将两个参数a和b相加并返回结果,同时调用了java域的callback方法,而参数env表示java运行的环境,thiz表示在java域中调用此方法的对象实例。java通过调用init方法初始化native运行环境,比如在此存储一个全局的对象。
3、通过JNI_OnLoad方法注册自定义的native方法到虚拟机中。
- jint JNI_OnLoad(JavaVM* vm, void* reserved)
- {
- UnionJNIEnvToVoid uenv;
- uenv.venv = NULL;
- jint result = -1;
- JNIEnv* env = NULL;
-
- LOGI("JNI_OnLoad");
-
- setJavaVM(vm);
- if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
- LOGE("ERROR: GetEnv failed");
- goto bail;
- }
- env = uenv.env;
- if (registerNatives(env) != JNI_TRUE) {
- LOGE("ERROR: registerNatives failed");
- goto bail;
- }
- result = JNI_VERSION_1_4;
-
- bail:
- return result;
- }
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项目,并运行