AS2.2使用CMake方式进行JNI/NDK开发
之前写过一篇比较水的文章Android手机控制电脑撸出HelloWorld
里面用到了JNI/NDK技术。
这篇文章给大家介绍下JNI/NDK开发。采用的是Android Studio2.2开发环境,使用CMake方式进行开发。
JNI(Java Native Interface)是java与C/C++进行通信的一种技术,使用JNI技术,可以java调用C/C++的函数对象等等,Android中的Framework层与Native层就是采用的JNI技术。
我们知道,Android系统是基于linux开发,采用的是linux内核 ,Android APP开发大部分也要和系统打交道,只是Android FrameWork 帮我们处理了和系统相关的操作, 我们从Android 系统的分成结构可以看出,Android FrameWork是通过JNI与底层的C/C++库交互,例如:FreeType,OpenGL,SQLite,音视频等等。
如果我们程序也需要调用自己的C/C++函数库,就必须用到JNI/NDK开发。
NDK配置(最新的CMake方式)
Android Studio2.2版本已经完全支持ndk开发了。而且默认采用CMake方式。(传统方式不过多介绍了)
CMake的优势
- 可以直接的在C/C++代码中加入断点,进行调试
- java引用的C/C++中的方法,可以直接ctrl+左键进入
- 对于include的头文件,或者库,也可以直接的进入
- 不需要配置命令行操作,手动的生成头文件,不需要配置
android.useDeprecatedNdk=true
属性
下载
首先需要下载NDK,来到设置界面点击下载NDK
安装完NDK,还可以选择配置一些工具。
- CMake: 外部构建工具。如果你准备只使用 ndk-build 的话,可以不使用它。(Android Studio2.2默认采用CMake)
- LLDB: Android Studio上面调试本地代码的工具。
创建项目
Android Studio升级到2.2版本之后,在创建新的project时,界面上多了一个Include C++ Support的选项。勾选它之后将会创建一个默认的C++与JAVA混编的Demo程序。
然后一路 Next,直到 Finish 为止即可。
上面图的这三个文件都是默认生成的NDK项目的一部分:
1. .externalNativeBuild文件夹:cmake编译好的文件, 显示支持的各种硬件等信息。系统生成。
2. cpp文件夹:存放C/C++代码文件,native-lib.cpp文件是默认生成的,可更改。需要自己编写。
3. CMakeLists.txt文件:CMake脚本配置的文件。需要自己配置编写。
app/build.gradle也有所不同
如果你在创建工程选择C++11的标准,则使用cppFlags “-std=c++11”
externalNativeBuild {
cmake {
cppFlags "-std=c++11"
}
}
来看一下,CMakeLists.txt文件中的具体配置
这个文件#开头的全是注释,里面不是注释的只有下面的内容。
cmake_minimum_required(VERSION 3.4.1) #指定cmake版本
add_library( #生成函数库的名字
native-lib
SHARED #生成动态函数看
src/main/cpp/native-lib.cpp ) #依赖的cpp文件
find_library( #设置path变量的名称
log-lib
#指定要查询库的名字
log ) #在ndk开发包中查询liblog.so函数库(默认省略lib和.so),路径赋值给log-lib
target_link_libraries( #目标库,和上面生成的函数库名字一至
native-lib
#连接的库,根据log-lib变量对应liblog.so函数库
${log-lib} )
java代码
public class MainActivity extends AppCompatActivity {
// 加载函数库
static {
System.loadLibrary("native-lib");
}
@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());
}
/**本地方法, 当前方法是通过C/C++代码实现*/
public native String stringFromJNI();
}
上面java代码中的 stringFromJNI()方法用native关键字修饰,这个方法是通过C/C++代码实现的。
native-lib.cpp 代码
#include <jni.h>
#include <string>
extern "C"
jstring
Java_com_a520wcf_jniproject_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
上面的C++代码,定义的函数名是固定写法,Java_包名_类名_Java中方法名 ,通过这种命名方式就可以唯一对应到java中具体的方法,从而具体实现java中的native方法。
运行项目
修改完C/C++代码需要点击“锤子”图标进行编译,然后运行项目。
运行代码,就能看到效果,调用了C++方法在界面上显示了Hello from C++字符串。
如果你不是使用CMake而是使用传统方式进行开发,这时候就会使用了ndk -build来编译C/C++文件为so文件。
那么,我们安装运行的apk中,有对应的so文件吗?
如果想验证一下apk是否有so文件,我们可以使用 APK Analyzer查看。
选择 Build > Analyze APK。
选择 apk,并点击 OK。
当前项目debug阶段的apk默认路径为 app/build/outputs/apk/app-debug.apk
如下图,在 APK Analyzer 窗口中,选择 lib/x86/,可以看见 libnative-lib.so 。
.so文件是动态函数库,写好的c/c++代码默认打包成函数库,就没法看到代码,只能使用了。
如果我们想在工程中使用其他人编译好的函数库,只需要根据不同的cpu架构把函数库在src/main/jniLibs目录下。
在java代码中也需要引入相应的函数库,编写一样的native方法。
手动添加native方法
上面我们主要介绍程序自动生成的代码,接下来我们自己动手写写。
我们也可以在MainActivity中写一个native方法。
有红色警告,因为当前方法并没有找到对应的底层代码的实现。我们可以在报错的地方按下万能的快捷键alt+回车。
选择第一项,就会自动生成对应的底层方法。
参考之前的方法,照着葫芦画瓢,把错误先修复下。
修改MainActivity代码,调用我们写的native方法。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(stringFromJNI2());//调用新写的native方法
}
编译运行当前程序。
运行结果:
可以看到我们成功调用了我们自己创建的native方法。
更多精彩请关注微信公众账号likeDev
AS2.2使用CMake方式进行JNI/NDK开发的更多相关文章
- JNI/NDK开发
公司的新需求终于解决完了,离测试和发布还有段时间,第一次体验了下没需求没bug的感觉,真是舒爽~然后翻了翻有什么可以学的.无意翻到了Android后期发展的五大趋势.一.性能优化.二.高级UI.三.J ...
- JNI/NDK开发指南(开山篇)
转载请注明出处:http://blog.csdn.net/xyang81/article/details/41759643 相信很多做过Java或Android开发的朋友经常会接触到JNI方面的技术, ...
- android Jni NDK开发环境搭建及其简单实例的编写
android Jni NDK开发环境搭建及其简单实例的编写 由于工作需要,需要采用开发想要的JNI,由于之前没有接触过安卓的开发,所以更加网上的帖子,学习了下.遇到了些问题,然后总结下学习过程中 ...
- Android JNI/NDK开发教程
JNI/NDK开发指南:http://blog.csdn.net/xyang81/article/details/41759643
- JNI/NDK开发指南(一)—— JNI开发流程及HelloWorld
转载请注明出处:http://blog.csdn.net/xyang81/article/details/41777471 JNI全称是Java Native Interface(Java本地接口)单 ...
- Android JNI(NDK)开发总结
早就知道Java有个jni可以调用本地化代码,一直没有动力去研究它,现在公司想通过在Android中调用本地化代码来申请较多的内存以突破Android对单个进程的内存限制,这确实是可行的:我的Nexu ...
- Android学Jni/Ndk 开发记录(一)
治疗拖延症的唯一办法就是:一想起些什么 / 要做些什么就 TM 立马去做! 是的,突然想起我不会 JNI.NDK 开发.解决办法:立马去学! 一:配置 NDK 环境 下载 NDK 写入到配置文件 ...
- 超简单的JNI——NDK开发教程
不好意思各位,我按照网上一些教程进行JNI开发,折腾了半天也没成功,最后自己瞎搞搞定了,其实超简单的,网上的教程应该过时了,最新版的AS就包含了NDK编译的功能,完全不用手动javah,各种包名路径的 ...
- JNI NDK开发Crash错误定位 调试
总结: 搜索backtrace 然后: $ /d/android-ndk-r10c/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86 ...
随机推荐
- php 网页内容抓取
最近抓的2个网站内容的代码 列表页抓取:第一种使用phpquery插件,可以快速获取,第二种它是api,所以直接获取 load_third("phpQuery.php"); /** ...
- pip报错ImportError: cannot import name main
编辑pip sudo gedit /usr/bin/pip 修改pip文件: 源文件 from pip import main if __name__ == '__main__': sys.exit( ...
- mysql高级教程(二)-----性能分析
MySQL常见瓶颈 1.cpu SQL中对大量数据进行比较.关联.排序.分组 2.IO a.实例内存满足不了缓存数据或排序等需要,导致产生大量物理 IO. b.查询执行效率低,扫描过多数据行. 3.锁 ...
- Jeecms之JSP访问action类
因为Jeecms采用spring容器管理类,在web容器加载的时候类都已经实例化好了.我们可以通过在JSP中访问spring上下文的方式来调用action业务类例: ApplicationContex ...
- jeecms首页模板自定义
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/qxy369/article/details/50387465我们在点击[查看首页]时,发现出现的并不 ...
- 【DM8168学习笔记5】EZSDK目录结构
EZSDK5.02的目录结构与之前的版本不同,之前的版本各个组件都放在/ezsdk目录下,5.02做了整合. 之前版本:(图片摘自:3.DM816x_1-day_Workshop-Getting_St ...
- /etc/inittab配置文件详解
init的进程号是1,从这一点就能看出,init进程是系统所有进程的起点,Linux在完成核内引导以后,就开始运行init程序,init程序需要读取设置文件/etc/inittab.inittab是个 ...
- vim编辑器操作②
本文主要介绍vim的常用编辑命令: 字符编辑: x:删除光标所在处的字符: #x:删除光标所在处起始的#个字符: 替换命令: r:替换光标所在处的字符: rCHAR; 例如:替换list中的l为大写L ...
- Redis 混合存储最佳实践指南
Redis 混合存储实例是阿里云自主研发的兼容Redis协议和特性的云数据库产品,混合存储实例突破 Redis 数据必须全部存储到内存的限制,使用磁盘存储全量数据,并将热数据缓存到内存,实现访问性能与 ...
- Codeforces 222B 数组行列交换操作
/*做完这题发现自己好水,太伤人了.... 不过还是学到一些,如果直接暴力模拟的话肯定是TLM.. 所以要用虚拟数组来分别保存当前数组的每行没列在初始数组中的位置...*/ #include<c ...