概述
想要学习JNI和NDK,首先要知道JNI和NDK分别是什么,都有什么作用,这样才可以更好的学习和理解JNI和NDK,本篇文章主要作为学习笔记,以防以后忘记
JNI介绍
定义:JNI即 Java Native Interface
java本地接口
作用:可以让java和其他类型语言(例如C和C++)进行交互
注意:JNI是属于java的,跟 android 没有关系
NDK 介绍
定义:NDK即 Native Development Kit
是一个android的一个开发工具包
作用:快速开发C/C++动态库,并自动把so和应用打包成APK
注意:NDK是属于android的和java无关
JNI和NDK的联系
可以通过NDK工具 在Android中使用JNI与本地代码(C、C++)进行交互
JNI是实现的目的,NDK是实现JNI的手段
即在Android 的开发环境中(Android Studio)通过NDK实现JNI的功能
使用Android Studio 创建一个NDK项目
由于Android Studio2.2以上已经内部集成了NDK 所以只需要在Android Studio内部配置即可,我目前演示的版本为3.5.3



经过这三个步骤就可以自动生成一个NDK项目

和普通的项目相比多了这个文件夹,其中native-lib.cpp
是C、C++代码,CMakelist.txt
是编译脚本
下面分析下这个项目
MainActivity
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
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 = 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();
}
首先加载native-lib.so
,然后调用so中的stringFromJNI
方法,最后把这个方法返回的值显示在TextView
上
其中native-lib.so
,这个库的名称是在CMklist.txt中指定的, stringFromJNI
是一个java中native
方法,其真正的实现在native-lib.cpp
中
native-lib.cpp
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_text_ndk1_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
上面的public native String stringFromJNI()
的实现就是在这里,那么如何确定java中的Native方法对应C中的哪个方法呢,这里用的是静态注册,即Java包名类名_方法名
的形式,后面再继续讲其他的注册方式
整个调用流程
- Gradle调用外部构建脚本CMklist.txt
- CMake按照脚本中的命令将C++源文件
native-lib.cpp
编译成native-lib.so
动态库,并把它编译到APK中 - 运行时首先加载
native-lib.so
,然后调用so中的stringFromJNI
方法,最后把这个方法返回的值显示在TextView
上
配置Gradle支持NDK
我们先看下上面建立的项目的gradle

其中里面红色框是配置NDK的,也就是说需要配置externalNativeBuild {}
添加到gradle中,并使用 cmake {}
进行配置
我们可以看到Gradle中俩个地方用了externalNativeBuild {}
,一个在defaultConfig
里面一个在defaultConfig
外面
- 在
defaultConfig
外面的externalNativeBuild {}
代码块用cmake
制定了CMakeList.txt
的路径 - 在
defaultConfig
里面的externalNativeBuild {}
代码块用cmake
主要是填写CMake
命令参数
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.4.1)
# 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.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.cpp)
# 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)
# 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.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib})
cmake_minimum_required(VERSION 3.4.1)
设置CMake的最低版本
add_library
第一个参数:设置这个库的名字 第二个参数:设置库的类型,SHARE 动态库.so后缀 ,STATIC 静态库 .a后缀 第三个参数:源文件的相对路径
可以定义多个库,CMake会构建他们,Gradle将自动把共享库打入APK中
find_library
找到一个NDK库,并且把这个库的路径储存在一个变量中,例如例子中就是找到一个NDK中的log库(支持android的日志库),并且把变量储存在log-lib变量中
target_link_libraries
关联库,将指定的库关联起来,比如上边的例子,第一个参数:目标库,第二个参数:将目标库链接到日志库包含在NDK中。
这是一个最基础的CMakeLists.txt,其实他可以非常的强大,比如可以自定义命令,查找文件,设置变量等,推荐参考CMAKE手册