Android JNI使用方法

jopen 13年前
     <p>经过几天的努力终于搞定了android JNI部分,下面将我的这个小程序和大家分享一下。android JNI是连接android Java部分和C/C++部分的纽带,完整使用JNI需要Java代码和C/C++代码。其中C/C++代码用于生成库文件,Java代码用于引用C /C++库文件以及调用C/C++方法。</p>    <p>android Java部分代码:</p>    <pre class="brush:java; toolbar: true; auto-links: false;">jnitest.java  package com.hello.jnitest;     import android.app.Activity;  import android.os.Bundle;     public class jnitest extends Activity {      /** Called when the activity is first created. */      @Override      public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.main);          Nadd test = new Nadd();          setTitle("The Native Add Result is "+String.valueOf(test.nadd(10, 20)));      }   }  Nadd.java  package com.hello.jnitest;     public class Nadd {  static {  System.loadLibrary("hello_jni");  }     public native int nadd(int a, int b);  }</pre>    <br />    <div>     Java代码说明:    </div>    <div>     1)jnitest.java是一个activity的类对象,在该类对象中生成调用JNI函数的类对象,同时调用JNI方法,最后将JNI方法的结果显示到标题栏上;    </div>    <div>     2)Nadd.java是一个引用和声明JNI库和函数的类,其中System.loadLibrary();函数用来引用JNI库,默认JNI库放在 android系统的/system/lib/目录下;public nadd int nadd(int a, int b);为声明需要在java程序中使用的JNI库中的函数;    </div>    <div>     JNI中java部分的代码到此就结束了,总结一下在java代码中需要做两件事:    </div>    <div>     1)使用System.loadLibrary()函数来引用JNI库;    </div>    <div>     2)声明调用JNI库的函数且前面添加native关键字;    </div>    <div>     <br />    </div>    <div>     android C/C++部分代码:    </div>    <pre class="brush:cpp; toolbar: true; auto-links: false;">#define LOG_TAG "hello-JNI" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <assert.h> #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" static jint com_hello_jnitest_jnitest_nadd(JNIEnv *env, jobject obj, jint a, jint b) { return (a * b); } static JNINativeMethod gMethods[] = { {"nadd", "(II)I", (void *)com_hello_jnitest_jnitest_nadd}, }; static int register_android_test_hello(JNIEnv *env) { return android::AndroidRuntime::registerNativeMethods(env, "com/hello/jnitest/Nadd", gMethods, NELEM(gMethods)); } jint JNI_OnLoad(JavaVM *vm, void *reserved) { JNIEnv *env = NULL; if (vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK) { printf("Error GetEnv\n"); return -1; } assert(env != NULL); if (register_android_test_hello(env) < 0) { printf("register_android_test_hello error.\n"); return -1; } return JNI_VERSION_1_4; }</pre>    <br />    <div>     JNI C/C++代码说明:    </div>    <div>     1)JNI_OnLoad()函数。该函数在Java程序调用System.loadLibrary()时,被调用执行,用于向JavaVM注册JNI函数等。在本例中首先通过参数JavaVM(Java虚拟机指针)获取当前应用程序所在的线程,即:JNIEnv。再通过调用 android::AndroidRuntime::registerNativeMethods()注册native实现的函数指针。    </div>    <div>     2)JNI函数和Java调用函数的映射关系。使用JNINativeMethod将java调用的函数名与JNI实现的函数名联系在一起;    </div>    <div>     3)JNI函数实现;    </div>    <div>     <br />    </div>    <div>     Android.mk代码:    </div>    <div>     <pre class="brush:cpp; toolbar: true; auto-links: false;">LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_PRELINK_MODULE := false LOCAL_SRC_FILES := \ com_hello_jnitest.cpp LOCAL_SHARED_LIBRARIES := \ libandroid_runtime LOCAL_MODULE := libhello_jni include $(BUILD_SHARED_LIBRARY)</pre>    </div>    <div>     <br />    </div>    <div>     需要注意的是:    </div>    <div>     1)JNI C/C++部分的代码需要在android源代码树上进行编译,编译完成后我的做法是直接将生成的.so通过adb push方法上传到android虚拟机的/system/lib/目录下;    </div>    <div>     2)java代码可以在eclipse下直接编译且在虚拟机上执行;    </div>    <div>     <br />    </div>    <div>     编译JNI C/C++部分代码(在android内核源代码根目录下):    </div>    <div>     #make libhello_jni    </div>    <div>     之后在out/target/product/generic/system/lib/目录下生成libhello_jni.so    </div>    <div>     <br />    </div>    <div>     上传libhello_jni.so到android虚拟机:    </div>    <div>     #adb push out/target/product/generic/system/lib/libhello_jni.so /system/lib    </div>    <div>     注意:此时有可能出现Out of Memory的错误提示。当出现如上错误提示时,需要使用#adb remount重新加载一下就可以了。    </div>    <div>     另外,也有可能直接使用eclipse启动android虚拟机时出现上述错误且使用#adb remount也出现的情况,此时需要手动启动android虚拟机,如:#emulator -avd xxx -partition-size 128,之后在使用#adb push就可以了。    </div>