Android NDK使用分析

Android NDK使用分析:

在Android应用程序开发中,对于一些对性能安全要求较高的模块开发中,我们一般会使用C/C++代码来实现,或者引用一些已经实现好的C/C++库时,都需要使用JNI机制。正如上面的介绍是比较常用的,同样可以实现编写基于JNI机制访问C/C++库文件。

Android NDK是谷歌公司提供的开发工具集,我们可以使用它快捷得开发基于JNI机制的程序。它的几个重要的功能如下:

A、提供将C/C++源代码编译成本地库文件(编译器、连接器等)

B、提供将编译好的本地库文件插入到Android的包文件(.apk)

C、提供NDK开发相关的文档、实例及规范等

注意:

谷歌是不建议开发者使用NDK开发Android本地应用程序的,当然,这样做是可以实现的,因为Android系统的主要应用是运行在dalvik虚拟机上的Java程序,推荐多开发运行在dalvik上的程序。

 

NDK的功能:

 Android NDK使用分析

如上图所示,Android ndk先编译了C/C++本地代码,并生成本地库文件,然后将其插入到Android应用程序的包当中,但调用JNI的编译本地代码的工作还需要我们来做的。

NDK安装:

在谷歌官网上下载最新的NDK包,并解压到指定的目录下,那么这个目录就作为环境变量的名字,即NDK_HOME,然后在环境变量的path中添加该NDK_HOME环境变量即可。

Cygwin安装:

在上面,我们已经安装并安装了Cygwin了,在这里简单介绍下他的作用。Cygwin主要是用来处理不同平台间的转化工作,例如Android是基于Linux的框架集,而我们常使用的系统却是windows系统,所以使用它来将库文件从windows转为基于Linux系统的。当然,如果使用的系统是Linux的话 则无需这个步骤了。

既然在这里介绍了它,无可置疑会用到它的。回到上面NDK环境的配置,怎么样验证环境变量是否配置成功那?答案就是使用这个Cygwin工具。我们打开它,在里面输入ndk-build,如果没有报错而是出现这个结果的话,则说明环境变量配置成功:

 Android NDK使用分析

哦,这里的错误是因为没设定项目的路径,这里不用理会即可。

NDK的使用步骤:

实际上,NDK的使用流程与之前介绍的《Android本地接口JNI使用分析》使用流程及内容很多都很相似,在这里,我只介绍与之前不同的一些东西,下面即为NDK的开发流程:

1、创建Java本地方法类

2、编译Java本地方法生成C/C++头文件

3、编写实现上面的C/C++实现文件

4、编译生成动态运行库(.so)

5、运行应用程序

下面,根据上面的流程来介绍下NDK的使用及注意事项。我的项目目录:

 Android NDK使用分析

运行的效果如:

 Android NDK使用分析

每点击按钮打印LOG日志。

创建Java本地方法:

创建Java本地方法与之前文章是相同的,只不过这里的LOG内容为”Hello Ndk!”而已,代码如下:

public class VerifyNdkJniMethod {

static {

System.loadLibrary("hello_ndk");

}

public static native String helloNdk();

}

编译Java本地方法:

和之前的文章内容相同,都是使用Javah命令来编译生成的class文件,从而生成对应的C/C++头文件,我的头文件:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class com_demo_verifyndk_jni_ndk_VerifyNdkJniMethod */

 

#ifndef _Included_com_demo_verifyndk_jni_ndk_VerifyNdkJniMethod

#define _Included_com_demo_verifyndk_jni_ndk_VerifyNdkJniMethod

#ifdef __cplusplus

extern "C" {

#endif

/*

 * Class:     com_demo_verifyndk_jni_ndk_VerifyNdkJniMethod

 * Method:    helloNdk

 * Signature: ()Ljava/lang/String;

 */

JNIEXPORT jstring JNICALL Java_com_demo_verifyndk_1jni_ndk_VerifyNdkJniMethod_helloNdk

  (JNIEnv *, jclass);

 

#ifdef __cplusplus

}

#endif

#endif

同样的,与之前的头文件编写方式相同,我的实现文件如下:

#include <stdio.h>

#include "VerifyNdkJniMethod.h"

 

JNIEXPORT jstring JNICALL Java_com_demo_verifyndk_1jni_ndk_VerifyNdkJniMethod_helloNdk

  (JNIEnv *env, jclass obj)

{

return (*env)->NewStringUTF(env,"Hello Ndk!");

}

 

编译生成动态库文件(.so):

在这里,与我们之前介绍的略有不同,我们任然需要编写Android.mk文件,我的mk文件如下(在文章的最下面会介绍下mk文件):

#指定源文件的位置

LOCAL_PATH := $(call my-dir)

 

#初始化与Make相关的环境变量

include $(CLEAR_VARS)

 

#库编译相关信息 包括库名称、源码等

LOCAL_MODULE := hello_ndk

LOCAL_SRC_FILES := VerifyNdkJniMethod.c

 

#生成共享库

include $(BUILD_SHARED_LIBRARY)

 

同样需要将头文件和实现文件及mk文件放在一起,只不过这里我们必须在项目的根目录下新建一个jni目录,cd到这个目录下,使用ndk-build或是$NDK/ndk-build来编译生成动态库文件。这与之前有些不同,之前我们使用的是$NDK/ndk-build来编译,是因为之前我们没有通过NDK的方式来实现,而是借助工具Cygwin来实现生成共享库文件的(这个是成立的);而现在,我们配置了NDK的环境变量可以使用$NDK/ndk-build或是ndk-build都可以进行编译生成,不同的是使用NDK及进行编译的话,我们必须cd到项目根目录下的jni下,上面的编译命令才会生效。原因是这样的,使用NDK编译的时候,NDK自身带有编译器系统,在编译的时候,编译系统会在当前的目录下查找AndroidManifest.xml文件,若文件存在,则将当前的目录看做为Android工程目录。然后再转到jni目录下,根据Android.mk进行NDK编译。

运行应用程序:

这个过程与之前的文章《Android本地接口JNI使用分析》基本相同,我的代码如下:

public class VerifyNdkJniActivity extends Activity {

private static String TAG = "VerifyNdkJniActivity";

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_verify_ndk_jni);

}

 

public void helloNdk(View v) {

String result = VerifyNdkJniMethod.helloNdk();

log(result);

}

private void log(String log) {

Log.d(TAG, log);

}

}

 

Android.mk文件说明:

实际上,Android.mk文件的帮助文件在<NDK_HOME>/docs/ANDROID_MK.html中(不过是英文的),下面就介绍下吧!

LOCAL_PATH := $(param...):

这个变量是用来在开发树中查找源文件,必须在mk文件的最开始处定义,一般情况下,使用下面的这种的编写格式:

LOCAL_PATH := $(call my-dir)

其中的my-dir为一个宏函数,$(call my-dir)就是用来返回一个宏函数的值,一般Android.mk文件与源文件在同一个目录下。

Include $(CLEAR_VARS):

用来初始化mk文件中LOCAL_XXX的变量,但是上面的LOCAL_PATH除外,因为Android系统会将LOCAL_XXX的变量当作全局变量,所以会先对其进行初始化。

LOCAL_MODULE := XXX:

用来标记在mk文件中描述的每一个模块,也就是要生成的库的名称。这个名称必须唯一并且不能含有空格,编译系统会自动产生适当的前缀和后缀,比如:libhello_jni.so文件。

LOCAL_SRC_FILES := XXX.c/.cpp:

用来将包含将要被编译进打包模块的各个资源文件。同时,这些源文件所在的位置为LOCAL_PATH所指定的目录。

Include $(BUILD_SHARED_LIBRARY):

用来使用LOCAL_PATH、LOCAL_SRC_FILES等的变量值,创建名称为lib$(LOCAL_MODULE).so的库文件。

 

到这里,关于NDK的一些基本的东西介绍完了,如果想要更灵活的使用NDK,那么可以参看NDK中自带的simples,仔细研究学习,其位置在: <NDK_HOME>\samples\

 

 

 

 

 

/**

* 欢迎加入技术群:179914858

* 如果有任何问题请在评论中进行讨论学习

*/

 

Android NDK使用分析,布布扣,bubuko.com

Android NDK使用分析

上一篇:安卓Socket开发注意事项


下一篇:“小米公司”的简单工厂模式