Android ndk开发
前言:我对C/C++是没有任何基础的,虽然大学中学了一个学期的C但是都算还给老师了。这篇文章是我做一个NDK项目积累下来的知识,可以说是一篇小白上手文章,所以高手请自行绕路。
1、准备
做NDK开发是非常要注意开发环境和开发版本的(个人认为)。我使用的是Eclipse (Luna 4.4.0),NDK版本r10,应该是在<=r6版本的NDK还需要安装cygwin(这这里就不讨论,网上大把资料),附上NDK的下载链接方便不能×××的朋友,32位,64位,网站不能访问,但是直接用下载链接是可以下载到的。
安装好NDK后,就需要在Eclipse上进行配置了。
1、windows-preferences-android-ndk-ndklocation 选择ndk的安装目录
2、配置builder环境在需要进行ndk开发的项目上右键-properties-builder-new - program 在出现的弹窗中做以下配置
3、右键项目工程Android tools - Add Native Support
出现jni目录以及Android.mk,xx.cpp就说明添加成功了。就可以进行NDK开发了。
2、Java调用C++中的方法。
例如:获取从C++文件中获取字符串并打印
在Activity类A中:
static{System.loadLibrary("xx");//xx是Android.mk文件中LOCAL_MODULE的字段}//必须和ndk中的方法名一样publicnativeStringgetString();//onclick方法publicvoidclick(Viewv){Stringstr=getString();System.out.println("调用JNI中的方法:"+str);}
在ndk.cpp中
#include<jni.h>#include<string.h>/***extern"C"是必须加的,经测试不加的话方法调用不成功,也没找到答案,有知道为什么的请*告知,方法名称必须按照JNI的规范来Java_包名_类名_方法名,都必须以'_'隔开。*/extern"C"jstringJava_com_test_ndk_A_getString(JNIEnv*env,jobjectthiz){jstringstr;//在C中的是以(*env)->调用的,网上大部分的博客文档也是这种情况。str=env->newStringUTF("helloworld");//不能使用中文,不然会报错。returnstr;}
运行工程即可看到效果。
3、C++中调用Java方法
在ClassB中
static{System.loadLibrary("ndk");}publicnativevoidloadJavaMethod();publicvoidf1(){Stringstr;str="helloworldfromjava";System.out.println(str);}publicStringf2(){Stringstr;str="f2:helloworldfromjava";System.out.println(str);returnstr;}publicvoidf3(Stringstr,inti){System.out.println("f3内容为:"+str+",数字为:"+i);}
在ndk.cpp中
#include<jni.h>#include<string.h>extern"C"voidJava_com_test_ndk_B_loadJavaMethod(JNIEnv*env,jobjectthiz){//调用无参无返回值的方法jclasscls=env->GetObjectClass(thiz);//GetMethodID("jclass对象","方法名","方法参数")jmethodIDmID=env->GetMethodID(cls,"f1","()V");if(mID!=NULL){env->CallVoidMethod(thiz,mID);}//调用有参无返回值得方法//参数类型除了基本数据类型外,其他的都需要按照这样的格式//L包名/类名;包名用/分割,必须以;结束//详情请参考这篇文章jclasscls=env->GetObjectClass(thiz);jmethodIDmID=env->GetMethodID(cls,"f3","(Ljava/lang/String;I)V");jstringcontent=env->NewStringUTF("hehe");jinti=10;if(mID!=NULL){env->CallVoidMethod(thiz,mID,content,i);}//调用有返回值无参的方法jclasscls=env->GetObjectClass(thiz);jmethodIDmID=env->GetMethodID(cls,"f2","()Ljava/lang/String;");if(mID!=NULL){env->CallObjectMethod(thiz,mID);}//调用其他类中的方法假设有一个Student类,如果要使用Student类中的内部类A,格式为//com/test/ndk/Student$Ajclassstu=env->FindClass("com/test/ndk/Student");//实例化无参构造方法jobjectstuObj=env->NewObject(stu,env->GetMethodID(stu,"<init>","()V"));jmethodIDgetNameId=env->GetMethodID(stu,"getName","()V");if(getNameId!=NULL){env->CallVoidMethod(stuObj,getNameId);}}
4、在自己的 so文件中调用第三方的so文件
这种情况一般是因为第三方的C/C++中的方法不是按照JNI的规范来写,这时就需要进行重新包装,并使用,当然前提是有了第三方的说明文档。
将第三方的so文件配置到预编译环境
在工程的jni文件下新建prebuilt文件夹(名称随意)将第三方的so文件放到里面例如libthird.so,然后在这个文件夹下新建Androdid.mk文件,文件内容为
LOCAL_PATH:=$(callmy-dir)include$(CLEAR_VARS)LOCAL_MODULE:=libthirdLOCAL_SRC_FILES:=libthird.soinclude$(PREBUILT_SHARED_LIBRARY)
打开jni下的Android.mk文件,加入以下字段
LOCAL_PATH:=$(callmy-dir)include$(CLEAR_VARS)LOCAL_MODULE:=ndkLOCAL_SRC_FILES:=ndk.cpp#名称和第三方mk中LOCAL_MODULE定义的名称一样LOCAL_SHARED_LIBRARIES:=libthirdinclude$(BUILD_SHARED_LIBRARY)#添加路径include$(LOCAL_PATH)/prebuilt/Android.mk
配置完成后,在工程的libs\armeabi目录下可以看到第三方的so文件,注意不能直接将第三方的so文件放到这个目录下。否则在builde的时候会删除。
假设在第三方的C/C++文件中有这样一个方法
//extern"C"在第三方的包中的方法也必须添加,测试时,如果不添加方法调用不成功,但这个是不能限//制到第三方的,有待解决extern"C"intf1(){return101;}
在自己的C/C++文件中调用第三方的方法
#include<jni.h>#include<dlfcn.h>#include<fcntl.h>void*filehandle=NULL;jstring(*f1)()=NULL;extern"C"jintJava_com_test_ndk_classA_f1(JNIEnv*env,jobjectthiz){jinti;filehandle=dlopen("/data/data/com.fly.ndk2/lib/libndk.so",RTLD_LAZY);if(filehandle){f1=(int(*)())dlsym(filehandle,"f1");}if(f1){i=f1();dlclose(filehandle);filehandle=NULL;}returni;}
以上内容除了没有涉及到真正的C/C++编程外,JNI开发的一些知识点都涉及到了,仅属入门的一些知识,在完全不了解C/C++编程的情况下耗费了2天时间才积累了以上知识。如果还需要更深入的学习就需要学习C/C++的语法知识以及编译。
以上的代码以及操作不一定在其他的环境中有效,谨记。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。