NDK开发的奇技淫巧(一)

来源:互联网 发布:手机看书软件免费下载 编辑:程序博客网 时间:2024/06/06 03:15

本人之前搞过比较多的android业务层开发,一些套路基本已经烂熟于心,但仅仅这样很难让我的技术水平更上一层楼。目前在架构部门做通用sdk,涉及到底层业务,我怀着极大的热情去学习android native开发,然而最开始的过程让我十分痛苦,咬牙挺过这段时间后,让我对android的理解有质的飞跃。这里整理一些经验, 与大家分享。

android native 开发可以使用c或者c++。但经过多次实验,使用 c 开发相对比较更麻烦,而c++能过面向对象更符合本人的开发哲学,c++ 也能满足大多数native开发的需求,所以本系列文章均采用c++编程。

为了使大家能更加深刻的理解native开发,先介绍一下开发的基本流程与程序结构:

程序结构:


如图,java和 c++层通信需要一层接口层来处理,我们重点研究接口层通信问题,基本流程如下:

1.在java中定义一个类NInterface,专门用于定义native接口方法。使用关键字native:

public class NInterface {    public native void setAge(int age);    public native void setName(String name);    }

2.android工程和native工程可以看做是两个不相干的工程,编译时互不受影响,我们可以单独建一个文件夹来存放c++代码。详细操作后面文章再专门介绍。

这里新建jni文件夹,在文件夹中新建main.cpp 文件:

extern "C" JNIEXPORT void JNICALLJava_com_api_NInterface_setAge(JNIEnv*env,jobject jobj,jint age){}extern "C" JNIEXPORT void JNICALLJava_com_api_NInterface_setName(JNIEnv*env,jobject jobj,jstring name){}

其中extern "C" 是为了兼容c的编译方式,因为android内核很多都是用c写的。

extern "C" JNIEXPORT void JNICALL 是jni标准规范写法,void表示接口返回类型。

Java_com_api_NInterface_setAge(JNIEnv*env,jobject jobj,jint age),这是接口方法名在jni 中的写法,前面以Java开头,然后是方法在java中的包名,最后接方法名( 必须与java接口方法明相同),中以下划线分割开。当运行时,jvm通过包名查到对应的c++ 方法。
参数 JNIEnv *env 表示当前jni环境指针,jobject jobj 表示调用该接口的对象,如果该方法是静态方法,则换为jclass jclazz 。这两个参数是jni接口中必不可少的。
后面jint 是方法setAge 传递的参数,表示java的int 类型。这里java 和 c++ 的基本数据类型不一样,在传递的过程中在类型前面加一个字母 j 以示区分。要在本地使用这些类型需要经过对应的转换。

每次每个接口写这么一大串实在烦人,我们利用宏定义来简化代码,新建java_define.h文件:

#define JNI_RETURN(ret_t) extern "C" JNIEXPORT ret_t JNICALL#define JAVA_FUNC(clazz,func_name) Java_com_api_##clazz##_##func_name

导入头文件,以上方法就可以写为:

JNI_RETURN(void) JAVA_FUNC(NInterface,setAge)(JNIEnv*env,jclass jclazz ,jint age){}
当然,如果开发者想更方便编写程序,可以二次自定义宏。有些博客介绍使用java的命令工具自动生成相应的c++接口代码,生成的文件名也是包名的形式,这就让人很费解,其实只要接口方法名没有问题就能正常运行,跟文件名以及方法是不是都在同一个文件中都没有关系。开发者可以根据业务需求自定义多个接口文件。



0 0
原创粉丝点击