Android进阶-NDK技术
一.介绍
1.什么是ndk技术?
在学习ndk技术前,我们需要先了解一下JNI(Java Native Interface)技术,JNI技术是一种实现Java代码和C/C++代码之间交互的技术,它提供了一组编程接口,使得Java程序可以调用C/C++代码并与其进行通信。通过JNI技术,开发者可以将C/C++代码嵌入Java项目中,并在Java代码中调用这些C/C++函数。那么,NDK技术和它有什么关系呢?NDK是一种用于开发Android应用程序的工具集,它允许开发者使用C/C++编写部分或全部的Android应用程序代码,以便提高性能和访问底层系统功能。这样看起来NDK技术和JNI技术是一回事,就是为了实现Java调用C/C++或C/C++调用Java。确实如此,用一句话概括它们之间的关系就是:开发者使用NDK技术在Android应用程序中编写C/C++代码,并将其编译成共享库(如.so文件),然后使用JNI技术在Java代码中加载并与这些C/C++代码进行交互。
2.为什么要学习ndk?
第一点的话就是提高性能了,这个显而易见,C/C++的性能肯定比Java高,如果有些功能用Java实现性能不行,就可以把这部分代码用C/C++实现。第二点的话就是C/C++语言可以直接访问底层系统功能和硬件资源,如摄像头和传感器等,这是Java做不到的。最后一点是保密性,Java代码是编译成字节码,而C/C++代码是直接编译成机器码,反编译的难度比Java大的多。所以,如果哪部分功能需要保密,也可以用C/C++来实现。
3.编写C/C++代码并编译出.so文件
我们要在Android项目中调用C/C++代码,首先要将写好的C/C++代码编译成.so共享库,下面我会以Android Studio 2021来详细讲解编译出.so文件的过程。
第一步:打开Android Studio,新建一个Native C++项目,如下图所示:



项目新建完成后是下面这个样子:

我们可以看到main目录下面有一个cpp目录,这里就是我们编写C++代码的地方,我们先来看一下自动生成的CmakeLists.txt文件,代码如下:
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html # Sets the minimum version of CMake required to build the native library. cmake_minimum_required(VERSION 3.18.1) //cmake的最低版本是3.18.1 # Declares and names the project. project("ndkstudy") # Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK. add_library( # Sets the name of the library.
ndkstudy //生成的库的名称 # Sets the library as a shared library.
SHARED //设置生成的库为共享库.so # Provides a relative path to your source file(s).
native-lib.cpp //c++源文件的相对路径
) # Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build. find_library( # Sets the name of the path variable.
log-lib # Specifies the name of the NDK library that
# you want CMake to locate.
log) //使用find_library来查找log库,并把找到的log库存储在变量log-lib中 # Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries. target_link_libraries( # Specifies the target library.
ndkstudy # Links the target library to the log library
# included in the NDK.
${log-lib}) //将ndkstudy库和log库进行链接
然后,我们再来看一下自动生成的native-lib.cpp文件,代码如下:
#include <jni.h>
#include <string> extern "C" JNIEXPORT jstring JNICALL
Java_com_example_ndkstudy_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}//函数的功能就是返回一个"Hello from C++"字符串
我们发现这个函数名特别长,其实就是对应java目录下com.example.ndkstudy包下MainActivity类下的stringFromJNI()这个函数。了解了这些之后,我们只需要Make Project即可,如下图所示:

然后就可以看到所生成的.so文件了,如果没有的话,可以刷新一下项目

接下来,我们建一个新的项目,然后把上面所生成的不同CPU架构的.so文件复制到新项目的main/jniLibs目录,jniLibs目录需要自己新建。

然后在app/build.gradle文件下添加以下的代码:
android {
namespace 'com.example.ndkstudy'
compileSdk 32
defaultConfig {
applicationId "com.example.ndkstudy"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
ndk {
// 设置支持的SO库架构(开发者可以根据需要,选择一个或多个平台的so)
abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86","x86_64"
}//新增代码
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
接下来,就可以调用so库中的C++函数了,这里也是特别容易出错的地方,我先贴出代码,然后再详细讲解。
public class MainActivity extends AppCompatActivity {
private TextView tv_display;
{
System.loadLibrary("ndkstudy");//第一步,加载动态库,放到静态代码块里就行
}
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_display=findViewById(R.id.tv_display);
tv_display.setText(stringFromJNI());//第三步,调用本地函数,实际上调用的函数是Java_com_example_ndkstudy_MainActivity_stringFromJNI();
} public native String stringFromJNI();//第二步,本地方法声明,也就是说这个方法由c++实现,这里作个声明 }
一个特别需要注意的点是我们在加载动态库和作本地方法声明的时候,需要在com.example.ndkstudy包下,MainActivity类下进行操作,也就是要对应那个特别长的函数名。如果以上的步骤都没有错的话,就可以在手机屏幕上看到输出的"Hello from C++"字符串了。
Android进阶-NDK技术的更多相关文章
- Android的NDK技术
Android的NDK技术
- 《Android进阶》之第七篇 NDK的使用
<Android进阶>之第一篇 在Java中调用C库函数 这一篇列举的方法是在NDK没有出来时候用的方式 在Android发布NDK之后,可以这样使用 一.首先下载android-ndk ...
- Android开发面试经——4.常见Android进阶笔试题(更新中...)
Android开发(29) 版权声明:本文为寻梦-finddreams原创文章,请关注:http://blog.csdn.net/finddreams 关注finddreams博客:http:/ ...
- 我的Android进阶之旅------>经典的大牛博客推荐(排名不分先后)!!
本文来自:http://blog.csdn.net/ouyang_peng/article/details/11358405 今天看到一篇文章,收藏了很多大牛的博客,在这里分享一下 谦虚的天下 柳志超 ...
- Android进阶推荐书籍
中级进阶推荐看一下以下这几本书 1.<Android从入门到精通(附光盘)> 明日科技 编 2.<第一行代码2 Android(第二版)> 郭霖 著 3.<Android ...
- 这是一份非常适合收藏的Android进阶/面试重难点整理
写在前面 记得我大二时“不务正业”地自学Android并跟了老师做项目,到大三开始在目前的公司实习,至今毕业已有几年多,学习Android已经6.7年多了!但总感觉知识点很零散,并且不够深入,遇到瓶颈 ...
- 可怕!字节跳动大牛爆出的“Android进阶指南”,强到无法形容,GitHub已标星“8.5k”!
前言 从去年8月份开始,我开始重新找工作,在这期间刷了不少面试题和大牛博客,无意中薅到一份字节跳动大牛整理的一份"Android进阶指南",包含Android面试常见问题.主流技术 ...
- Android之NDK开发(转)
Android之NDK开发 一.NDK产生的背景 Android平台从诞生起,就已经支持C.C++开发.众所周知,Android的SDK基于Java实现,这意味着基于Android SDK进行开发的第 ...
- Android 进阶 Android 中的 IOC 框架 【ViewInject】 (下)
上一篇博客我们已经带大家简单的吹了一下IoC,实现了Activity中View的布局以及控件的注入,如果你不了解,请参考:Android 进阶 教你打造 Android 中的 IOC 框架 [View ...
- Android之NDK开发
转自:http://www.cnblogs.com/devinzhang/archive/2012/02/29/2373729.html 一.NDK产生的背景 Android平台从诞生起,就已经支持C ...
随机推荐
- CesiumJS 源码杂谈 - 从光到 Uniform
目录 1. 有什么光 2. 光如何转换成 Uniform 以及何时被调用 2.1. 统一值状态对象(UniformState) 2.2. 上下文(Context)执行 DrawCommand 2.3. ...
- 重新实现hashCode()方法
在Java中,为了让对象在集合中能够更高效地进行查找和比较,我们通常需要重写对象的equals()和hashCode()方法.其中,equals()方法用于比较两个对象是否相等,而hashCode() ...
- 基于django+ansible+webssh运维自动化管理系统
基于django+ansible+webssh运维自动化管理系统 前言 最初开发这个基于Django ansible运维自动化管理系统的想法其实从大学时候就已经有了,但是苦于技术原因和没有线上环境 ...
- oracle逻辑备份exp导出指定表名时需要加括号吗?
Oracle 的exp.imp.expdp.impdp命令用于数据库逻辑备份与恢复; exp命令用于把数据从远程数据库server导出至本地,生成dmp文件. 笔者在实操中遇到: $exp user/ ...
- 记一次某CMS代码审计(转载)
作者:ddwGeGe 本文转自先知社区:https://xz.aliyun.com/t/11774 前言 无意中浏览到某小众OA官网且可以下载到源码,随机审计一波,最后成功Getshell,大佬勿喷 ...
- MySQL-分组函数ROLLUP的基本用法
一.ROLLUP简介 ROLLUP是GROUP BY子句的扩展. ROLLUP选项允许包含表示小计的额外行,通常称为超级聚合行,以及总计行. 通过使用ROLLUP选项,可以使用单个查询生成多个分组集. ...
- Nuxt3.0中使用EChart可视化图表📊
在Nuxt3.0项目中用到了可视化图表,于是我用了EChart可视化图表库.但是在官网我没有找到针对在Nuxt3.0中使用EChart的方法,于是在这里记录我的引入EChart并简单使用的步骤.需要声 ...
- vue全家桶进阶之路4:NPM包
NPM(Node Package Manager)是 Node.js 的包管理工具,用来安装各种 Node.js 的扩展. NPM是 JavaScript 的包管理工具,也是世界上最大的软件注册表.有 ...
- 在 Transformers 中使用对比搜索生成可媲美人类水平的文本 🤗
1. 引言 自然语言生成 (即文本生成) 是自然语言处理 (NLP) 的核心任务之一.本文将介绍神经网络文本生成领域当前最先进的解码方法 对比搜索 (Contrastive Search).提出该方法 ...
- boot-admin 项目数据库缺省字段设计之最佳实践
数据库(Database)中的缺省字段(也称为默认字段),就是在一般情况下,每个数据表(Table)必须包含的字段(Field),这类字段用于满足特定的数据需求,字段值的填充或更改一般遵照一定的逻辑要 ...