使用CMake来进行Android NDK开发

版权声明:本文为博主原创文章,转载必须注明出处!! https://blog.csdn.net/qq_34902522/article/details/78104610

本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

前言

Android NDK开发可能在平时的项目开发中不常用到,但是这并不代表其不重要,  
相反NDK开发是Android开发人员的进阶过程中必须要掌握的技能。  
Android NDK是一组允许将C或C++(原生代码)嵌入到Android应用中的工具。  
如果开发者在需要以下操作的时候,使用NDK开发特别有用:  
*  在平台之间移植其应用
*  从设备获取卓越性能以用于计算密集型应用,例如游戏或物理模拟。  
*  重复使用现有库或者提供自己库供重复使用。  
除此之外,对于ndk的学习,也有助于加深开发者在阅读框架的源码理解。  
ndk开发有两种编译方式,一种是通过ndk-build来构建;  
一种是通过CMake构建原生库。通过CMake构建原生库是Google新提出来的方式,比较方便、强大。  

准备

通过cmake进行ndk开发首先有个要求,需要Android Studio的版本是2.2以上版本(包含2.2)  
,Gradle的版本需要升到2.2.0及以上。  
满足上面的条件下,我们需要下载ndk和构建工具。如下图:  

这里写图片描述

红线标记的三个工具下载好就行。CMake和NDK就不说了,都好理解,  
LLDB呢是一种调试程序,用来调试原生代码的。  

向项目添加原生代码

上面的准备工作做完之后就可以向项目中添加原生代码,构建原生库进行ndk开发了。  
这边有个讨论,向项目中添加原生代码有两种情况:  
一种是新建一个新的项目支持C/C++;  
一种是在已有项目中添加原生代码。  
所以这边相应的也有两种方式。先说第一种方式。  

1.创建支持C/C++的新项目

创建支持原生代码的新项目跟平常开发中创建一个新项目没有太大的区别,说一下不同的地方。  
1.前者在向导的Config your new project界面需要选中  
 Include C++ Support 复选框。如图1:

图一


2.前者在向导的Customize C++ Support 界面会有C++ Standard 的选择  
意思是你希望使用哪种 C++ 标准。  
选择 Toolchain Default 会使用默认的 CMake 设置。  
这里我们选择默认的。  
Exceptions Support:如果你希望启用对 C++ 异常处理的支持,请选中此复选框。  
如果启用此复选框,Android Studio 会将 -fexceptions 标志添加到模块级 build.gradle 文件的   
cppFlags 中,Gradle 会将其传递到 CMake。  
Runtime Type Information Support:如果你希望支持 RTTI,请选中此复选框。  
如果启用此复选框,Android Studio 会将 -frtti 标志添加到模块级 build.gradle 文件的   
cppFlags 中,Gradle 会将其传递到 CMake。  
这里自己看需求选择勾不勾选,这边演示的demo选择勾选。如图2:  

图二

创建项目完成之后,在as的左侧项目结构目录中的app应用模块中可以看到cpp文件夹,  
cpp文件件里面存放有属于项目的所有原生源文件、标头和预构建库。  
对于新项目,Android Studio 会创建一个示例 C++ 源文件 native-lib.cpp  
除了cpp文件夹之外,我们还看到一个CMakeLists.txt的这样一个文件。  
这个文件是CMake的构建脚本,下面会详细说,这里就暂且不说。  
之前有说过新建支持C/C++的项目会提供了一个示例的c++源文件native-lib.cpp,存放在cpp文件夹中  
,我们点开看看内容。

这里写图片描述

恩,是使用C++写的一个方法,返回一个"Hello from C++",我们跟踪进去这个方法,看看哪里调用。

这里写图片描述

我们发现,这个原生方法是在MainActivity中调用的,返回的字符串设置给了TextView。  
通过这两张图我们发现,原生方法通过native关键字来表示、在使用原生库之前,  
需要通过System.loadLibrary(“库名称”)加载、  
原生方法的方法名命名等常见要点。这边就一笔略过。因为本文重点是CMake构建原生库。  
所以ndk的一些基础知识,以及JNI等,就不细说。本文假设读者知道这些。  
这样的一个新的支持原生代码的项目创建之后,并且还自带demo,开发者就可以很方便在上面进行开发。  
假设现在要创建一个原生库进行ndk开发,我们在cpp文件夹下new一个C/C++ Source file ,  
在你new出来的文件编写你的C/C++代码逻辑,然后在CMakeLists.txt配置文件上稍作配置,即可。  
下面会详述CMakeLists.txt的配置。  

2.向现有项目添加原生代码

向现有项目添加原生代码,进行ndk开发,这里选择一个我的项目,空闲时间写的一个APP,  
一款仿今日头条的资讯类软件(求star)-

PalmRead

主要有三个大步骤。第一步:创建新的原生源文件;第二步:创建CMake构建脚本;第三步:将Gradle关联  
到原生库。    
现在我们来看第一步,创建新的原生源文件,首先我们要先在应用模块src/main 目录下  
创建一个cpp文件夹用来存放原生源文件等。  
然后在cpp文件夹下面创建C/C++源文件New > C/C++ Source File。如图:

这里写图片描述

创建了一个名为palmread-lib文件。  
第二步,我们创建CMake构建脚本,也就是CMakeLists.txt文件,在应用模块下new一个file文件,  
命名为CMakeLists.txt即可,  
注意哦,这个文件的名称不能搞错哦。CMakeLists.txt创建好打开后,发现没有任何内容,这就对了。。  
需要我们自己配置的。  
不像是通过第一种新创建支持原生代码的项目那种,还给你写好,不过我们可以参考第一种方式下,系统给我们  
默认生成的内容。  
咱们看一下第一种方式下,系统默认生成的CMakeLists.txt文件的内容是什么样子吧。如图:  

这里写图片描述

这里写图片描述

通过图片我们看到,其实内容也没什么。就cmake_minimum_required()、add_library()  
、find_library、target_link_libraries()。这几个CMake命令,每个CMake命令都有英文介绍很好理解。  
比如add_library创建和命名一个库,这边名称我们就填palmread-lib,种类分为static和shared,  
具体区别嘛移步:

static和shared的区别

这里我们选择SHARED,然后就是提供一个library的相对路径。只有在CMakeLists.txt文件中配置了该命令  
,才能找到编译这个库。  
其他的一些CMake命令大家自行搜索了解,都不是很难,很好理解,这里篇幅有限就不细说了。  
那现在我们可以按照系统提供的模板,基于自己的项目写了一份CMakeLists.txt文件,代码如下:  

这里写图片描述
随后在Java类中加载palmread-lib库,这里我这边写了一个NdkHelper类,专门用来定义native方法的:
这里写图片描述
这一步做完后,第二步也算告一段落了,现在我们来看第三步:将 Gradle 关联到你的原生库。
将gradle关联到原生库有两种方式,这里就先说第一种比较简单的方式,第二种下篇博文再说。
第一种方式是通过as的快捷键来实现的,右键点击你想要关联到原生库的模块(例如 app 模块),
并从菜单中选择 Link C++ Project with Gradle。
BuildSystem选择CMake,projectpath就是CMakeLists.txt文件的路径。点击ok完成。
你会在应用模块的build.gradle文件中发现,android闭包里出现了

externalNativeBuild {
        cmake {
            path 'CMakeLists.txt'
        }
    }

这个语句就跟我们之前说的第二种方式有关系,这里先不说了,后面博文再说。

同步项目后,突然想到之前新建的palmread-lib.c文件好像还没有写C代码呢,呀,这脑子,没事,我们现在写。  
写些什么呢?这样吧我们用C来实现这样一个功能,接受一个字符串参数,然后对字符串进行拼接修改操作  
,使得返回一个新的字符串。  
代码如下:

这里写图片描述

代码写好之后,就是去调用了,为了方便测试,我们选在在应用的首页activity去调用这个原生方法。  
通过toast显示方法返回的值。  
如图:

这里写图片描述

通过代码,我们可以看出,我们调用了,NdkHelper.GetStringFromC()这个原生方法,  
传入一个“欢迎来到PalmRead”字符串作为参数。按照之前的C逻辑,应该会返回一个新的字符串为  
“欢迎来到PalmRead from c”。  
那我们运行程序试试效果吧。  

这里写图片描述

O(∩_∩)O哈!,我们发现toast显示的值确实是我们设想的返回值。这样就架起了Java与原生代码之间的桥梁。  
现在我们可以应用模块的build/outputs/apk目录下,打开我们的apk,我们会发现,我们创建的原生文件,  
编译成了原生库"libpalmread-lib.so"也打包进了apk文件。如图:  

这里写图片描述


结语

好了,关于CMake来进行Android NDK开发,大致的流程就是这样。CMakeLists的一些命令 还有Gradle关联原生库的第二种通过编辑build.gradle文件的方式 , 通过CMake来进行ndk开发之补充篇 有详细说明。现在,总览全貌,整体下来是不是比ndk-build方便很多呢。

猜你喜欢

转载自blog.csdn.net/qq_34902522/article/details/78104610