NDK & JNI(方式读写Android系统的Demo)
大家都知道Android系统是一种基于Linux的自由及开放源码的操作系统,所以读写GPIO也可以直接用Linux那一套export/unexport方法,本文将介绍如何使用NDK jni方式来读写Android系统的GPIO。
1.环境的具体配置参考博客:http://blog.youkuaiyun.com/darlingqiang/article/details/79049638
2. Android Studio安装NDK
打开Android Studio 中的SDK Manager,菜单Tools -> Android -> SDK Manager
查看安装情况如下,如果没有安装完整的话,请选中NDK,点击OK就可以安装NDK
3. 创建Android工程
(1) 创建Android工程jnigpio,然后添加一个新的java类GPIOControl.java
代码如下:
public class GPIOControl {
static {
System.loadLibrary("GPIOControl");
}
public final static native int exportGpio(int gpio);
public final static native int setGpioDirection(int gpio, int direction);
public final static native int readGpioStatus(int gpio);
public final static native int writeGpioStatus(int gpio, int value);
public final static native int unexportGpio(int gpio);
}
(2) Build -> Rebuild Project即可,会生成 .class文件
(3) 生成jni的头文件
Android Studio Terminal中输入如下命令:cd app/src/main/java/
Ternial执行: javah -d jni com.sun.jnigpio.GPIOControl(前面博客有介绍具体的意思)
生成jni头文件如下图: 生成
(4) jni目录下创建GPIOControl.c程序
代码如下:
//
// Created by Gavin Zhuang on 05/12/2017.
//
#include <jni.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <android/log.h>
#include "com_zhuang_jnigpio_GPIOControl.h"
#define TAG "jni_gpio"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__)
#define IN 0
#define OUT 1
#define LOW 0
#define HIGH 1
#define BUFFER_MAX 3
#define DIRECTION_MAX 48
/*
* Class: com_zhuang_jnigpio_GPIOControl
* Method: exportGpio
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_com_zhuang_jnigpio_GPIOControl_exportGpio(JNIEnv *env, jobject instance, jint gpio)
{
char buffer[BUFFER_MAX];
int len;
int fd;
fd = open("/sys/class/gpio/export", O_WRONLY);
if (fd < 0) {
LOGE("Failed to open export for writing!\n");
return(0);
}
len = snprintf(buffer, BUFFER_MAX, "%d", gpio);
if (write(fd, buffer, len) < 0) {
LOGE("Fail to export gpio!\n");
return 0;
}
close(fd);
return 1;
}
/*
* Class: com_zhuang_jnigpio_GPIOControl
* Method: setGpioDirection
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_zhuang_jnigpio_GPIOControl_setGpioDirection(JNIEnv *env, jobject instance, jint gpio, jint direction)
{
static const char dir_str[] = "in\0out";
char path[DIRECTION_MAX];
int fd;
snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/direction", gpio);
fd = open(path, O_WRONLY);
if (fd < 0) {
LOGE("failed to open gpio direction for writing!\n");
return 0;
}
if (write(fd, &dir_str[direction == IN ? 0 : 3], direction == IN ? 2 : 3) < 0) {
LOGE("failed to set direction!\n");
return 0;
}
close(fd);
return 1;
}
/*
* Class: com_zhuang_jnigpio_GPIOControl
* Method: readGpioStatus
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_com_zhuang_jnigpio_GPIOControl_readGpioStatus(JNIEnv *env, jobject instance, jint gpio)
{
char path[DIRECTION_MAX];
char value_str[3];
int fd;
snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/value", gpio);
fd = open(path, O_RDONLY);
if (fd < 0) {
LOGE("failed to open gpio value for reading!\n");
return -1;
}
if (read(fd, value_str, 3) < 0) {
LOGE("failed to read value!\n");
return -1;
}
close(fd);
return (atoi(value_str));
}
/*
* Class: com_zhuang_jnigpio_GPIOControl
* Method: writeGpioStatus
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_zhuang_jnigpio_GPIOControl_writeGpioStatus(JNIEnv *env, jobject instance, jint gpio, jint value)
{
static const char values_str[] = "01";
char path[DIRECTION_MAX];
int fd;
snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/value", gpio);
fd = open(path, O_WRONLY);
if (fd < 0) {
LOGE("failed to open gpio value for writing!\n");
return 0;
}
if (write(fd, &values_str[value == LOW ? 0 : 1], 1) < 0) {
LOGE("failed to write value!\n");
return 0;
}
close(fd);
return 1;
}
/*
* Class: com_zhuang_jnigpio_GPIOControl
* Method: unexportGpio
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_com_zhuang_jnigpio_GPIOControl_unexportGpio(JNIEnv *env, jobject instance, jint gpio)
{
char buffer[BUFFER_MAX];
int len;
int fd;
fd = open("/sys/class/gpio/unexport", O_WRONLY);
if (fd < 0) {
LOGE("Failed to open unexport for writing!\n");
return 0;
}
len = snprintf(buffer, BUFFER_MAX, "%d", gpio);
if (write(fd, buffer, len) < 0) {
LOGE("Fail to unexport gpio!");
return 0;
}
close(fd);
return 1;
}
android.useDeprecatedNdk=true
在defaultConfig中添加ndk内容:
ndk{
moduleName "GPIOControl" //so文件: lib+moduleName+.so
ldLibs "log", "z", "m" // 添加android日志引用
abiFilters "armeabi", "armeabi-v7a", "x86" //cpu的类型
}
3

(6) Rebuild Project 生成so文件
so文件在app>build>intermediates>make>debug>lib>目录下,如图:

(7) 方法调用
// 定义GPIO输入输出方式和高低电平
public final static int GPIO_DIRECTION_IN = 0;
public final static int GPIO_DIRECTION_OUT = 1;
public final static int GPIO_VALUE_LOW = 0;
public final static int GPIO_VALUE_HIGH = 1;
Thread.sleep(1000);
}
GPIOControl.unexportGpio(gpioPin);
} catch (Exception ex){
}
}
});
thread.start();
}
});
注意事项:该控制GPIO需要su权限,可以试着用adb shell去修改 /sys/class/gpio/export 和 /sys/class/gpio/unexport 的读写权限。如:chmod 666 /sys/class/export
参考自博客:http://blog.youkuaiyun.com/zjc3909/article/details/78732374