最近项目需要,要做串口的通信,涉及到NDK的编程,在网上查了下资料,发现基本清一色的都是很旧的,抄自几年前同一位大神的模板文,晦涩难懂。CSDN的付费都没法看。其实这几年谷歌一直在做相关的优化,NDK同样也做了很多改进,今天我写一下,算是个总结,方便以后查阅,有兴趣的过来我们可以一起交流一下新的技术。
一、关于旧资料的几点澄清:
1.新建project时,如果想包含NDK编程,已经没有所谓的复选框来选择“include C++”,从Android studio3.3开始,谷歌在模板选择时单独做了一个,直接选择就可以,如下图1.进去以后会有一个CPP的文件夹,里边有一儿c++文件,同时build.gradle也已经配置好了,在默认文件里进行编程修改增删就行,具体的就不再赘述。
PS:Next以后,会让你选择C++ Standard,其中使用下拉列表选择您希望使用哪种 C++ 标准。选择 Toolchain Default 会使用默认的 CMake 设置。
2.网上好多教程涉及到要在命令行进行头文件生成的,我在实际操作的时候并没有这一步,不敢说不对,但是这里我没做过多研究,只是声明一下不需要也行。
3.关于cMake和ndk-build的说明,这是两种编译NDK库的方法,谷歌官方文档写的很是清楚,现在官方默认支持的是cMake,也就是说你现在如果在工程里新建本地库进行NDK编程,你应该用cMake;如果你之前的工程用的是ndk-build,那么Android studio也支持这种方法。至于两者具体的区别,不做赘述,就补充一下,cMake需要对应的脚本文件“CMakeLists.txt”,ndk-build需要两个.mk的文件( Android.mk 、 Application.mk)。本文我们只讲述相关cMake的方法。
二、基础知识废话
Native Develope Kit(NDK):这套工具集允许您为 Android 使用 C 和 C++ 代码,并提供众多平台库,让您可以管理原生 Activity 和访问物理设备组件,例如传感器和触摸输入。
cMake:一款外部构建工具,可与 Gradle 搭配使用来构建原生库。如果您只计划使用 ndk-build,则不需要此组件。
LLDB:一种调试程序,Android Studio 使用它来调试native code。
JNI:Java Native Interface,Java本地接口。
你可以使用 SDK 管理器安装这些组件:
在打开的项目中,从菜单栏选择 Tools > Android > SDK Manager。
点击 SDK Tools 标签。
选中 LLDB、CMake 和 NDK 旁的复选框,如图 2 所示。
从 SDK 管理器中安装 LLDB、CMake 和 NDK。
点击 Apply,然后在弹出式对话框中点击 OK。
安装完成后,点击 Finish,然后点击 OK。
三、关于添加NDK编程
1.创建项目时即包含有NDK编程,如上所述已经讲过。新建完成后,视图如下图3。
在 cpp 组中,您可以找到属于项目的所有原生源文件、标头和预构建库。对于新项目,Android Studio 会创建一个示例 C++ 源文件 native-lib.cpp,并将其置于应用模块的 src/main/cpp/ 目录中。本示例代码提供了一个简单的 C++ 函数 stringFromJNI(),此函数可以返回字符串“Hello from C++”。
2.在已有代码中增加NDK编程,这是本文主要要讲述部分。
四、向现有项目添加C/C++代码
(一)主要步骤:
1.创建新的原生源文件(指代C/C++代码)并将其添加到您的 Android Studio 项目中。
如果您已经拥有原生代码或想要导入预构建的原生库,则可以跳过此步骤。
2.创建 CMake 构建脚本,将您的原生源代码构建到库中。如果导入和关联预构建库或平台库,您 也需要此构建脚本。
如果您的现有原生库已经拥有 CMakeLists.txt 构建脚本,则可以跳过此步骤。
3.提供一个指向您的 CMake 脚本文件的路径,将 Gradle 关联到您的原生库。Gradle 使用构建脚 本将源代码导入您的 Android Studio 项目并将原生库(SO 文件)打包到 APK 中。
(二)创建新的原生源文件
要在应用模块的主源代码集中创建一个包含新建原生源文件的 cpp/ 目录,请按以下步骤操作:
1.从 IDE 的左侧打开 Project 窗格并从下拉菜单中选择 Project 视图。
2.导航到 你的模块> src,右键点击 main 目录,然后选择 New > Directory。
3.为目录输入一个名称(例如 cpp)并点击 OK。
4.右键点击您刚刚创建的目录,然后选择 New > C/C++ Source File。
5.为你的源文件输入一个名称,例如 native-lib。(我的是JNIcpp,只要前后对应就可以)
6.从 Type 下拉菜单中,为您的源文件选择文件扩展名,例如 .cpp。
如果你还希望创建一个标头文件,请选中 Create an associated header 复选框。
点击 OK。
7.在你的.cpp文件中输入以下图片内容;
8.新建JNIhelp类,内容如下:
9.MainActivity中代码如下:
(三)创建 CMake 构建脚本
CMake 构建脚本是一个纯文本文件,你必须将其命名为 CMakeLists.txt。本部分介绍了你应包含到构建脚本中的一些基本命令,用于在创建原生库时指示 CMake 应使用哪些源文件。
1.从 IDE 的左侧打开 Project 窗格并从下拉菜单中选择 Project 视图。
2.右键点击 你的模块 的根目录并选择 New > File。
3.输入“CMakeLists.txt”作为文件名并点击 OK。
编辑内容如下两图图4和图5.(本来想上传高亮代码的,捣鼓了一会不会用传,只能截图了。大家可以先新建一个默认带NDK编程的工程,然后找到这TXT文件,把里边的内容复制过来就行,基本是一样的。)
上图有四个命令函数,基本看名字就能分辨作用,我就不一一写了,网上也能查到,不懂得私信问我也行。还有其他的命令,及添加多个库的方法,这里就不一一写了,大家可以去查。
(四)将 Gradle 关联到原生库
方法1、使用 Android Studio UI
1、从 IDE 左侧打开 Project 窗格并选择 Android 视图。
2、右键点击您想要关联到原生库的模块(例如 app 模块),并从菜单中选择 Link C++ Project with Gradle。您应看到一个如图 4 所示的对话框。
3、从下拉菜单中,选择 CMake 或 ndk-build。
如果你选择 CMake,请使用 Project Path 旁的字段为你的外部 CMake 项目指定 CMakeLists.txt 脚本文件。
4、点击 OK。
方法2、手动配置 Gradle
1.要手动配置 Gradle 以关联到您的原生库,你需要将 externalNativeBuild {} 块添加到模块级 build.gradle 文件中,并使用 cmake {}对其进行配置:
2.指定可选配置
你可以在模块级 build.gradle 文件的 defaultConfig {} 块中配置另一个 externalNativeBuild {} 块,为 CMake 指定可选参数和标志。与 defaultConfig {} 块中的其他属性类似,你也可以在构建配置中为每个产品风格重写这些属性。(一般默认即可,初级阶段不用写)
3.指定 ABI
默认情况下,Gradle 会针对 NDK 支持的 ABI 将你的原生库构建到单独的 .so 文件中,并将其全部打包到您的 APK 中。如果您希望 Gradle 仅构建和打包原生库的特定 ABI 配置,您可以在模块级 build.gradle 文件中使用 ndk.abiFilters 标志指定这些配置,如下所示:
在大多数情况下,你只需要在 ndk {} 块中指定 abiFilters(如上所示),因为它会指示 Gradle 构建和打包原生库的这些版本。不过,如果您希望控制 Gradle 应当构建的配置,并独立于你希望其打包到 APK 中的配置,请在 defaultConfig.externalNativeBuild.cmake {} 块配置另一个 abiFilters 标志。Gradle 会构建这些 ABI 配置,不过仅会打包你在 defaultConfig.ndk{} 块中指定的配置。
五、构建和运行示例应用
点击 Run 后,Android Studio 将在您的 Android 设备或者模拟器上构建并启动一个显示文字“Hello from C++”的应用。下面的概览介绍了构建和运行示例应用时会发生的事件:
1、Gradle 调用您的外部构建脚本 CMakeLists.txt。
2、CMake 按照构建脚本中的命令将 C++ 源文件 native-lib.cpp 编译到共享的对象库中,并命名为 libnative-lib.so,Gradle 随后会将其打包到 APK 中。
3、运行时,应用的 MainActivity 会使用 System.loadLibrary() 加载原生库。现在,应用可以使用库的原生函数 stringFromJNI()(我自己的工程是 sayhello()函数)。
4、MainActivity.onCreate() 调用 stringFromJNI(),这将返回“Hello from C++”并使用这些文字更新 TextView。
六、结尾
得去开会了,没时间写了,基础的过程就是这样,草草收个尾,有时间再写。需要注意的就是,因为好多是截图,是两个工程(一个默认就有NDK编程的,一个是自己新建然后添加C/C++代码的)截图的,可能会有混淆;还有是官方文档的资料复制来的,难免有错误。大家记得函数名和相关地方的名字同意对应就行,来看NDK编程的,肯定是Android做了有段时间了,这些应该没问题。就这样了,第一次发技术文档,代码片段全是截图,谅解。
还有,刚刚发现的,就是应该是先在java类中声明native函数,然后再新建jni文件夹和其中的C/C++文件,再配置,是这样一个流程。新建完C++的空文件(写上包含头文件语句)并配置完CMakeLists.txt以后,文件会全部链接,此时java中的native函数的函数名会变红,光标放上去以后会显示找不到对应的函数,然后按Alt+enter,选择添加,就会自动在C++函数中添加对应的函数。
然后,头文件