android windows 上JNI编程
2015-06-24 12:13
381 查看
昨天学习windows上的JNI编程,JNI说白了就是java和c语言的一个互相沟通的桥梁,java可以调用JNI来完成调用C语言实现的方法。JNI的全称是(Java native interface),其实在编程重你只需要将与java交互的函数写出来,其他的C语言内部调用的就可以直接使用C语言相关语法了。闲话少说,开始正题吧。
要想在windroid或者是linux上使用JNI必须要下载NDK的并且指定路径,在windows我们还需要安装一个sygwin,这里我就不再说怎样安装cygwin了,在你安装好的cygwin文件夹中找到一个etc的文件夹,在这个文件中找到一个profile文件,修改其中的Path后加上:(ndk的路径),在我理解ndk就是构建出了一个重pc到android的一个交叉编译环境,当然它里面还有很多我不知道的,还有待探索。然后我们就可以开始使用了,当然你要是用eclipse写C/C++还需要安装cdt插件。安装过后就可以使用eclipse编写c/c++的代码了。
下面我们来看看代码怎样编写吧,首先我们在android工程中创建一个jni的文件夹,在jni的文件夹中创建c语言的源文件,在android中穿件一个类,类中可以使用native标识创建函数例如下面:
这些都是使用javah后自动生成的。下一步我将该在c语言中是实现这些函数了,在此之前还需要创建一个mk文件,这个文件就是makefile,C语言在编译成库的情况下就可以读取makefile来编译。
执行函数有不同的call函数,例如返回值是int是CallIntMethod(env, obj, mid, 3, 5);空类型是CallVoidMethod(env, obj, mid);后面的()V是函数签名,代表是返回值是void型,无参的函数。(II)I返回值是int型参数是两个int值得函数。c语言编写后要在工程的src目录下运行ndk-bulid命令就可以生成一个c语言库,在eclipse工程目录中也有显示。
在每次编译之前需要删除obj文件夹,以清除缓存。
jni对于一些可以很大的提高java代码的隐秘性,而且使用c语言开发jni程序可以提高效率。
要想在windroid或者是linux上使用JNI必须要下载NDK的并且指定路径,在windows我们还需要安装一个sygwin,这里我就不再说怎样安装cygwin了,在你安装好的cygwin文件夹中找到一个etc的文件夹,在这个文件中找到一个profile文件,修改其中的Path后加上:(ndk的路径),在我理解ndk就是构建出了一个重pc到android的一个交叉编译环境,当然它里面还有很多我不知道的,还有待探索。然后我们就可以开始使用了,当然你要是用eclipse写C/C++还需要安装cdt插件。安装过后就可以使用eclipse编写c/c++的代码了。
下面我们来看看代码怎样编写吧,首先我们在android工程中创建一个jni的文件夹,在jni的文件夹中创建c语言的源文件,在android中穿件一个类,类中可以使用native标识创建函数例如下面:
public class DataProvider { //带参数的c语言调用java语言 public int add2( int x, int y){ return x + y; } //无参数的函数C语言调用java语言 public void show(){ System.out.println( "我被调用了啊" ); } //无参数的静态函数C语言调用java语言 public static void show2(){ System.out.println( "我又被调用了啊" ); } //将函数使用native标识,可以自动生成相应的函数 public native int add(int x, int y); public native int sayHello( String hello ); public native int[] array(int[] arr); public native int callbackadd2(); public native void callbackshow(); public native static void callbackshow2(); public native void callbackshow3(); } 将这个类写好了就可以使用javah (类的全类名), 全类名是指包名+类名,例如com.example.testjni.DataProvider,这样就可以生成一个c语言中使用的头文件例如: /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_testjni_DataProvider */ #ifndef _Included_com_example_testjni_DataProvider #define _Included_com_example_testjni_DataProvider #ifdef __cplusplus extern "C" { #endif /* * Class: com_example_testjni_DataProvider * Method: add * Signature: (II)I */ JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_add (JNIEnv *, jobject, jint, jint); /* * Class: com_example_testjni_DataProvider * Method: sayHello * Signature: (Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_sayHello (JNIEnv *, jobject, jstring); /* * Class: com_example_testjni_DataProvider * Method: array * Signature: ([I)[I */ JNIEXPORT jintArray JNICALL Java_com_example_testjni_DataProvider_array (JNIEnv *, jobject, jintArray); /* * Class: com_example_testjni_DataProvider * Method: callbackadd2 * Signature: ()I */ JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_callbackadd2 (JNIEnv *, jobject); /* * Class: com_example_testjni_DataProvider * Method: callbackshow * Signature: ()V */ JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow (JNIEnv *, jobject); /* * Class: com_example_testjni_DataProvider * Method: callbackshow2 * Signature: ()V */ JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow2 (JNIEnv *env, jclass); /* * Class: com_example_testjni_DataProvider * Method: callbackshow3 * Signature: ()V */ JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow3 (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
这些都是使用javah后自动生成的。下一步我将该在c语言中是实现这些函数了,在此之前还需要创建一个mk文件,这个文件就是makefile,C语言在编译成库的情况下就可以读取makefile来编译。
mk文件: LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) #对应的c语言的函数库 LOCAL_MODULE := hello #对应c代码的文件 LOCAL_SRC_FILES := hello.c functions.c LOCAL_LDLIBS := -llog//使用本地库 include $(BUILD_SHARED_LIBRARY) #include <stdio.h> #include "com_example_testjni_DataProvider.h" //引用头文件 #include <android/log.h> //打印的日志 const char *TAG = "clog"; #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__ ); #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__ ); //使用log头文件中的函数打印日志到eclipse中的logcat,在这里需要在mk文件中添加库引用,LOCAL_LDLIBS += -llog JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_add (JNIEnv *env, jobject o, jint x, jint y) { LOGI("%d\n", x ); LOGD("%d\n", y ); return x + y; //直接返回就可以 } //int print(jintArray localarray, int i); int print( int* localarray, int i ) { LOGD( "array = %d\n", *(localarray+i)); return 0; }//平常的c语言代码,可以直接调用 /* * Class: com_example_testjni_DataProvider * Method: sayHello * Signature: (Ljava/lang/String;)I */ JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_sayHello (JNIEnv *env, jobject o, jstring hello) { } /* * Class: com_example_testjni_DataProvider * Method: array * Signature: ([I)[I */ JNIEXPORT jintArray JNICALL Java_com_example_testjni_DataProvider_array (JNIEnv *env, jobject obj, jintArray array )//传的是一个java中int型数组,java调用c语言 { //获得数组长度 int length = (*env)->GetArrayLength(env, array); int i; jint* localarray = (*env)->GetIntArrayElements(env, array, 0); for( i = 0; i < length; i++ ){ *(localarray+i) += 5; print( localarray, i ); } return array; } /* * Class: com_example_testjni_DataProvider * Method: callbackadd2 * Signature: ()I */ JNIEXPORT jint JNICALL Java_com_example_testjni_DataProvider_callbackadd2 (JNIEnv *env, jobject obj) { jclass clazz = (*env)->FindClass(env, "com/example/testjni/DataProvider"); jmethodID mid = (*env)->GetMethodID(env, clazz, "add2", "(II)I"); return (*env)->CallIntMethod(env, obj, mid, 3, 5); } /* * Class: com_example_testjni_DataProvider * Method: callbackshow * Signature: ()V */ JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow (JNIEnv *env, jobject obj) { jclass clazz = (*env)->FindClass(env, "com/example/testjni/DataProvider"); jmethodID mid = (*env)->GetMethodID(env, clazz, "show", "()V");// (*env)->CallVoidMethod(env, obj, mid); } /* * Class: com_example_testjni_DataProvider * Method: callbackshow2 * Signature: ()V */ JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow2 (JNIEnv *env, jclass jc) { jmethodID mid = (*env)->GetStaticMethodID(env, jc, "show2", "()V"); jobject obj = (*env)->CallStaticObjectMethod(env, jc, mid); (*env)->CallVoidMethod(env, obj, mid); } /* * Class: com_example_testjni_DataProvider * Method: callbackshow3 * Signature: ()V */ JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow3 (JNIEnv *env, jobject obj) { jclass clazz = (*env)->FindClass(env, "com/example/testjni/DataProvider"); jmethodID mid = (*env)->GetStaticMethodID(env, clazz, "show2", "()V"); (*env)->CallVoidMethod(env, obj, mid); } java调用C语言将java传过来的值,使用jni的方法进行处理,然后使用,返回,c语言调用java需要在C语言代码中进行映射,例如: JNIEXPORT void JNICALL Java_com_example_testjni_DataProvider_callbackshow3 (JNIEnv *env, jobject obj) { jclass clazz = (*env)->FindClass(env, "com/example/testjni/DataProvider");//得到类的字节码 jmethodID mid = (*env)->GetStaticMethodID(env, clazz, "show2", "()V");//得到函数的id (*env)->CallVoidMethod(env, obj, mid);//执行函数 }
执行函数有不同的call函数,例如返回值是int是CallIntMethod(env, obj, mid, 3, 5);空类型是CallVoidMethod(env, obj, mid);后面的()V是函数签名,代表是返回值是void型,无参的函数。(II)I返回值是int型参数是两个int值得函数。c语言编写后要在工程的src目录下运行ndk-bulid命令就可以生成一个c语言库,在eclipse工程目录中也有显示。
在每次编译之前需要删除obj文件夹,以清除缓存。
jni对于一些可以很大的提高java代码的隐秘性,而且使用c语言开发jni程序可以提高效率。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories