Android.mk 文件使用说明
Android.mk文件是NDK编译指令,基于GUN MakeFile片段,它的语法与其他的MakeFiled一样,GUN Make工具不处理他们,但是根据命名规则,变量名需要大写。
一般固定的写法如下:
#前两行都是固定设置的,编译器自动进行解析
LOCAL_PATH := $(call my-dir)
#编译过程中清除多余的声明文件
include $(CLEAR_VARS)
#设置当前模块的名称以及源文件,也就是在System.loadLibrary()加载文件
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
#构建共享库,为了在主程序中能够使用该模块,则必须将该模块编程共享库,Android NDK构建系统将BUILD_SHARED_LIBRARY 变量设置为build-shared-library.mk文件的保存位置
include $(BUILD_SHARED_LIBRARY)
#一般对于程序而言,前两行都是固定的写法,如果在程序中将要包含了多个Module,则需要根据以上的语法进行添加,如以下的方式
include $(CLEAR_VARS)
LOCAL_MODULE :=test
LOCAL_SRC_FILES :=Test.cpp
include $(BUILD_SHARED_LIBRARY)
构建静态库
Android NDK构建系统也支持静态库,实际的Android应用程序并不是直接的使用静态库,并且在应用程序中也不包含静态库。静态库可以用来构建共享库,例如在将第三方代码添加到现有的原生程序中的时候,可以直接将第三方的代码编译成为静态库然后并入共享库。如以下的代码所示:
LOCAL_PATH := $(call my-dir)
//第三方库
include $(CLEAR_VARS)
LOCAL_MODULE :=avilib
LOCAL_SRC_FILES :=avilib.c platform_posix.c
include $(BUILD_STATIC_LIBRARY)
//以下原生模块调用
include $(CLEAR_VARS)
LOCAL_MODULE :=myModule
LOCAL_SRC_FILES :=myModule.c
LOCAL_STATIC_LIBRARY :=avilib
include $(BUILD_SHARED_LIBRARY)
NDK编译过程中c以及c++
构建的区别
- 使用c语言进行函数的命名方式比c++简单,如下所示:
jstring Java_com_example_HelloJni_HelloJni_sayHello(JNIEnv *p,Jobject thiz);
命名规则为:返回值+包名+类名+方法名,中间以_为分割线。
- 使用c++语言命名时方式比c语言要稍微复杂一点;如下所示:
extern "C"{
JNIEXPORT jstring Java_com_example_hellojni_HelloJni_sayHello(JNIEnv *p,jobject thiz){
}
//需要注意的地方在于要添加上extern "C",否则编译生成方法前面将会生成前缀,在Java中调用方法将找不到原生实现方法。这一点是方法声明较为重要的一点区别。
NDK中对数据的操作
- 数组操作
- 1、创建数组,可以使用 (*env)->NewIntentArray(env,10)。类似于这种方法来进行创建。 在内存溢出的情况下,New
<Type>
Array函数可能返回null空指针。 - 2、访问数据元素
- Jni提供了两种访问Java数组元素的方法,可以将数组的代码复制成C数组或者是让Jni提供直接指向数组的指针。
- 3、对副本的操作
- Get
<Type>
ArrayRegion 函数将指定的Java数组复制到给定的C数组中,如以下代码所示:
java
(*env)->GetIntArrayRegion(env,javaArray,
0,10,nativeArray);
- Get
- 4、对直接指针的操作
- 在原生代码中可以直接使用Get
<Type>
ArrayElements 函数获取指向数组元素的直接指针,函数有三个参数,最后一个参数isCopy
- 在原生代码中可以直接使用Get
- 1、创建数组,可以使用 (*env)->NewIntentArray(env,10)。类似于这种方法来进行创建。 在内存溢出的情况下,New
NIO操作
1、创建直接字节缓冲区
原生方法中的内存分配超出了虚拟机的管理范围,且不能用虚拟机的垃圾回收原生方法中的内存,所以在使用完毕之后应该通过释放未使用的内存避免内存泄露来正确的管理内存。
2、直接字节缓冲区的获取
Java应用程序中也可以创建直接字节缓冲区,在原生代码中调用GetDirect
BufferAddress 函数可以获得原生字节数组的内存地址。
如代码所示:
usigned char* buffer;
buffer=(unsigned char*)(*env)->GetDirectBufferAddress(env,directBuffer)
3、访问域
在Java 中存在实力域以及静态域。类的每个实例都有自己的实例域副本,而一个类的所有实例都共享了一个静态域。
Jni提供了访问两类域的函数,首先是获取域Id,JNI可以利用域Id访问两类域的方法,可以通过给定实例的class对象获取域Id,用getObjectClass函数可以获得class对象,如下代码所示: