Android Studio 3.5 JNI (ndk-build)
记录下 Android Studio 嵌入 C 代码的过程,使用 ndk-build.
当前环境:Android Studio 3.51 NDK 20.1
创建 JNI 文件夹
Android结构下,直接在项目右键,选择 New - Folder - JNI Folder ,对话框直接点击 Finish 即可方便地在默认位置创建 jni 文件夹用于存放 c 源码。默认位置在 app/src/main/jni.
创建 Java 类
package cn.sh.changxing.myled;public class JniLib { static { System.loadLibrary("JniLib"); } public native int led_open(); public native int led_close(); public native int ledIoctl(int num, int en);}
生成头文件 (.h)
这边可以在External Tools中配置:
每次都这样搞一遍很麻烦,我们可以配置一下扩展工具,这样一劳永逸。
点击File - Setting - Tools - External Tools 打开外部工具配置页,点击 + 新建一个工具。
先起个名字叫,这里叫做 javah.
Program: J D K P a t h JDKPath JDKPath\bin\javah.exe
Arguments: -classpath . -jni -d M o d u l e F i l e D i r ModuleFileDir ModuleFileDir\src\main\jni F i l e C l a s s FileClass FileClass
Working directory: M o d u l e F i l e D i r ModuleFileDir ModuleFileDir\src\main\Java
(上面三行直接复制添加)点击 OK 保存后就新建了一个工具。此时我们右击 JniTest.java,在菜单中选择 External Tools - javah 就可以快速生成头文件并放到 jni 目录。
/* DO NOT EDIT THIS FILE - it is machine generated */#include /* Header for class cn_sh_changxing_myled_JniLib */#ifndef _Included_cn_sh_changxing_myled_JniLib#define _Included_cn_sh_changxing_myled_JniLib#ifdef __cplusplusextern "C" {#endif/* * Class: cn_sh_changxing_myled_JniLib * Method: led_open * Signature: ()I */JNIEXPORT jint JNICALL Java_cn_sh_changxing_myled_JniLib_led_1open (JNIEnv *, jobject);/* * Class: cn_sh_changxing_myled_JniLib * Method: led_close * Signature: ()I */JNIEXPORT jint JNICALL Java_cn_sh_changxing_myled_JniLib_led_1close (JNIEnv *, jobject);/* * Class: cn_sh_changxing_myled_JniLib * Method: ledIoctl * Signature: (II)I */JNIEXPORT jint JNICALL Java_cn_sh_changxing_myled_JniLib_ledIoctl (JNIEnv *, jobject, jint, jint);#ifdef __cplusplus}#endif#endif
编写 c 代码
//// Created by cheng on 2019/10/26.// #include #include #include #include #include #include #include #include #include #include #include #include #include "cn_sh_changxing_myled_JniLib.h" #undef TCSAFLUSH #define TCSAFLUSH TCSETSF #ifndef _TERMIOS_H_ #define _TERMIOS_H_ #endif int fd=0; JNIEXPORT jint JNICALL Java_cn_sh_changxing_myled_JniLib_led_1open (JNIEnv *env, jobject obj) { if(fd<=0)fd = open("/dev/leds", O_RDWR|O_NDELAY|O_NOCTTY); if(fd <=0 )__android_log_print(ANDROID_LOG_INFO, "serial", "open /dev/leds Error"); else __android_log_print(ANDROID_LOG_INFO, "serial", "open /dev/leds Sucess fd=%d",fd); } /* * Class: com_topeet_ledtest_led * Method: Close * Signature: ()I */ JNIEXPORT jint JNICALL Java_cn_sh_changxing_myled_JniLib_led_1close (JNIEnv *env, jobject obj) { if(fd > 0)close(fd); } /* * Class: com_topeet_ledtest_led * Method: Ioctl * Signature: ()I */ JNIEXPORT jint JNICALL Java_cn_sh_changxing_myled_JniLib_ledIoctl (JNIEnv *env, jobject obj, jint num, jint en) { ioctl(fd, en, num); }
创建 mk 文件
mk 文件用于告诉 ndk-build 该如何编译 c 源码,详情见官方指南。
在 jni 目录下创建 Android.mk:
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_LDLIBS += -llogLOCAL_LDLIBS +=-lmLOCAL_MODULE := JniLibLOCAL_SRC_FILES =: JniLib.cinclude $(BUILD_SHARED_LIBRARY)
其中 LOCAL_SRC_FILES 列出了所有要编译的 c 源码文件
然后创建 Application.mk:
APP_MODULES := JniLibAPP_ABI := all
在 module 的 build.gradle 里,amndroid.defaultConfig 下加入下面配置:
代码:
ndk{ moduleName "JniLib" //abiFilters \"armeabi-v7a", "x86" //输出指定abi下的so库 } sourceSets.main{ jni.srcDirs = [] jniLibs.srcDir "src/main/libs" }
编译:
编译需要使用 ndk-build,其位于 ndk 目录下。如果要直接在命令行使用需要添加环境变量。类似的,为了方便我也添加了一个外部工具。
注意改成你自己的目录。
Program: D:\Android_sdk\ndk\20.0.5594570\build\ndk-build.cmdWorking directory: F:\android_project\Myled
任意找个第地方右击,选择 External Tools - ndk-build 即可编译 c 源码。成功后可以看见创建了 libs 目录,里面包含了不同平台下的 so 文件。
运行
最后修改下 Activity 的代码:
package cn.sh.changxing.myled;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.view.View;public class MainActivity extends AppCompatActivity { private JniLib jniTest = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); jniTest = new JniLib(); jniTest.led_open(); } public void led1_en(View view) { //Toast.makeText(this, "test", Toast.LENGTH_SHORT).show(); jniTest.ledIoctl(0, 1); } public void led1_off(View view) { jniTest.ledIoctl(0, 0); } public void led2_en(View view) { jniTest.ledIoctl(1, 1); } public void led2_off(View view) { jniTest.ledIoctl(1, 0); } }
参考:https://blog.csdn.net/slaughteryou/article/details/88235000
更多相关文章
- Android -- 消息处理机制源码分析(Looper,Handler,Message)
- Gears Android WIFI/基站定位源代码分析
- 安卓学习(初)第三章(2)(《第一行代码》)
- Android 国际化工具 Android Localizer
- 《第一行代码Android》阅读笔记
- Android源码阅读之MessageQueue
- 白话开发——Android Studio代码调试技巧篇
- Android 导入android源码有错,R.java文件不能自动生成解决方法