【JNI】JNI环境搭建

article/2025/7/30 3:14:44

1 前言

        JNI (Java Native Interface) 是 JDK 提供的一种机制,用于实现 Java 代码与其他语言(主要是 C 和 C++)编写的本地代码之间的交互。

        JNI 接口详见 JDK 安装目录中的 include/jni.h 文件,Android NDK 对 JDK 的 JNI 进行了扩展,对应的 jni.h 文件路径如下。

SDK\ndk\27.2.12479018\toolchains\llvm\prebuilt\windows-x86_64\sysroot\usr\include\jni.h

         JNI 官方文档见 → https://docs.oracle.com/en/java/javase/17/docs/specs/jni/index.html。

2 在命令行中编译代码

2.1 环境准备

        1)安装 JDK

        下载 JDK(建议下载 x64 Compressed Archive 文件),解压后将根目录写入 JAVA_HOME 环境变量中,如下。

        然后将 %JAVA_HOME%、%JAVA_HOME%\bin 加入 Path 环境变量中,如下。

        在命令行分别输入 java --version、 javac --version,如果有打印版本号,说明 JDK 环境搭建成功。

        2)安装 MinGW

        MinGW(Minimalist GNU for Windows)是一个用于 Windows 平台的轻量级 GNU 开发环境,它允许开发者在 Windows 上使用 GCC(GNU Compiler Collection)工具链编译本地 Windows 应用程序。

        下载 MinGW,解压后将根目录下的 bin 目录写入 Path 环境变量中。

        在命令行输入 gcc --version、g++ --version, 如果有打印版本号,说明 MinGW 环境搭建成功。

2.2 一个简单的案例

        1)编写 java 代码

        用记事本编辑以下代码,保存为 HelloJNI.java。

        HelloJNI.java

/*** 1. 生成字节码和头文件*    javac -encoding UTF-8 -h ./ HelloJNI.java (或 javah -encoding UTF-8 ./ HelloJNI.java, jdk10 之前)* * 2. 生成 dll 或 so*    g++ -fPIC -I"%JAVA_HOME%\\include" -I"%JAVA_HOME%\\include\\win32" -shared -o hello.dll HelloJNI.c* * 3. 运行*    java HelloJNI*/
public class HelloJNI {static {// 运行时加载 native 库, hello.dll (Windows) 或 hello.so (Linux/Unix/Android)System.loadLibrary("hello");}private native void sayHello();public static void main(String[] args) {new HelloJNI().sayHello();}
}

        2)生成字节码和头文件

        在命令行执行以下命令,生成字节码(.class 文件)和头文件(.h 文件)。

// jdk10 及之后
javac -encoding UTF-8 -h ./ HelloJNI.java
// jdk10 之前
javah -encoding UTF-8 ./ HelloJNI.java

        执行完以上命令后,会生成 HelloJNI.class 和 HelloJNI.h 文件。HelloJNI.h 文件内容如下。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloJNI */#ifndef _Included_HelloJNI
#define _Included_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/** Class:     HelloJNI* Method:    sayHello* Signature: ()V*/
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *, jobject);#ifdef __cplusplus
}
#endif
#endif

        3)编写 C 代码 

#include <jni.h>
#include <stdio.h>
#include "HelloJNI.h"JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) {printf("Hello World!\n");return;
}

        4)生成 dll 或 so

        在命令行执行以下命令,生成 ddl(或 so)文件。

// 生成 dll 文件 (Windows)
g++ -fPIC -I"%JAVA_HOME%\\include" -I"%JAVA_HOME%\\include\\win32" -shared -o hello.dll HelloJNI.c// 生成 so 文件 (Linux/Unix/Android)
g++ -fPIC -I"%JAVA_HOME%\\include" -I"%JAVA_HOME%\\include\\win32" -shared -o hello.so HelloJNI.c

        5)运行代码

        在命令行执行以下命令,运行代码。

java HelloJNI

        运行结果如下。

Hello World!

        6)一键编译运行脚本

@echo off
set class_name=HelloJNI
set native_file_name=HelloJNI
set lib_name=hello:: 删除缓存文件
del %class_name%.class
del %class_name%.h
del %lib_name%.dll:: 生成字节码和头文件
javac -encoding UTF-8 -h ./ %class_name%.java:: 生成 dll 或 so
g++ -fPIC -I"%JAVA_HOME%\\include" -I"%JAVA_HOME%\\include\\win32" -shared -o %lib_name%.dll %native_file_name%.c:: 运行
java %class_name%
pause

3 在 Android Studio 中编译代码

        在 Android Studio 中,依此选择 New -> New Project -> Native C++,创建 Native C++ 项目。

        也可以通过 New -> New Module -> Android Native Library,创建 Native Library。

        对于普通的 Android 项目,可以通过以下配置,使其支持 JNI。

        1)build.gradle

defaultConfig {ndk {abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'}
}externalNativeBuild {cmake {path file('src/main/cpp/CMakeLists.txt')version '3.22.1'}
}

        abiFilters 的作用是指定应用支持的 ABI(Application Binary Interface) 架构类型,即应用只会为指定的 CPU 架构生成原生库(.so 文件),而忽略其他架构。如果未配置 abiFilters,Gradle 默认会构建所有支持的 ABI(取决于 NDK 版本和项目依赖)。

armeabi-v7a: 32 位 ARM 架构 (较旧的 Android 设备)
arm64-v8a: 64 位 ARM 架构 (现代主流设备,性能更好)
x86: 32 位 Intel 架构 (模拟器或少数平板设备)
x86_64: 64 位 Intel 架构 (模拟器或高端设备)

        2)创建 cpp 目录

        3)C/C++ 代码

        如果用 C 语言实现,代码如下。

        demo.c

#include <jni.h>
#include <string.h>JNIEXPORT jstring JNICALL
Java_com_zhyan8_test_MainActivity_stringFromJNI(JNIEnv* env,jobject /* this */) {return (*env)->NewStringUTF(env, "Hello from C++");
}

        如果用 C++ 语言实现,代码如下。 

        demo.cpp

#include <jni.h>
#include <string>extern "C" JNIEXPORT jstring JNICALL
Java_com_zhyan8_test_MainActivity_stringFromJNI(JNIEnv* env,jobject /* this */) {return env->NewStringUTF("Hello from C++");
}

        可以看到,C 与 C++ 的主要区别如下。

  • 头文件:C 中 string 的引用是 #include <string.h>,C++ 中 string 的引用是 #include <string>。
  • extern "C":C++ 中多了 extern "C" 修饰,表示使用 C 风格的函数链接,禁止 C++ 的名称修饰。如果不禁用名称修饰,C++ 编译器会对函数名进行修饰,以支持函数重载等特性,会导致 Java 无法查找到本地函数。因此,使用 extern "C" 的函数不能重载(因为名称不再修饰)。
  • env:C 中的 env 是二级指针,所以访问函数通过 (*env)-> 访问;C++ 中的 env 是一级指针,所以访问函数通过 env-> 访问。

        4)CMakeLists.txt

# 项目要求的最小CMake版本
cmake_minimum_required(VERSION 3.22.1)# 声明项目名, 可以通过${PROJECT_NAME}访问, 在顶层CMakeLists.txt中, 也可以通过${CMAKE_PROJECT_NAME}访问
project("hello")# 添加预构建库, 在顶层CMakeLists.txt中, ${CMAKE_PROJECT_NAME}用于定义目标库名,
# 在Java/Kotlin中, 需要通过System.loadLibrary()加载该库, 并且与这里使用相同的名字
# SHARED用于将该库声明为一个shared library
add_library(${CMAKE_PROJECT_NAME} SHARED# C/C++ 源文件列表, 相对于CMakeLists.txt的路径com/zhyan8/demo/demo.cpp)# 指定需要链接到目标库的三方库或Android系统库
target_link_libraries(${CMAKE_PROJECT_NAME}# 链接到目标库的库文件androidlog)

        5)MainActivity.java

package com.zhyan8.test;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.util.Log;public class MainActivity extends AppCompatActivity {static {System.loadLibrary("hello");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.i("MainActivity", stringFromJNI());}public native String stringFromJNI();
}

http://www.hkcw.cn/article/uIhjCwRghg.shtml

相关文章

利用IEEE 802.15.4z-IR UWB系统进行手势检测

本文介绍了一种符合 IEEE 802.15.4z 标准的脉冲无线电超宽带 (IR-UWB) 手势检测雷达系统。该系统可检测车辆乘客座椅上的人员是否执行了 12 个预定义手势中的某一个。这些预定义手势包括各种手部动作&#xff0c;例如左右滑动或顺时针旋转手掌。为了进行手势检测&#xff0c;我…

STM标准库-GPIO输入

文章目录 一、GPIO输入按键简介传感器模块简介硬件电路 二、C语言C语言数据类型C语言宏定义C语言typedefC语言结构体C语言枚举 三、练习3.1按键控制LED3.1.1接线图3.1.2代码效果&#xff1a; 3.2光敏电阻控制蜂鸣器3.2.1接线图3.2.2代码效果&#xff1a; 一、GPIO输入 STM32 的…

HackMyVM-Jabita

信息搜集 主机发现 ┌──(kali㉿kali)-[~] └─$ nmap -sn 192.168.43.0/24 Starting Nmap 7.95 ( https://nmap.org ) at 2025-06-01 05:20 EDT Nmap scan report for 192.168.43.1 Host is up (0.020s latency). MAC Address: C6:45:66:05:91:88 (Unknown) Nmap scan repo…

桑托斯0-1博塔弗戈 内马尔染红 阿图尔制胜球

北京时间6月2日,巴西足球甲级联赛第11轮,桑托斯主场对阵博塔弗戈。比赛中,桑托斯的内马尔因累计两张黄牌被罚出场。博塔弗戈凭借雅伊尔-库尼亚的助攻,由阿图尔打入制胜一球,最终以1-0战胜桑托斯。比赛开始前,双方队长进行了挑边仪式。第5分钟,内马尔在禁区内投诉被对手拉…

英国军事战略转向全面“备战”

△英国首相府(资料图)当地时间6月1日,总台记者从英国首相府获得信息,英国政府将在2日发布新一轮《战略国防评估报告》的同时,宣布大幅扩建其核动力攻击型潜艇舰队,并加速推进军工产业现代化。此举被外界普遍解读为英国在地缘安全压力加剧背景下,全面进入“备战状态”。新…

Java虚拟机内存区域划分

Java虚拟机内存区域划分 Java虚拟机&#xff08;JVM&#xff09;的内存区域划分主要分为五个部分&#xff1a; 程序计数器&#xff1a;程序计数寄存器&#xff0c;给CPU使用本地方法栈&#xff1a;为JVM使用到的Native方法服务方法区&#xff1a;存储的是编译后的.class文件堆…

cursor升级至0.505,运行统计视频中的人数

帮助--检查更新&#xff0c;升级。 升级后&#xff0c;新建文本&#xff0c;另存选python格式保存后&#xff0c;右下角提示选择编译器&#xff0c;选择python后&#xff0c;自动安装ms python 3.11.9 一.查看pthon安装在哪&#xff0c; winr,输入cmd后, ctrlshiftenter三个…

《Pytorch深度学习实践》ch2-梯度下降算法

------B站《刘二大人》 1.Gradient Decent 局部最优&#xff0c;全局最优&#xff0c;非凸函数&#xff1a; 梯度下降算法公式&#xff1a; 2.Implementation import matplotlib.pyplot as plt# 数据集 x_data [1.0, 2.0, 3.0] y_data [2.0, 4.0, 6.0]# 权重 w 1.0# 模型…

LabVIEW多按键自动化检测系统

LabVIEW开发一套高精度按键力与行程自动化检测系统&#xff0c;针对传统检测设备自动化程度低、定位误差大等痛点&#xff0c;实现多按键产品的全流程自动化测试。系统集成 6 轴工业机器人、高精度传感器及实时数据处理模块&#xff0c;满足汽车电子、消费电子等领域对按键手感…

Chorme如何对于youtube视频进行画中画背景播放?

画中画可以让你小窗播放&#xff0c;然后浏览器放后台还可以做点别的事情。 B站直接可以选择小窗播放&#xff0c;游览器最小化就可以&#xff0c;但是youtube的小窗播放游览器一切换就不显示了。 其实是因为youtube的小窗播放不是真的小窗播放。要想真的实现需要在youtube视…

JDBC连不上mysql:Unable to load authentication plugin ‘caching_sha2_password‘.

最近为一个spring-boot项目下了mysql-9.3.0&#xff0c;结果因为mysql版本太新一直报错连不上。 错误如下&#xff1a; 2025-06-01 16:19:43.516 ERROR 22088 --- [http-nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispat…

C/C++ 面试复习笔记(3)

一.valgrind工具 参考&#xff1a; 内存检查工具valgrind介绍、安装与使用-CSDN博客https://blog.csdn.net/mijichui2153/article/details/85240349 二.C语言中如何实现一个线程池&#xff1f; 答案&#xff1a; 线程池是通过预先创建固定数量的线程来处理多个任务&#xf…

Spring框架核心知识深度解析

Spring框架核心知识深度解析 最近正在复习Java八股&#xff0c;所以会将一些热门的八股问题&#xff0c;结合ai与自身理解写成博客便于记忆 今天将对spring常见问题做出解析 一、IOC与AOP核心原理 1. IOC&#xff08;控制反转&#xff09;详解 核心思想&#xff1a;将对象…

【第四十七周】HippoRAG 2 复现与分析(一):环境部署与代码分析

目录 摘要Abstract安装依赖试运行HippoRAG 初始化文档索引QA运行脚本 总结 摘要 本周对HippoRAG 2系统进行核心功能测试&#xff0c;通过构建小型结构化文档库&#xff08;如人物职业、童话事件、地理关系&#xff09;&#xff0c;验证其索引构建、动态增删、多轮检索问答及评…

【js逆向_AES】全国二手房指数数据爬取

目标&#xff1a;请求参数signcode&#xff0c;请求结果data。 网址&#xff1a;aHR0cDovL3d3dy5jY2hpbmRleC5jb20vSG9tZS9pbmRleA 查看载荷 查看响应数据 点击xhr&#xff0c;发现所有请求参数都是一个signCode&#xff0c;还是加密后的结果&#xff0c;对应结果中数据data也…

郑钦文社媒:人都应该有梦 刷新赛会最佳战绩

北京时间6月1日晚,在法网女单1/8决赛中,郑钦文战胜俄罗斯选手萨姆索诺娃,职业生涯首次跻身法网女单八强,刷新个人赛会最佳战绩。这也是中国选手时隔14年再次闯进法网八强。赛后,郑钦文在社交媒体上写道:“人都应该有梦,有梦就别怕痛,是一颗宝石就该闪烁。”她还祝所有的…

【第16届蓝桥杯 | 软件赛】CB组省赛第二场

个人主页&#xff1a;Guiat 归属专栏&#xff1a;算法竞赛 文章目录 A. 密密摆放&#xff08;5分填空题&#xff09;B. 脉冲强度之和&#xff08;5分填空题&#xff09;C. 25 之和D. 旗帜E. 数列差分F. 树上寻宝G. 翻转硬币H. 破解信息 正文 总共8道题。 A. 密密摆放&#xff0…

在线音乐服务器测试报告

1.项目背景 此项目主要用于模拟市面上主流的音乐软件的主要功能&#xff0c;提高自己的开发和测试能力。此项目采用的技术栈是SpringBoot MyBatis SpringMVC Mysql实现的&#xff0c;为了实现简单&#xff0c;方便测试&#xff0c;此项目没有注册功能&#xff0c;数据提前存…

球展世界,筑梦中原,2025郑州台球展会,年中招商即将开启

-壹肆柒2025中国&#xff08;郑州&#xff09;国际台球产业博览会暨全国台球产业链发展大会&#xff0c;将于2025年08月15-17日&#xff0c;在郑州中原国际会展中心盛大举办。本届博览会主题&#xff1a;同聚中原共赢未来&#xff0c;四个展馆&#xff0c;42000㎡的展览面积&am…

58、辣椒种植学习

辣椒&#xff08;学名&#xff1a;Capsicum annuum&#xff09;属于茄科辣椒属&#xff0c;是一种重要的蔬菜兼调味作物&#xff0c;具有较高的经济价值和营养价值。其果实富含维生素C、辣椒素等成分&#xff0c;既可鲜食&#xff0c;也可加工成干辣椒、辣椒粉、辣椒酱等产品&a…