Android NDK(一)- 认识 NDK
JNI 简介
在讲 NDK 之前,先要搞清楚什么是 JNI。
定义:Java Native Interface,即 Java 本地接口。
作用: 使得 Java 与本地其他类型语言(如 C、C++)交互。也就是在 Java 中调用 C/C++ 代码,或者在 C/C++ 中调用 Java 代码。
注意,JNI 是 Java 的,和 Android 无关。
NDK 简介
定义:Native Development Kit,是 Android 的一个工具开发包。
那到底 JNI 和 NDK 有什么区别呢?
NDK 可以看做是 Android 中实现 JNI 的一种手段,通过 NDK,还可以打包 C/C++ 动态库,并自动打包进 APK/AAR 中。
最简单的 NDK 项目
Android Studio 新建项目的时候可以选择各种各样的模板,选择 Native C++ 模板就可以创建一个简单的 NDK 项目。
在 app/src/main/cpp 下可以看到有 CMakeList.txt 和 native-lib.cpp。
native-lib.cpp 里面是原生代码。
CMakeList.txt 是 CMake 构建脚本,用于把原生代码构建入库。
CMakeList.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.10.2)
# Declares and names the project.
project("myndk")
# 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.
myndk
# 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.
myndk
# Links the target library to the log library
# included in the NDK.
${log-lib})
CMakeList 的具体解释可以见注释部分。
native-lib.cpp
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_teletian_sample_myndk_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
一个简单的 C++ 方法,返回一个 Hello from C++ 的字符串。
- 参数 JNIEnv* env:JNI 所有的接口函数都是通过这个指针调用的。
- 参数 object:如果 Java 中此方法是实例方法,那么这边就是 Java 实例,如果是类方法,那么就是 Java 类。
这边还导入了一个头文件 jni.h,jni.h 中定义了 JNI 的数据类型、数据结构、接口函数、回调函数以及常量等等。
MainActivity.java
public class MainActivity extends AppCompatActivity {
// Used to load the 'myndk' library on application startup.
static {
System.loadLibrary("myndk");
}
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
// Example of a call to a native method
TextView tv = binding.sampleText;
tv.setText(stringFromJNI());
}
/**
* A native method that is implemented by the 'myndk' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
}
Java 中定义和 Java_com_teletian_sample_myndk_MainActivity_stringFromJNI 相对应的方法 stringFromJNI。
在使用之前,需要提前加载 CMakeList 中定义的 myndk 动态库。
app 下的 build.gradle 文件设置如下:
android {
defaultConfig {
externalNativeBuild {
cmake {
// 支持 c++11
cppFlags '-std=c++11'
// 需要运行的 CPU 类型
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
}
}
// 指定 CMake 文件路径和版本
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
version '3.18.1'
}
}
}