Java Native Interface (JNI) 是 Java 平台的一部分,它允许 Java 代码与用其他编程语言(如 C、C++)编写的本地应用程序或库进行互操作。JNI 提供了一种机制,通过这机制,Java 程序可以调用本地代码,而本地代码也可以调用 Java 代码。

基本概念

  1. JNI 的用途
    • 调用现有的本地库:重用已经用 C 或 C++ 编写的高效代码库。
    • 提高性能:对一些性能要求极高的操作,可以使用 C 或 C++ 实现。
    • 访问特定平台特性:使用 Java 不能直接访问的平台特定功能和硬件。
  2. JNI 环境
    • Java 虚拟机 (JVM):JNI 运行在 JVM 上,通过 JVM 提供的接口与本地代码进行交互。
    • 本地方法库:包含用本地语言编写的代码,通常是动态链接库(如 Windows 上的 DLL 或 Unix 上的 SO 文件)。
  3. 基本结构
    • Java 声明本地方法:在 Java 类中声明一个本地方法,通过 native 关键字。
    • 加载本地库:使用 System.loadLibrary() 方法加载包含本地方法实现的库。
    • 本地方法实现:在 C/C++ 中实现与 Java 声明匹配的方法,并使用 JNI 提供的接口进行数据交换。

使用Android使用 JNI 详细步骤

1.使用Android Studio新建项目

较新的Android Studio 与旧版的Android Studio 新建方式略有不同,新版创建需要选择**Native C++**项目

在这里插入图片描述

选择完毕之后点击Next,给项目起名字,选择开发语言,可选Java和Kotlin

在这里插入图片描述

最后点击next 选择C++ Standard

在这里插入图片描述

选择C++11 点击Finish 等待加载Gradle配置完项目,第一个JNI程序就搭建好了

2.项目结构分析

与普通的Android项目多了CPP目录,该目录存放C++代码和CMakeLists.txt 指定生成的库和如何加载外部库

在这里插入图片描述

在这个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.22.1)

# Declares and names the project.

project("firstjni")

# 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.
        firstjni

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        native-lib.cpp)


#添加外部库
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)
#编译链接库
target_link_libraries( # Specifies the target library.
        firstjni

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

这个 CMakeLists.txt 文件的主要功能是:

  1. 设置 CMake 的最低版本:确保使用的 CMake 版本至少是 3.22.1。
  2. 声明项目:将项目命名为 firstjni
  3. 添加库:定义一个名为 firstjni 的共享库,并指定其源文件为 native-lib.cpp
  4. 查找外部库:使用 find_library 查找并设置 Android NDK 提供的 log 库。
  5. 链接库:将 log 库链接到 firstjni 库,使其可以使用日志功能。

3.JNI函数接口和C++实现解析

在新建好的MainActivity中会发现,默认生成了一些代码

首先是默认加载C++库,也就是对应cpp的文件夹

// 加载C++库
    static {
        System.loadLibrary("firstjni");
    }

默认生成了 一个JNI函数接口 使用native修饰

在这里插入图片描述

Android Studio 左边自动提示生成了C++图标,单击图标就可以跳转到对应的C++实现

extern "C" JNIEXPORT jstring JNICALL
Java_com_marxist_firstjni_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

这个函数是一个典型的 JNI (Java Native Interface) 函数,它定义了一个从 C++ 返回字符串给 Java 的本地方法

函数声明:

extern "C" JNIEXPORT jstring JNICALL
Java_com_marxist_firstjni_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */)

extern "C":

  • 这个修饰符告诉编译器使用 C 语言的函数命名规则,以防止 C++ 的名称修饰(name mangling)。这样,Java 虚拟机 (JVM) 可以正确地找到这个函数。

JNIEXPORT:

  • 这是一个宏,用于定义 JNI 函数的导出规范,确保函数可以被 JVM 调用。

jstring:

  • 这是函数的返回类型,表示一个 Java 字符串对象。

JNICALL:

  • 这是一个宏,用于定义 JNI 函数的调用规范,确保函数可以按照 JNI 的约定被调用。

Java_com_marxist_firstjni_MainActivity_stringFromJNI:

  • 这是函数的名称。按照 JNI 的命名规则,这个名称由以下部分组成:
    • Java_:前缀,表示这是一个 JNI 函数。
    • com_marxist_firstjni_MainActivity:类的全限定名,其中包名中的点号(.)被替换为下划线(_)。
    • stringFromJNI:方法名,对应 Java 类中的本地方法名。

JNIEnv* env:

  • 这是一个指向 JNI 环境的指针,提供了调用 JNI 函数的接口。
  • JNI (Java Native Interface) 函数的一个重要参数,它是一个指向 JNIEnv 结构体的指针。这个结构体包含了大量的函数指针,这些函数提供了与 JVM 交互的各种功能。通过这个参数,C/C++ 代码可以调用 Java 方法、操作 Java 对象、处理异常等。

jobject:

  • 这是调用该本地方法的 Java 对象实例的引用,表示 this 对象。

4.效果展示

在调用本地方法的Java对象,可以直接调用JNI接口,如下所示:

  TextView tv = binding.sampleText;
  tv.setText(stringFromJNI());

编译运行之后,第一个JNI程序显示Hello信息

在这里插入图片描述

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部