android studio 使用CMAKE
前言
之前,每次需要边写C++代码的时候,我的内心都是拒绝的。
1. 它没有代码提示!!!这意味着我们必须自己手动敲出所有的代码,对于一个新手来说,要一个字母都不错且大小写也要正确,甚至要记得住所有的jni函数等,真是太折磨人了…平时写Java代码的时候都是写几个字母会出来一大堆提示然后选择的,这样还有一个好处就是很多时候我们不知道有那些函数,但是我们可以通过obj.
,然后就可以看到它有哪些方法函数了。
2. 很多地方会显示为红色,就像是错误提示的那种,当然,如果没错的话还是能编译运行的,但是如果像编写java代码一样,写错的地方才给我红色显示不是更好吗?
这两个问题可折磨死我这个强迫症了…在网上百度了很久如何能够使用Android Studio编写C++代码时有代码提示自动补全功能,但是一直没有找到有效的(不使用CMake的情况下,若有人知道,麻烦告知)。好在一次偶然的机会,在网上看到在
Android Studio 2.2 中愉快地使用 C/C++这篇文章,看到上面说Android
Studio2.2版本完善了对C/C++的支持,还提及到CMAKE,赶紧把Android
Studio从2.0版本升级到了2.2版本,按照介绍新建了一个NDK工程,发现里面居然有我梦寐以求的C++代码自动补全提示!!!喜大普奔!!!
赶紧了解学习下Android Studio2.2版本提供的CMAKE方式。打算以后都使用这种方式了,别的不说,就冲可以有C++代码自动补全提示这个功能我就爱上它了。
工具安装
Android Studio升级到2.2之后,我们可以先配置好NDK开发的一些所需工具,如图,在SDK Tools中勾选安装CMake、LLDB、NDK。
CMake: 外部构建工具。如果你准备只使用 ndk-build 的话,可以不使用它。
LLDB: Android Studio上面调试本地代码的工具。
Android Studio自带DEMO了解CMAKE
Android Studio升级到2.2版本之后,在创建新的project时,界面上多了一个Include C++ Support
的选项。勾选它之后将会创建一个默认的C++与JAVA混编的Demo程序。就让我们先来看看这个官方标准Demo吧。
开始之前最好先下载好NDK,见NDK开发 从入门到放弃(一:基本流程入门了解),即在Project Structure界面Android NDK location处下载或选择正确的路径。或者使用上方提供的工具安装方法来进行下载。否则,创建的新project也会报错,需要配置好后clean。
File -> New -> New Project,在如下界面中勾选Include C++ Support
,然后一路 Next,直到 Finish 为止即可。
项目打开后我们查看目录结构,与常规项目不同的是多了.externalNativeBuild文件夹、cpp文件夹、CMakeLists.txt文件,如下图:
这三个东西都是NDK部分:
1. .externalNativeBuild文件夹:cmake编译好的文件, 显示支持的各种硬件等信息。系统生成。
2. cpp文件夹:存放C/C++代码文件,native-lib.cpp文件是该Demo中自带的,可更改。需要自己编写。
3. CMakeLists.txt文件:CMake脚本配置的文件。需要自己配置编写。
Gradle中也有两处不同:
java代码:
- public class MainActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- // Example of a call to a native method
- TextView tv = (TextView) findViewById(R.id.sample_text);
- tv.setText(stringFromJNI());
- }
- /**
- * A native method that is implemented by the 'native-lib' native library,
- * which is packaged with this application.
- */
- public native String stringFromJNI();
- // Used to load the 'native-lib' library on application startup.
- static {
- System.loadLibrary("native-lib");
- }
- }
从native-lib.cpp的代码中我们能看到它使用的是静态注册的方式,动态注册的方式代码同传统JNI。
- #include <jni.h>
- #include <string>
- extern "C"
- jstring
- Java_com_example_person_myapplication_MainActivity_stringFromJNI(
- JNIEnv* env,
- jobject /* this */) {
- std::string hello = "Hello from C++";
- return env->NewStringUTF(hello.c_str());
- }
CMakeLists.txt文件中我们需要注意的是下面这三个地方。两个library的名字(需一致)以及一个cpp文件的路径,彼此需要对应一致,当我们自己定义library以及自己创建cpp文件时需要对应修改。
运行代码,就能看到效果,调用了C++方法在界面上显示了Hello from C++
字符串。这就是CMake方式进行NDK开发的Demo。
还记得传统JNI方式中吗?我们使用了ndk
-build来编译C/C++文件为so文件,对于使用过第三方库的开发者来说,对so肯定不陌生。我们只能使用别人给的so文件,而无法看到C/C++源码,更别说去修改了。但是在这里我们好像一直没看到so文件的影子,那么,我们安装运行的apk中,有对应的so文件吗?如果想验证一下apk是否有so文件,我们可以使用
APK Analyzer:
- 选择 Build > Analyze APK。
- 选择 apk,并点击 OK。
- 如下图,在 APK Analyzer 窗口中,选择 lib/x86/,可以看见 libnative-lib.so 。
Tips:Instant Run 并不兼容使用了 native code 的项目。Android Studio 会自动禁止 Instant Run 功能。
但是我个人目前更关注的问题是C++代码自动补全提示的功能,当在cpp文件中写代码时,里面不再是一大片的红色,输入若干个字母的时候,也能给出提示了,简直叼渣天,至于原因…我就不清楚了,为什么在这里就有这个强大的功能了呢?哪位大神能解释下…
CMake编译so文件
CMake和传统 JNI在目录结构和配置文件上的区别
现在我们有了CMake和传统JNI两种开发NDK的方法,它们在目录结构和Gradle上有所区别,下面我们将分别介绍目录区别和Gradle配置的区别。
一、目录结构
传统JNI
CMake
这两种方式在目录上的区别就是两点:
1. 以前的jni目录改成cpp,名字更换了,下面还是存放C/C++文件。
2. 之前对C/C++文件的编译配置Android.mk、Application.mk文件放在jni目录下,现在改成CMakeLists.txt文件。(事实上这些文件的位置是可任意存放的,只需要配置好就行。但最好还是按照默认习惯放置。)
二、Gradle
传统JNI
CMake
事实上,我们在使用传统JNI方式的时候,上面的两处地方我们都省略了,也不会造成什么异常(若Android.mk存放位置在其他地方则需要配置)。CMake方式中第一处也可省略,但是第二处不能省略(同样,位置路径要写对),因为没有它将无法Build生成.externalNativeBuild文件夹。
另外,传统JNI开发还需要在项目根目录下的gradle.properties文件中配置
android.useDeprecatedNdk=true
- 1
- 1
否则Build项目的时候会报错。
CMake的优势
- 可以直接的在C/C++代码中加入断点,进行调试
- java引用的C/C++中的方法,可以直接ctrl+左键进入
- 对于include的头文件或者库,也可以直接进入
- 不需要配置命令行操作,手动的生成头文件,不需要配置android.useDeprecatedNdk=true属性
普通Android项目转NDK开发项目
我们之前说了,在创建新project时若勾选了Include C++ Support
选项(需Android Studio版本不低于2.2),则该项目就已经是一个NDK开发项目了。那么,若项目已经存在,该如何再转为NDK开发项目呢?
Tips: 在配置好NDK的前提下。且各种地方的配置均不再赘述。如Android.mk中如何配置、CMakeLists.txt文件中的配置、各个地方的统一等。
传统JNI方式,在NDK开发 从入门到放弃(一:基本流程入门了解)中我们了解过:
- 新建jni目录,写好C/C++代码。静态注册JNI时我们使用了javah -jni对JAVA类进行操作自动生成了jni目录以及对应的头文件(事实上,当我们有一定经验后可以自己写,而不再需要使用该辅助命令来保证不写错,另外动态注册也是一个很值得提倡的方式),然后根据头文件写了C/C++代码。但在动态注册JNI时我们可以自己先创建好jni目录且写好C/C++代码。
- 在jni目录下创建且配置好Android.mk和Application.mk两个文件。
- build.gradle文件中根据情况进行配置,可不进行配置使用默认值。
- 通过ndk-build操作,我们能得到对应的so文件,放置在相应位置,java代码中即可调用C/C++代码,运行程序。
回顾前面提到的CMake方式的NDK开发,我们得到如下步骤:
- 新建cpp目录,写好C/C++代码。
- 创建且配置CMakeLists.txt文件。
- build.gradle文件中根据情况进行配置,CMakeLists.txt文件的路径必须配置。
- java代码中即可调用C/C++代码,运行程序。
- project的build.gradle文件中,gradle版本不能低于2.2,否则会报错。
关联本地库与 Gradle
为了将本地库与 Gradle 相关联,你需要在 CMake 或 ndk-build 构建脚本中提供一个路径地址。当你构建你的 APP 时,Gradle 会将 CMake 或 ndk-build 作为一个依赖运行,然后将共享库(.so 文件)打包到你的 APK 中。Gradle 同样使用构建脚本来识别哪些文件需要导入到 Android Studio 项目,你可以从 Project 窗口面板中看到相应的文件。如果你还没有一个为 native sources 准备的构建脚本,你需要先创建一个。
使用 Android Studio 图形化界面
你可以使用 Android Studio 的图形化界面来将 Gradle 与外部 CMake 或者 ndk-build 项目关联起来。
- 打开 IDE 左边的 Project 面板,选择 Android 视图。
- 右键点击你想链接本地库的 module,比如 app module,然后从菜单中选择 Link C++ Project with Gradle。你应该能看见一个和下图很像的对话框。
在下拉菜单中,选择 CMake 或者 ndk-build。
a. 如果你选择 CMake,需要在 Project Path 中指定CMakeLists.txt
脚本文件的路径。
b. 如果你选择 ndk-build,你需要在 Project Path 中指定Android.mk
脚本文件的路径。
点击 OK。
手动配置 Gradle
如果要手动将 Gradle 与你的本地库相关联,你需要在 module 层级的 build.gradle 文件中添加 externalNativeBuild {}
代码块,并且在该代码块中配置 cmake {}
或 ndkBuild {}
:
- android {
- ...
- defaultConfig {...}
- buildTypes {...}
- // Encapsulates your external native build configurations.
- externalNativeBuild {
- // Encapsulates your CMake build configurations.
- cmake {
- // Provides a relative path to your CMake build script.
- path "CMakeLists.txt"
- }
- }
- }
可选配置
你可以在你的 module 层级的 build.gradle 文件中的 defaultConfig {}
代码块中,添加 externalNativeBuild {}
代码块,为 CMake 或 ndk-build 配置一些额外参数。当然,你也可以在你的构建配置中的其他每一个生产渠道重写这些属性。
比如,如果你的 CMake 或者 ndk-build 项目中定义了多个本地库,你想在某个生产渠道使用这些本地库中的几个,你就可以使用 targets
属性来构建和打包。下面的代码展示了一些你可能会用到的属性:
- android {
- ...
- defaultConfig {
- ...
- // This block is different from the one you use to link Gradle
- // to your CMake or ndk-build script.
- externalNativeBuild {
- // For ndk-build, instead use ndkBuild {}
- cmake {
- // Passes optional arguments to CMake.
- arguments "-DCMAKE_VERBOSE_MAKEFILE=TRUE"
- // Sets optional flags for the C compiler.
- cFlags "-D_EXAMPLE_C_FLAG1", "-D_EXAMPLE_C_FLAG2"
- // Sets a flag to enable format macro constants for the C++ compiler.
- cppFlags "-D__STDC_FORMAT_MACROS"
- }
- }
- }
- buildTypes {...}
- productFlavors {
- ...
- demo {
- ...
- externalNativeBuild {
- cmake {
- ...
- // Specifies which native libraries to build and package for this
- // product flavor. If you don't configure this property, Gradle
- // builds and packages all shared object libraries that you define
- // in your CMake or ndk-build project.
- targets "native-lib-demo"
- }
- }
- }
- paid {
- ...
- externalNativeBuild {
- cmake {
- ...
- targets "native-lib-paid"
- }
- }
- }
- }
- // You use this block to link Gradle to your CMake or ndk-build script.
- externalNativeBuild {
- cmake {...}
- // or ndkBuild {...}
- }
- }
指定 ABI
一般情况下,Gradle 会将你的本地库构建成 .so
文件,然后将其打包到你的 APK 中。如果你想 Gradle 构建并打包某个特定的 ABI 。你可以在你的 module 层级的 build.gradle 文件中使用 ndk.abiFilters
标签来指定他们:
- android {
- ...
- defaultConfig {
- ...
- externalNativeBuild {
- cmake {...}
- // or ndkBuild {...}
- }
- ndk {
- // Specifies the ABI configurations of your native
- // libraries Gradle should build and package with your APK.
- abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
- 'arm64-v8a'
- }
- }
- buildTypes {...}
- externalNativeBuild {...}
- }
大多数情况,你只需要像上面的代码那样,在 ndk {}
代码块中指定 abiFilters
即可。如果你想控制 Gradle 构建、依赖你希望的东西,你就需要在 defaultConfig.externalNativeBuild.cmake {}
代码块或 defaultConfig.externalNativeBuild.ndkBuild {}
代码块中,配置其他的 abiFilters
标签。Gradle 会构建这些 ABI 配置,但是只会将 defaultConfig.ndk {}
代码块中指定的东西打包到 APk 中。
android studio 使用CMAKE的更多相关文章
- android studio使用CMake和NDK,实现应用自身被卸载时打开某一网址
实现应用自身被卸载时打开某一网址的c代码 MyActivity: public class MyActivity extends Activity { /** * Called when the ac ...
- 【Android Studio安装部署系列】二十五、Android studio使用NDK生成so文件和arr文件
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 Android Studio使用ndk的简单步骤. NDK环境搭建 下载NDK 下载链接:https://developer.and ...
- OpenCV - Android Studio 2.2 中利用CAMKE进行OpenCV的NDK开发
我在http://www.cnblogs.com/fx-blog/p/8206737.html一文中提到了如何在Android Studio中Java层导入OpenCV(包含opencv_contri ...
- Android开发学习之路--Android Studio cmake编译ffmpeg
最新的android studio2.2引入了cmake可以很好地实现ndk的编写.这里使用最新的方式,对于以前的android下的ndk编译什么的可以参考之前的文章:Android开发学习之路– ...
- 通过android studio的gradle强制cmake输出命令详情
https://stackoverflow.com/questions/43439549/force-cmake-in-verbose-mode-via-gradle-and-the-android- ...
- 将应用代码由eclipse导入Android studio的方法NDK-Build和Cmake两种方法(以android_serialport_api为例)
网上翻了几百篇博客,看了半天,要不就是写的乱七八糟看不懂,要不就是隐藏了一些细节,要不就是实现不了,最后还是在Android官网上看明白了,而且说得有条有理,以后遇到不懂的一定要先翻官网. 参考资料: ...
- android ndk-build 编译静态库libxx.a 以及Android studio openssl 静态库配置(cmake)
android ndk-build 编译静态库libxx.a 需求场景: 目前有安卓编码好的现在的openssl的两个.a,我们需要调用openssl的函数,并把功能再封装成.a; 这样使用时,在an ...
- Android Studio 2.2以上支持了Cmake的配置JNI的相关参数
Android Studio 2.2以上支持了Cmake的配置JNI的相关参数,简化了通过Android.mk配置.并很好的继承了C++的编辑方式.以下是对应的引入第三方so和第三方.cpp文件的路径 ...
- Android Studio中通过CMake使用NDK并编译自定义库和添加预编译库
Note:这篇文章是基于Android Studio 3.01版本的,NDK是R16. step1:创建一个包含C++的项目 其他默认就可以了. C++ Standard 指定编译库的环境,其中Too ...
随机推荐
- FairyGUI学习
官网:http://www.fairygui.com/ 教程:http://www.taikr.com/course/446/tasks 博客:http://gad.qq.com/article/de ...
- Unity3D Android手机屏幕分辨率问题
Android手机屏幕分辨率五花八门,导致开发时不好把握,还好各个引擎对这个屏幕分辨率问题都有较好的处理方式:unity3D 也为我们提供了一个不错的解决方案. 在Unity3D 进行 android ...
- 怎么输入MathType不等号
MathType是一款比较常用的数学公式编辑器,我们在使用这款软件的时候常常需要输入各种符号.有些新用户对这款软件不是很熟悉,对于一些符号不知道怎么输入,下面我们来给大家介绍介绍MathType不等号 ...
- Maven------pom.xml自动加载各种类库代码
转载: http://lavasoft.blog.51cto.com/62575/1388866/ 一般要加<type>jar</type> <dependency> ...
- python常用内置模块,执行系统命令的模块
Subprocess模块 python3.5将使用Subprocess模块跟操作系统进行交互,比如系统命令,他将替换 os.system os.spawn* subprocess.run()方法封装的 ...
- Python zmail 模块
zmail 是 python3 用来收发邮件的一个模块,用法参考: https://mp.weixin.qq.com/s?__biz=MzAxMjUyNDQ5OA==&mid=26535559 ...
- eclipse启动错误
1.错误日志 !SESSION 2013-12-09 12:24:33.826 -----------------------------------------------eclipse.build ...
- JS AJAX传递List数组到后台(对象)
今天在写代码的时候,碰到的问题,百度了一下,发现原来AJAX传递List数据是可以的,之前还一直用JSON序列化(new Array()数组设置)进行传值的. var _list = {}; //等价 ...
- 【BZOJ4545】DQS的trie 后缀自动机+LCT
[BZOJ4545]DQS的trie Description DQS的自家阳台上种着一棵颗粒饱满.颜色纯正的trie. DQS的trie非常的奇特,它初始有n0个节点,n0-1条边,每条边上有一个字符 ...
- ios UITableView默认选中第一行
NSIndexPath *ip = [NSIndexPath indexPathForRow:0inSection:0]; [titleTableViewselectRowAtIndexPath:ip ...