android jni的编写, 控制led灯

网友投稿 1067 2022-11-22

android jni的编写, 控制led灯

android jni的编写, 控制led灯

前言

jni的写法有好几种,在这里先介绍在android源码包+linux环境下的jni编程方式,随后会介绍ndk中的jni的编程方式。

一, JNI简介

jni, java native interface, java的本地接口,如果java代码想去调用native方法(实际就是c/c++函数),就需要用jni技术,在传统的java中jni技术就已经存在,但是由于传统的java代码中,不太去写架构或者平台相关的代码,所以以前jni不是太惹人注意,直到android出现后,android本身是一个linux操作系统, linux中的应用编程中就使用c/c++代码去调用驱动,假如android的应用apk想去调用底层的设备驱动,那么就必须要去调用c/c++代码,所以此时jni就显得很重要,它起着承上启下的作用.

二,JNI控制Led框架

编程之前首先需要给大家介绍一个大体的框架,我们需要在apk中去点一个led灯,此时就像做饭一样,介绍几个主料:

1, apk,实现button点灯

2, jni代码,调用linux的系统调用,去控制驱动

3, 驱动,完成控制led硬件

三, apk中使用jni中的接口

接口1: 调用动态库

static{

System.loadLibrary("led_jni"); // /system/lib/libled_jni.so

}

public native int OpenDev();

public native int DevOn();

public native int DevOff();

public native int CloseDev();

接口3: 直接调用本地方方法

OpenDev();

APP调用JNI代码非常简单

四,jni代码的编写

1, 原理

java中调用c代码的基本原理是通过查看一个映射表来完成的,比如java中调用OpenDev方法时,实际是有一个c/c++函数与它一一对应,所以需要一个映射表,并且将其注册给dvm,当dvm解析java中的native方法是,会去查看这个映射表,并执行对应的c/c++函数,同时jni代码所在的文件是需要编译成动态库,

2, 代码编写

jni代码可以写成c文件或者是cpp文件,但是建议大家写成cpp文件,在此,以下代码是写成一个文件led_jni.cpp

#define LOG_TAG "MyLed_jni"#include #include #include #include #include #include #include #include #include "jni.h"static int fd = -1;jint open_led(JNIEnv *env, jobject thiz){ LOGD("----^_^ %s------\n", __FUNCTION__); fd = open("/dev/led1", O_RDWR); if(fd < 0) { LOGE("open : %s\n", strerror(errno)); return -1; } return 0;}jint led_on(JNIEnv *env, jobject thiz){ LOGD("----^_^ %s------\n", __FUNCTION__); jint val = 1; jint ret = -1; ret = write(fd, &val, 4); if(ret < 0) { LOGE("write : %s\n", strerror(errno)); return -1; } return 0;}jint led_off(JNIEnv *env, jobject thiz){ LOGD("----^_^ %s------\n", __FUNCTION__); jint val = 0; jint ret = -1; ret = write(fd, &val, 4); if(ret < 0) { LOGE("write : %s\n", strerror(errno)); return -1; } return 0;}jint close_led(JNIEnv *env, jobject thiz){ LOGD("----^_^ %s------\n", __FUNCTION__); if(fd > 0) close(fd); return 0;}static JNINativeMethod myMethods[] ={ {"openDev", "()I", (void *)open_led}, {"devOn", "()I", (void *)led_on}, {"devOff", "()I", (void *)led_off}, {"closeDev", "()I", (void *)close_led}, };jint JNI_OnLoad(JavaVM * vm,void * reserved){ JNIEnv *env = NULL; jint ret ; ret = vm->GetEnv((void * * )&env, JNI_VERSION_1_4); if(ret != 0) { LOGE("vm->GetEnv error\n"); return -1; } jclass myclz = env->FindClass("com/example/ledjnitest/LedActivity"); if(myclz == NULL) { LOGE("env->FindClass error\n"); return -1; } ret = env->RegisterNatives(myclz, myMethods, sizeof(myMethods)/sizeof(myMethods[0])); if(ret < 0) { LOGE("env->RegisterNatives error\n"); return -1; } return JNI_VERSION_1_4;}

3, jni代码重点介绍

a, 动态库中的接口:

a, 获取dvm的环境变量对象,并测试jni的版本(1.4)

vm->GetEnv((void **)&env, JNI_VERSION_1_4)

该方法是dvm给我们提供的方法,用于获取环境变量对象JNIEnv* env,同时会检测jni的版本是否是1.4, 该方法正常返回JNI_OK

b, 映射表的注册,会调用env->RegisterNatives()方法

env->RegisterNatives(jclass clazz, const JNINativeMethod* methods,jint nMethods)

第一个参数: 将java中native修饰的方法所在的类转换成jni的class类型(jclass)

jclass mycls = env->FindClass("com/hq/JniLedTestActivity");

env->FindClass中的参数是java中的native方法所在包和类的路径,这个是必须要注意的,路径是用Linux常用的路径表示方式,而不是用windows,也不是用java中的点分方式,同时路径必须要指定正确,否则会出错

第二个参数: jni的映射表, 实际是一个结构体数组, 结构体如下所示:

typedef struct {   const char* name; // java的native修饰的方法名   const char* signature; // 方法的返回值和参数的描述,比如(I)I,表示返回值为int,带有一个int型的参  数   void* fnPtr; //c/c++中的函数名 } JNINativeMethod;

第三个参数: 映射表表的成员个数sizeof(myMethods)/sizeof(myMethods[0])

返回: JNI_OnLoad正常 返回JNI_VERSION_1_4, 错误返回一个负数

c, 接下来就是c/c++函数的实现了

static int fd = -1;jint open_led(JNIEnv *env, jobject thiz){ LOGD("----^_^ %s------\n", __FUNCTION__); fd = open("/dev/led1", O_RDWR); if(fd < 0) { LOGE("open : %s\n", strerror(errno)); return -1; } return 0;}

五,驱动部分

对于不同平台,led的驱动的写法是不一样的,但是基本的写法就是按照字符设备的方式去写,这个算是一个字符设备驱动的简单模板,基于s5pv210, 可以参考一下看看

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Android 10 根文件系统和编译系统(一):根文件系统目录结构
下一篇:Xss-labs-level11-15
相关文章

 发表评论

暂时没有评论,来抢沙发吧~