Physical Address:
ChongQing,China.
WebSite:
经常做Android开发的朋友不可避免地会接触到一个词:JNI,其英文全称为Java-Native Interface,JNI的作用即在于通过JNI可以让我们从Java代码调用到C++代码。
一般我们在开发APP时,由于Framework层没有对应的框架实现,可能需要调用C/C++编写的代码,或者是出于安全需要将核心代码使用C/C++编写,进而通过JNI来调用。
使用JNI需要提前配置NDK,因为C++代码依赖于NDK环境。在AndroidStudio中配置NDK时首先需要通过File->Settings->System Settings->Android SDK->SDK Tools内选择NDK进行下载,并通过File->Project Structure->Android NDK location配置其路径。
AndroidStudio中配置使用JNI大致可遵循如下步骤:
1.在app/src/main目录下创建cpp目录,并添加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 的最小版本 一般系统自动生成
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.
# 设置生成.so 的文件名,最终产物为libnative-lib.so
native-lib
# Sets the library as a shared library.
#设置库的类型 一种静态文件 STATIC .a 一种动态文件 SHARED .so
SHARED
# Provides a relative path to your source file(s).
# 需要编译的c/c++ 文件,以CMakeLists.txt所在目录为基准的相对目录
src/main/cpp/main.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.
# 依赖的NDK第三方库--
find_library( # Sets the name of the path variable.
dependencies-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
EGL, #依赖libEGL.so
nativehelper #依赖libnativehelper.so
log )#依赖liblog.so
# 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.
${dependencies-lib } )
关于CMake的更多使用信息,可以参考我的这篇博客。
2.在app/build.gradle中将gradle与cmake进行关联,如下所示:
android {
defaultConfig {
externalNativeBuild{
cmake{
cflags “_D”
cppflags “-frtti”,”-fexceptions”
abiFilters ‘x86’,’x86_64’,’armabi’,’armeabi-v7a’,’arm64-v8a’
}
}
.......
externalNativeBuild {
cmake {
//通过path关键字指定CMakeLists.txt路径
//该路径是是以build.gradle为基准的相对路径
path "CMakeLists.txt"
}
}
}
3.添加关键代码,关键代码的添加分为两部分,一部分是C/C++代码,另外一部分是Java代码。
首先是Java代码,包括加载JNI库,同时声明native 函数。如下示例:
//here we will load jni library
static {
System.loadLibrary("natiave-lib"); //该名称对应cmake中的add_library所添加的库名
}
// Native method declaration
private native boolean nUpdateTexture(HardwareBuffer buffer, int textureId);
然后我们需要编写C/C++代码:
//必须要引用jni.h头文件
#include <jni.h>
//此外有两个重要的函数JNI_OnLoad、JNI_OnUnload是需要去完成的
//当native library被加载时(如调用System.loadLibrary),JAVA VM将会调用JNI_Onload,返回JNI版本
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/) {
}
//当JAVA类加载器发生GC时,该函数将会被JAVA VM进行调用。通常该函数将用于清理工作。
JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* /*reserved*/) {
}
此外我们还需要了解一下JNI中的数据类型,以便将Java中的数据类型与native原生类型做匹配:
除了原生数据类型,JNI中也存在与Java中对应的复合类型,其对应关系如下:
Java Type | Native Type |
java.lang.Class | jclass |
java.lang.String | jstring |
arrays | jarray |
java.lang.Throwable | jthrowable |
在编写完相关代码后,在Androud Studio中你可以在Build窗口中查看编译相关的报错信息;如果你需要更准确地获取C/C++相关的诊断信息,可以在app/.cxx目录下找到更多的有效信息,如CMakeCache.txt等。