您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 电子设计/PCB > Android JNI开发入门与提高
AndroidJNI开发入门之一2010十二月07作者:Simon_fu目录:Android,Java,...评论:1条评论JNI在Android系统中有着广泛的应用。Android系统底层都是C/C++实现的,上层提供的API都是Java的,Java通过JNI调用底层的实现。比如:AndroidAPI多媒体接口MediaPlayer类,其实底层通过JNI调用libmedia库。由于JNI的存在可以让我们重用很多已经存在C/C++的库,省去了重复开发的麻烦,并且可以利用很多开源的库(Android库中就有很多开源库,比如libjpeg,libpng等等),并且让我们开发的程序更有效率(C/C++代码发挥硬件最佳性能)。如果你对标准JNI不熟悉的话,可以先参考我的博文《Linux下JNI实现》,文中介绍了怎样用标准JNI在Linux系统中实现一个Helloworld程序,可以让你对JNI有一个初步的认识。本文简单介绍一下怎样在Android下面怎样用JNI开发程序,并开发一个经典Helloworld应用程序。交叉编译环境首先是要搭建交叉编译环境,因为Java层的应用程序是和硬件无关的,JDK编译即可;但是NativeC/C++代码是和硬件相关的,必须要用交叉编译器编译成特定硬件可执行代码。请根据你的硬件平台搭建你的交叉编译环境,我的MIPS平台,当然选择的是MIPS的交叉编译器,如果你是Arm的请配置自己的交叉编译器。我们首先编译一个NativeC的helloworld程序,一个学习怎样在Android中增加一个程序,另外也可以验证我们的交叉编译环境是否正确,可以参考《Android编译环境(1)–编译NativeC的helloworld模块》。如果这个步没有问题说明你的交叉编译环境是没有问题的,可以继续往下面进行。Java编写的Android应用程序我们首先用java编写helloworld应用程序(APK),这个代码很简单创建一个HelloWorldactivity。代码如下:packagecom.simon;importandroid.app.Activity;importandroid.os.Bundle;importandroid.util.Log;publicclassHelloWorldextendsActivity{privatestaticfinalStringTAG=HelloWorld;static{System.loadLibrary(helloworld);}privatenativeStringprintJNI();/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);Log.d(TAG,ActivitycallJNI:+printJNI());}}这个HelloWorldActivity非常简单,只是调用JNI接口printJNI()打印一些信息到Androidlogger上面。我们需要关注一下的是printJNI()的声明,有一个native的关键字,说明他是一个用native代码实现的函数,需要用JNI调用Native代码。另外注意static代码段,这段代码意思是当类HelloWorld第一次被加载的时候,加载libhelloworld.so(请注意这里写的是库名称,在Linux中共享库名为xxx共享库,文件存在形式为libxxx.so。所以loadLibrary的参数不是libhelloworld.so,而是helloworld。如果写错误了将会加载库失败,将会收到异常)。C语言实现helloworld共享库接下来我们需要来完成Native代码部分了,这里需要强调一下,AndroidJNI实现中为C/C++提供了两套不同的API,调用的时候需要注意,否则非常有可能你会受到一些libc库的崩溃信息,没准儿会把你整“崩溃”,呵呵!下面先实现NativeC来实现helloworld库。如果你对Java标准JNI熟悉的话,肯定知道javah工具,可以根据java源程序,生成Native代码的头文件(可以参考我的博文《Linux下JNI实现》)。如果你是在Eclipse中开发apk的话,可以在打开终端进入bin目录,然后执行:javahcom.simon.HelloWorld你将会得到,一个头文件com_simon_Helloworld.h,这里包含有printJNI接口的C/C++声明。这个声明肯定正确,如果你把printJNI接口声明写错了,HelloWorld将找不到printJNI接口,然后产生崩溃。我们创建com_simon_Helloworld.c文件,并在该文件中输入:#includejni.h#defineLOG_TAGHelloWorld#includeutils/Log.h/*Nativeinterface,itwillbecallinjavacode*/JNIEXPORTjstringJNICALLJava_com_simon_HelloWorld_printJNI(JNIEnv*env,jobjectobj){LOGI(HelloWorldFromlibhelloworld.so!);return(*env)-NewStringUTF(env,HelloWorld!);}/*Thisfunctionwillbecallwhenthelibraryfirstbeload.*Youcandosomeinitinthelibray.returnwhichversionjniitsupport.*/jintJNI_OnLoad(JavaVM*vm,void*reserved){void*venv;LOGI(JNI_OnLoad!);if((*vm)-GetEnv(vm,(void**)&venv,JNI_VERSION_1_4)!=JNI_OK){LOGE(ERROR:GetEnvfailed);return-1;}returnJNI_VERSION_1_4;}请注意Java_com_simon_HelloWorld_printJNI函数的名字,这个名字是符合JNI规范的,Java_开头,后面紧跟着调用他类名(包含包名和类名,com_simon_HelloWorld),然后才是接口的名字printJNI。这样java虚拟机就可以在com.simon.HelloWorld类调用printJNI接口的时候自动找到这个C实现的Native函数调用。你可能注意到这个名字非常的长,作为一个函数名它非常有可能不是一个好的选择。JNIAPI允许你提供一个函数映射表,注册给Jave虚拟机,这样Java虚拟机就可以用函数映射表来调用相应的函数,就可以不必通过函数名来查找需要调用的函数了。这样你的函数名也可以随便定义了(可以定义最能表现函数功能的函数名),这个将会在helloworld共享库的C++实现中演示。但是Android系统中,还是推荐用JNI标准的函数名定义的。JNI_OnLoad函数JNI规范定义的,当共享库第一次被加载的时候会被回调,这个函数里面可以进行一些初始化工作,比如注册函数映射表,缓存一些变量等,最后返回当前环境所支持的JNI环境。本例只是简单的返回当前JNI环境。注意网上很多例子都说可以不实现JNI_OnLoad,我发现如果不是实现的话,printJNI只可以返回整型类型的值,如果返回其他类型的值都会崩溃。并且GetEnv的调用也是必须的,否则也是崩溃,但是GetEnv的返回值我并没有用到,这些地方使我非常迷惑,期待达人解惑。接下来编写Android.mk文件,创建之,并输入:LOCAL_PATH:=$(callmy-dir)include$(CLEAR_VARS)LOCAL_SRC_FILES:=com_simon_Helloworld.cLOCAL_C_INCLUDES:=$(JNI_H_INCLUDE)LOCAL_MODULE:=libhelloworldLOCAL_SHARED_LIBRARIES:=libutilsLOCAL_PRELINK_MODULE:=falseinclude$(BUILD_SHARED_LIBRARY)这里面有几个标签需要说明:1、LOCAL_C_INCLUDES说明包含的头文件,这里需要包含JNI的头文件。2、LOCAL_MODULE当前模块的名称3、LOCAL_SHARED_LIBRARIES当前模块需要依赖的共享库,因为在hellowold中我们调用Android打印系统输出到logger,所以我们必须要依赖libutils库。4、LOCAL_PRELINK_MODULE指明该模块是否被启动就加载,可以参考《动态库优化——Prelink(预连接)技术》。我们的helloworld库不需要prelink,所以置为false。编译这个模块,根据你的环境不同,选择不同的编译途径。然后安装apk,然后运行他们,通过logcat工具将会看到相应的输出。请继续关注《AndroidJNI开发入门之二》。AndroidJNI开发入门之二2010十二月08作者:Simon_fu目录:Android,Java,...评论:1条评论在上一篇文章《AndroidJNI开发入门之一》中,我介绍了Android应用程序(APK)怎样通过JNI调用NativeC实现的共享库。本文将进一步介绍Android应用程序通过JNI调用NativeC++实现的共享库,并实现一个和上文《AndroidJNI开发入门之一》相同功能的Helloworld应用程序。两套不同的API前文已经提到,Android系统的Java虚拟机为C和C++实现两套不同的API,所以我们调用的时候需要注意这一点儿。另外Google并没有提供JNI的文档,我们调用的时候可以参考Android的jni.h文件,里面有C和C++的JNI函数原型。也可以把本例的相同功能HelloWorld库和上文《AndroidJNI开发入门之一》进行比较。C++实现HelloWorld共享库在本例中Android应用程序不需要有任何变化,我们需要重新用C++实现HelloWorld共享库。创建com_simon_Helloworld.cpp文件,并在文件中输入如下内容:#includejni.h#defineLOG_TAGHelloWorld#includeutils/Log.h/**Class:com_simon_Helloworld*Method:print*Signature:()V*//*JNIEXPORTvoidJNICALLJava_com_simon_Helloworld_print(JNIEnv*,jobject)*/JNIEXPORTjstringJNICALLJava_com_simon_HelloWorld_printJNI(JNIEnv*env,jobjectobj){LOGI(HelloWorldFromlibhelloworld.so!);returnenv-NewStringUTF(HelloWorld!);}staticconstchar*classPathName=com/simon/HelloWorld;staticJNINativeMethodmethods[]={{printJNI,()Ljava/lang/String;,(void*)Java_com_simon_HelloWorld_printJNI},};/**Registerseveralnativemethodsforoneclass.*/staticintregisterNativeMethods(JNIEnv*env,con
本文标题:Android JNI开发入门与提高
链接地址:https://www.777doc.com/doc-5940299 .html