Android开发之JNI调用本地C库专题(一):JNI的使用
JNI,是用于开发本地C函数库的技术。用于链接JAVA和C或者C++语言的桥梁。在部分android项目开发中,我们是需要用到这项技术的。那么废话不多说,进入正题。
开发JNI,需要用到NDK,这个大家应该都知道了。还需要一个linux的开发环境。一般而言,可以使用虚拟机装一个ubantu,博主以前就是搞linux开发的,这点还是比较熟悉。但是对于大部分android开发者而言,弄一个虚拟机成本太高。那么,我们需要搭建一个模拟linux的开发环境。这个博主就不说了,直接上链接
以上博文其实只需要做完第三步即可,如果是下载安装谷歌官方集成的eclipse,第三步都可以不用做了。
好,当一切东西都准备好了之后,我们以一个例子来讲解如何开发一个JNI项目。
一、新建一个Android项目
二、C语言方法实现。
1、新建本地native方法
public class DataProvider { public native int add(int x, int y); // public native String sayHelloInC(String s); public native int[] intMethod(int[] iNum); }
2、编译native方法
3、创建JNI目录
4、编写.c文件
#include <stdio.h> #include "com_example_ndkpassdata_DataProvider.h" #include <android/log.h> #include <string.h> #define LOG_TAG "clog" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) //将java语言中的字符串格式转换为C语言中的字符串格式。 char* Jstring2CStr(JNIEnv* env, jstring jstr) { char* rtn = NULL; jclass clsstring = (*env)->FindClass(env, "java/lang/String"); jstring strencode = (*env)->NewStringUTF(env, "GB2312"); jmethodID mid = (*env)->GetMethodID(env, clsstring, "getBytes", "(Ljava/lang/String;)[B"); jbyteArray barr = (jbyteArray)(*env)->CallObjectMethod(env, jstr, mid, strencode); // String .getByte("GB2312"); jsize alen = (*env)->GetArrayLength(env, barr); jbyte* ba = (*env)->GetByteArrayElements(env, barr, JNI_FALSE); if (alen > 0) { rtn = (char*) malloc(alen + 1); //"\0" memcpy(rtn, ba, alen); rtn[alen] = 0; } (*env)->ReleaseByteArrayElements(env, barr, ba, 0); // return rtn; } JNIEXPORT jint JNICALL Java_com_example_ndkpassdata_DataProvider_add( JNIEnv * env, jobject jobject, jint x, jint y) { // 想在logcat控制台上 打印日志 LOGD("x=%d", x); LOGI("y=%d", y); // log.i(TAG,"sss"); return x + y; } JNIEXPORT jstring JNICALL Java_com_example_ndkpassdata_DataProvider_sayHelloInC( JNIEnv * env, jobject jobject, jstring str) { char* c = "hello"; // 在C语言中不能直接操作java中的字符串 // 把java中的字符串转换成c语言中 char数组 char* cstr = Jstring2CStr(env, str); strcat(cstr, c); LOGD("%s", cstr); return (*env)->NewStringUTF(env, cstr); } JNIEXPORT jintArray JNICALL Java_com_example_ndkpassdata_DataProvider_intMethod( JNIEnv * env, jobject jobject, jintArray jarray) { // jArray 遍历数组 jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*); // 数组的长度 jsize (*GetArrayLength)(JNIEnv*, jarray); // 对数组中每个元素 +5 int length = (*env)->GetArrayLength(env, jarray); //拿到指针初始位置 int* array = (*env)->GetIntArrayElements(env, jarray, 0); int i = 0; for (; i < length; i++) { *(array + i) += 5; } return jarray; }
5、编写android.mk文件
LOCAL_PATH := $(call my-dir) // 返回当前c代码目录
include $(CLEAR_VARS) // 清楚了所有 已local 开头的配置文件 唯独不清楚LOCAL_PATH
LOCAL_MODULE := hello // 库函数的名字 严格遵守makefile 格式 lib .so 如果前面加lib 不会自动生成了
LOCAL_SRC_FILES := Hello.c //源文件名称,就是刚刚新建的那个.c文件的名称。
include $(BUILD_SHARED_LIBRARY) // 加入库函数
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libhello LOCAL_SRC_FILES := Hello.c LOCAL_LDLIBS += -llog include $(BUILD_SHARED_LIBRARY)
6、编译C文件
当android文件写好之后,一切的准备工作都已经就绪,这个时候我们只需要调用NDK去编译该项目即可上次.so动态库文件。这个时候需要启动Cygwin,然后来到该项目的目录下,调用ndk-build命令即可。过程如图所示:三、C语言函数库方法调用
public class MainActivity extends Activity { DataProvider provider; static { System.loadLibrary("hello"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); provider = new DataProvider(); } public void click1(View view) { int result = provider.add(6, 8); System.out.println(result); } public void click2(View view) { String str = provider.sayHelloInC("freedom"); Toast.makeText(getApplicationContext(), str, 0).show(); } public void click3(View view) { int[] arr = new int[] { 5, 6, 7, 8, 9 }; provider.intMethod(arr); for (int i : arr) { System.out.println(i); } } }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。