硬件平台:迅为iTOP-412开发板
接下来我们来仿写一个这个方法,我们已打开 led 灯代码为例。
1. 我们先在 MainActivity 里面实现三个方法,分别对应打开,关闭,和控制,我们添加以下代码:
public native int LedOpen();
public native int LedClos();
public native int LedIoctl(int num,int en);
如下图所示:
2. 然后我们打开 native-lib.cpp 文件,仿写 jin 代码,分别仿写打开,关闭,控制的实现,代码如下:
extern "C" JNIEXPORT jint JNICALL
Java_com_example_jnitest_MainActivity_LedOpen(
JNIEnv* env,
jobject /* this */) {
return 0;
}
extern "C" JNIEXPORT jint JNICALL
Java_com_example_jnitest_MainActivity_LedClos(
JNIEnv* env,
jobject /* this */) {
return 0;
}
extern "C" JNIEXPORT jint JNICALL
Java_com_example_jnitest_MainActivity_LedIoctl(
JNIEnv* env,
jobject /* this */,
jint num,
jint en) {
return 0;
}
如下图所示:
3. 接下来我们添加控制 led 的 c 代码,这部分的代码和我们直接用 C 控制 led 的代码是一样的,我们
先添加需要的头文件,代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <stdint.h>
#include <termios.h>
#include <android/log.h>
#include <sys/ioctl.h>
如下图所示:
4. 我们在 Java_com_example_jnitest_MainActivity_LedOpen 里面添加打开 led 设备节点的 C 代码:
先添加头文件和 fd 句柄的定义 代码如下
#include <android/log.h>为安卓打印调试信息的头文件。
#include <android/log.h>
int fd = 0;
如下图所示:
然后在 Java_com_example_jnitest_MainActivity_LedOpen 里面添加打开 led 节点的代码,代码如下:
fd = open("/dev/leds_ctl", O_RDWR | O_NDELAY | O_NOCTTY);
if(fd <= 0){
__android_log_print(ANDROID_LOG_INFO, "serial", "open /dev/leds_ctl Error");
}else{
__android_log_print(ANDROID_LOG_INFO, "serial", "open /dev/leds_ctl Sucess fd=%d", fd);
}
如下图所示:
5. 在 Java_com_example_jnitest_MainActivity_LedClos 里面添加关闭 fd 的代码,代码如下:
if(fd > 0) close(fd);
如下图所示:
6. 在 Java_com_example_jnitest_MainActivity_LedIoctl 添加 led 控制的代码,代码如下:
ioctl(fd,num,en);
如下图所示:
7. 我们点击一下编译,这样就可以在默认路径下生成我们这个
我们切换到 project 下面,在默认路径下可以看到我们生成的
8. 我们可以看到,我们生成的库有 arm64-v8a,armeabi-v7a,x86,x86_64 的库,但是我们实际上并
不需要这么多库,在现阶段,我们需要需要 armeabi-v7a 就可以满足大部分的需求了,armeabi-v7a 兼容
X86,ARMV7,ARMV8,而且这个库生成的路径很不好找,我们能不能改一下他生成的路径并只生成我们需要
的库呢?答案当然是可以的。
(1)更改 so 库的生成目录,我们打开 CMakeList.txt,添加下面的一句设置:
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
简化这个设置就是:
set(原路径,目标路径,生成那些平台对应的库文件)
参数解析如下:
CMAKE_CURRENT_SOURCE_DIR:这个是 cmake 的库的原路径
/../jniLibs/:这个是指与 CMakeList.txt 所在目录的同一级目录
ANDROID_ABI :生成那些平台对应的库文件。
我们打开 CMakeList.txt,在里面添加这句代码,代码如下:
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
如下图所示:
(2)生成指定平台的 so 库,我们打开 gradle,这句代码的意思就是说添加只生成 armeabi-v7a 的库
abiFilters "armeabi-v7a"
如下图所示:
(3)我们把之前生成的 so 的库删掉,不然编译会出问题,因为不能同时有俩个一样的库,如下图所示:
(4)点击编译,编译完成我们就可以在 main 目录下看到我们生成的 armeabi-v7a 的库了,如下图所示:
这个我们就得到了 so 库,这样既保护了我们的代码,又方便别人使用,那么我们要怎么使用呢?