NDK是什么
NDK是Native Development Kit,NDK允许用户使用类似C / C++之类的原生代码语言执行部分程序,还可以将我们的c或c++代码打包成.so文件,供安卓程序调用。
NDK的使用
首先看看NDK项目的目录:
在jni目录下面新建三个文件,Android.mk,Application.mk,native-lib.cpp;
其中Android.mk定义了“需要构建模块的名称”,“构建到模块中的 C 或 C++ 源文件列表”等,具体如下
# 构建系统提供的宏函数 my-dir 将返回当前目录(包含 Android.mk 文件本身的目录)的路径,基本上是固定的,不需要去动
LOCAL_PATH := $(call my-dir)
# 会清除很多 LOCAL_XXX 变量,不会清除 LOCAL_PATH,基本上是固定的,不需要去动
include $(CLEAR_VARS)
# 需要构建模块的名称,会自动生成相应的 libNDKSample.so 文件,每个模块名称必须唯一,且不含任何空格
LOCAL_MODULE := nativeLib
# 包含要构建到模块中的 C 或 C++ 源文件列表
LOCAL_SRC_FILES := native-lib.cpp
# 指定这个模块里会用到哪些原生 API,详见:https://developer.android.google.cn/ndk/guides/stable_apis.html
LOCAL_LDLIBS := -llog
# 帮助系统将所有内容连接到一起,固定的,不需要去动
include $(BUILD_SHARED_LIBRARY)
Application.mk定义了要编译的系统包和运行时,具体如下:
# 选择不同的 ABI,多个使用空格作为分隔符,全部是all
# APP_ABI := armeabi armeabi-v7a
APP_ABI := arm64-v8a, armeabi-v7a, x86, x86_64
# 指定要使用的运行时
APP_STL := c++_static
native-lib.cpp是我们需要实现的功能,供我们的Android端调用,我写了一个加法运算的功能,代码如下:
extern "C"
JNIEXPORT jint JNICALL
Java_com_dingxingxiang_myapplication_MainActivity_add(JNIEnv *env, jobject instance, jint a,
jint b) {
return a + b;
}
说明:
- extern "C"是固定的,代表调用C
- JNIEXPORT jint JNICALL中,jint代表返回值的类型,对应java中的int类型,还有 8 种基本数据类型 jbyte、jchar、jshort、jint、jlong、jfloat、jdouble、jboolean,引用数据类型 jintArray、jshortArray、jlongArray 等。
- 方法名部分,格式为:Java_包名_类名_方法名,
- 参数部分,包含了,JNIEnv代表运行时环境,jobject代表 调用 Java 中 native 方法的实例或 Class 对象,如果这个 native 方法是实例方法,则该参数是 jobject,如果是静态方法,则是 jclass。
写完代码之后,我们需要运行的c代码,有两种方式
:
自动编译的方式
自动编译的方式是在我们呢app/buildgradle中配置我们的运行命令,这样每次都可以同步罪行的c代码:
在Android下的defaultConfig中,新建externalNativeBuild ->ndkBuild,指定application.mk的位置等,在Android下,创建externalNativeBuild->ndkBuild,指定Android.mk的位置。这样运行项目就可以运行我们的代码
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.wuxiaolong.ndkbuild"
minSdkVersion 15
targetSdkVersion 27
versionCode 1
versionName "1.0"
externalNativeBuild {
ndkBuild {
//指定 Application.mk 的路径
arguments "NDK_APPLICATION_MK:=src/main/jni/Application.mk"
//指定生成哪些平台的 so 文件
// abiFilters "x86"
//cFlags 和 cppFlags 是用来设置环境变量的, 一般不需要动
cFlags "-DTEST_C_FLAG1", "-DTEST_C_FLAG2"
cppFlags "-DTEST_CPP_FLAG2", "-DTEST_CPP_FLAG2"
}
}
}
externalNativeBuild {
ndkBuild {
//指定 Android.mk 的路径
path "src/main/jni/Android.mk"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir 'src/main/libs'
}
}
运行成功之后,我们的项目中多了一个.externalNativeBuild文件,如图
生成的.so包在app/build/intermediates/ndkBuild/debug/obj/local/arm64-v8a/libnativeLib.so
NDK编译
使用命令 ndk-build,也可以生成对应的 so 文件,然后项目中调用。弊端是C 或 C++ 代码改动了,需要再次编译。
未下载NDK在Android Studio的SDK Tools中下载
下载安装之后,如果没有配置系统环境变量,我们需要配置系统环境变量,在path中填写ndk的路径:如图
然后我们通过cmd进入项目的jni路径下面,执行ndk-build,就可以生成我们需要的.so包了,如下如:
生成的.so包
至此,ndk的入门讲完了,下一篇我们讲ndk的另一种编程方式CMake。