android中的JNI的DEMO

一:源代码

native-lib.cpp

#include "native-lib.h"JNIEXPORT jint JNICALL
Java_com_example_jnidemo_MainActivity_add(JNIEnv* env, jobject, jint a, jint b) {return a + b;
}JNIEXPORT jint JNICALL
Java_com_example_jnidemo_MainActivity_subtract(JNIEnv* env, jobject, jint a, jint b) {return a - b + 3;
}JNIEXPORT jint JNICALL
Java_com_example_jnidemo_MainActivity_multiply(JNIEnv* env, jobject, jint a, jint b) {return a * b + 3;
}JNIEXPORT jdouble JNICALL
Java_com_example_jnidemo_MainActivity_divide(JNIEnv* env, jobject, jint a, jint b) {if (b == 0) return 0;return static_cast<jdouble>(a) / static_cast<jdouble>(b);
}

native-lib.h

#ifndef NATIVE_LIB_H
#define NATIVE_LIB_H#include <jni.h>#ifdef __cplusplus
extern "C" {
#endifJNIEXPORT jint JNICALL Java_com_example_jnidemo_MainActivity_add(JNIEnv* env, jobject, jint a, jint b);
JNIEXPORT jint JNICALL Java_com_example_jnidemo_MainActivity_subtract(JNIEnv* env, jobject, jint a, jint b);
JNIEXPORT jint JNICALL Java_com_example_jnidemo_MainActivity_multiply(JNIEnv* env, jobject, jint a, jint b);
JNIEXPORT jdouble JNICALL Java_com_example_jnidemo_MainActivity_divide(JNIEnv* env, jobject, jint a, jint b);#ifdef __cplusplus
}
#endif#endif // NATIVE_LIB_H

MainActivity

package com.example.jnidemo;import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;public class MainActivity extends AppCompatActivity {// Used to load the 'native-lib' library on application startup.static {System.loadLibrary("native-lib");}private native int add(int a, int b);private native int subtract(int a, int b);private native int multiply(int a, int b);private native double divide(int a, int b);@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);int a = 10;int b = 5;TextView tv = findViewById(R.id.sample_text);StringBuilder sb = new StringBuilder();sb.append("Add: ").append(add(a, b)).append("\n");sb.append("Subtract: ").append(subtract(a, b)).append("\n");sb.append("Multiply: ").append(multiply(a, b)).append("\n");sb.append("Divide: ").append(divide(a, b)).append("\n");tv.setText(sb.toString());}
}

 CMakeLists.txt

尤其注意下面的第一行camke的版本要与settings中的SDK TOOL中的保持一致:cmake_minimum_required(VERSION 3.10.2)

# 设置CMake的最低版本要求
cmake_minimum_required(VERSION 3.10.2)# 设置项目名称
project("native-lib")# 添加共享库
# add_library函数用来定义库的名称、类型和源文件
add_library(# 设置库的名称native-lib# 设置库的类型为共享库SHARED# 提供库的源文件路径E:/a_own_codes/android_java/JNIdemo/app/src/main/cpp/native-lib.cpp)# find_library函数用于查找系统中已存在的库,并设置其路径
find_library(# 设置路径变量的名称log-lib# 指定要查找的NDK库的名称log
)# target_link_libraries函数用于将目标库与其依赖库链接在一起
target_link_libraries(# 指定目标库native-lib# 将目标库链接到NDK中包含的log库${log-lib}
)

 代码结构

 二:关于NDK工具

2.1 AS中配置

 2.2 环境变量配置
 

 2.3验证安装

 

三:为什么使用JNI

JNI
JNI 全程:JNI(Java Native Interface),通俗翻译:Java本地方法
官方说法:提供一种Java字节码调用C/C++的解决方案,JNI描述的是一种技术。所以这里的Nativie的本地的意思就是C/C++,所以JNI通俗理解就是Java调用C/C++的方案技术。

NDK
NDK(Native Development Kit),通俗翻译:本地发展(扩展)工具
Android NDK 是一组允许您将 C 或 C++(“原生代码”)嵌入到 Android 应用中的工具,NDK描述的是工具集。

同样,把这里的Native理解成C/C++,那么NDK的简单理解就是能把C/C++编译成Java识别的工具模块。Android Studio中已经集成了NDK,所以才可以在Java代码中很方便就可以调用到C/C++的代码。网上有些示例是用NDK命令来编译cpp生成so,并调用测试,这里不做介绍。

Jni的开发背景:

需要调用Java语言不支持的依赖于操作系统平台特性的一些功能,比如

● 需要调用当前UNIX系统的某个功能,而Java不支持这个功能的时候,就要用到JNI
● 在程序对时间敏感或对性能要求特别高时,有必要用到更底层的语言来提高运行效率
● 音视频开发涉及到的音视频编解码需要更快的处理速度,这就需要用到JNI
● 为了整合一些以前的非Java语言开发的系统
● 需要用到早期实现的C/C++语言开发的一些功能或者系统,将这些功能整合到当前的系统或者新的版本中

其实就是为了调用C/C++代码

JNI是完善Java的一个重要功能,它让Java更加全面、封装了各个平台的差异性

JNI在 Android 开发里的主要应用场景:

● 音视频开发
● 热修复
● 插件化
● 逆向开发
● 等等…

这些都是比较复杂的模块,很多实现Java代码无法实现或者使用Java代码实现会很低效的情况。所以这些模块开发的就要提前掌握Jni相关技术才能实现复杂功能。其实这些概念,看一百遍也是很容易忘记的,只要记住一点就行了:

JNI就是Java为了调用C语言的技术,其中过程用到了NDK相关工具。

java-jni-c/c++ 关系图也是比较简单明了的:

Jni基础很简单,比如:Java 代码中加载so库,定义native方法,jni代码中执行简单的实现,相信很多人都是会的;

Jni的进阶知识:jni添加日志,复制对象的调用,C++调用Java方法,Jni方法的动态注册和静态注册,Jni报错分析等等,这些都是有一定的难度的,经过一定的学习了解就可以掌握了。

这些Jni相关知识的学习,不需要系统源码环境,只需要电脑安装Android Studio,安装模拟器或者有安卓真机调试验证就可以了。JNI在系统源码环境中也是有很多相关的代码和使用场景,如果是入门学习,优先使用Android Stduio 创建的项目会好入手很多。                        
原文链接:https://blog.csdn.net/wenzhi20102321/article/details/136291126

四:文件名称路径以及方法名的关系

在JNI(Java Native Interface)中,Java中的本地方法和C/C++中的实现方法之间通过特定的命名约定进行映射。这个命名约定由JNI定义,确保Java虚拟机能够正确找到并调用对应的本地实现方法。具体来说,这种映射关系由以下规则构成:

JNI 方法命名约定

  1. 前缀:所有的本地方法在C/C++实现中都以 Java_ 开头。
  2. 包名:将包名中的点号(.)替换为下划线(_)。
  3. 类名:直接使用类名。
  4. 方法名:直接使用方法名。
  5. 参数类型(可选):如果方法名相同且参数不同,参数类型也需要编码在方法名中。

例如,Java类中的方法签名如下:

package com.example.jnidemo;public class Calculator {static {System.loadLibrary("calculator");}public native int add(int a, int b);
}

根据命名约定,这个方法在C文件中的实现应该是:

#include <jni.h>
#include "com_example_jnidemo_Calculator.h"JNIEXPORT jint JNICALL Java_com_example_jnidemo_Calculator_add(JNIEnv *env, jobject obj, jint a, jint b) {return a + b;
}

命名规则详细解释

  • Java_: 前缀,所有JNI方法必须以这个前缀开头。
  • com_example_jnidemo: 包名,将包名中的 . 替换为 _
  • Calculator: 类名。
  • add: 方法名。

使用过程中如何映射

  1. 加载共享库

static {System.loadLibrary("calculator");
}

这行代码告诉Java虚拟机在加载类时加载名为 libcalculator.so 的共享库。System.loadLibrary("calculator") 会寻找 libcalculator.so 文件并将其加载到进程的地址空间中。 

        2.声明本地方法

public native int add(int a, int b);

        声明本地方法时,并没有提供实现,表示这个方法将在本地代码中实现。

        3.调用本地方法

        当Java代码中调用 add 方法时,JNI机制会查找对应的本地方法实现。根据命名约定,Java虚拟机会寻找名为 Java_com_example_jnidemo_Calculator_add 的C函数。

        4.映射过程:

       Java虚拟机加载 libcalculator.so 文件时,会建立共享库中的符号表。当调用 add 方法时,Java虚拟机根据命名约定查找符号表中的 Java_com_example_jnidemo_Calculator_add 函数地址。找到地址后,执行对应的C函数,实现本地方法调用。

        详细方法定义与调用以及方法体的代码见第一节

五:.so的位置

注意事项

*/01/*
原来源文件的路径写的是相对路径:
src/main/cpp/native-lib.cpp

报错:could not find souce file

# 提供库的源文件路径:
E:/a_own_codes/android_java/JNIdemo/app/src/main/cpp/native-lib.cpp

*/02/*

Invalidate Caches / Restart:清除所有缓存,并重启 IDE,适合解决缓存问题和一些难以解决的错误。
Just Restart:仅重启 IDE,不清除缓存,适用于普通的重启需求

*/03/*

[CXX5106] NDK was located by using ndk.dir property. This method is deprecated and will be removed in a future release. Please delete ndk.dir from local.properties and set android.ndkVersion to [21.4.7075529] in all native modules in the project. https://developer.android.com/r/studio-ui/ndk-dir

错误信息 [CXX5106] NDK was located by using ndk.dir property. This method is deprecated and will be removed in a future release. 表示使用了已弃用的方式来指定NDK路径。您需要更新配置,将ndk.dir从 local.properties 文件中移除,并使用 android.ndkVersion 配置(见上面的build.gradle文件中的ndkVersion '21.4.7075529')。

*/04/*

在Android Studio中,先点击“Clean Project”,点击“File” -> “Sync Project with Gradle Files”来同步项目,然后点击“Build” -> “Make Project”来构建项目。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/30029.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

当 DolphinDB 遇上方程式赛车:捕捉极速赛场上的时间印记

在风驰电掣的赛车场上&#xff0c;每一毫秒都蕴藏着无限的可能。在这里&#xff0c;数据不再是冰冷的数字序列&#xff0c;而是跳动的脉搏&#xff0c;每一次跃动都精准地回应着赛车的每一次呼吸&#xff0c;敏锐感知着赛车的动态。随着物联网和遥测技术的发展&#xff0c;实时…

六西格玛培训新选择,老字号品质有保障!

在追求企业卓越与完美的道路上&#xff0c;六西格玛管理无疑是一个被广泛认可与采纳的方法论。六西格玛不仅仅是一种管理策略&#xff0c;更是一种文化和哲学&#xff0c;它强调通过数据驱动和持续改进来减少流程中的缺陷&#xff0c;提升客户满意度&#xff0c;并最终实现企业…

【ARM Coresight Debug 系列 -- ARMv8/v9 软件实现断点地址设置】

请阅读【嵌入式开发学习必备专栏 】 文章目录 ARMv8/v9 软件设置断点地址断点地址软件配置流程代码实现 ARMv8/v9 软件设置断点地址 在ARMv8/9架构中&#xff0c;可以通过寄存器 DBGBVR0_EL1 设置断点。这个寄存器是一系列调试断点值寄存器中的第一个DBGBVRn_EL1&#xff0c;其…

jpg图片怎么压缩大小?图片压缩,3个方法

在日常生活中&#xff0c;我们经常会面临着需要在网络上传送、分享或存储的图片文件过大的问题&#xff0c;而JPG格式的图片由于其普遍性&#xff0c;也常常成为我们处理的对象。为了解决这一常见的挑战&#xff0c;学会如何压缩JPG图片的大小是非常实用的技能。 在这篇文章中…

「51媒体」电视台媒体邀约采访报道怎么做?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 电视台作为地方主流媒体&#xff0c;对于新闻报道有着严格的选题标准和报道流程。如果您希望电视台对某个会议或活动进行报道&#xff0c;可以按这样的方法来做&#xff1a; 1.明确活动信…

鼠情自动监测系统

TH-SH1在农业生产中&#xff0c;鼠害问题一直是困扰农民的一大难题。传统的鼠害防治方法往往依赖于大规模施药或布置捕鼠器等方式&#xff0c;这些方法不仅效率低下&#xff0c;而且容易对环境造成污染。随着科技的不断发展&#xff0c;鼠情自动监测系统应运而生&#xff0c;为…

LabVIEW Windows与RT系统的比较与选择

LabVIEW是一种系统设计和开发环境&#xff0c;广泛应用于各类工程和科学应用中。LabVIEW Windows和LabVIEW RT&#xff08;Real-Time&#xff09;是LabVIEW的两个主要版本&#xff0c;分别适用于不同的应用场景。以下从多个角度详细分析两者的区别&#xff0c;并提供选择建议。…

云计算 | (七)特殊云机制

文章目录 📚自动伸缩监听器📚负载均衡器📚SLA监控器📚按使用付费监控器📚审计监控器📚故障转移系统📚虚拟机监控器📚资源集群📚多设备代理📚状态管理数据库📚自动伸缩监听器 自动伸缩监听器 (Automated scaling listener)是一个服务代理,它监控和追踪…

JavaFX 下拉框

组合框允许用户选择几个选项之一。用户可以滚动到下拉列表。组合框可以是可编辑和不可编辑的。 创建组合框 以下代码将选项列表包装到ObservableList中&#xff0c;然后使用observable列表实例化ComboBox类。 ObservableList<String> options FXCollections.observab…

机器学习课程复习——朴素贝叶斯

1. 定义 是一种基于贝叶斯定理与特征条件独立假设的生成式分类方法。 2. 公式 原版公式 简化版公式 由于上述公式无法计算&#xff0c;引入条件独立假设 条件独立版公式 3. 贝叶斯分类器 由上述公式可得贝叶斯分类器 化简为 4. 参数估计 4.1. 极大似然估计 4.2. 学习与分…

【规格说明】软件需求规格说明书实际项目案例模板(doc原件套用)

1 范围 1.1 系统概述 1.2 文档概述 1.3 术语及缩略语 2 引用文档 3 需求 3.1 要求的状态和方式 3.2 系统能力需求 3.3 系统外部接口需求 3.3.1 管理接口 3.3.2 业务接口 3.4 系统内部接口需求 3.5 系统内部数据需求 3.6 适应性需求 3.7 安全性需求 3.8 保密性需求 3.9 环境需求…

【Nginx系列】反向代理在现代网络架构中的重要性

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

C# 利用XejeN框架源码,编写一个在 Winform 界面上的语法高亮的编辑器,使用 Monaco 编辑器

析锦基于Monaco技术实现的Winform语法高亮编辑器 winform中&#xff0c;我们有时需要高亮显示基于某种语言的语法编辑器。 目前比较强大且UI现代化的&#xff0c;无疑是宇宙最强IDE的兄弟&#xff1a;VS Code。 类似 VS Code 的体验&#xff0c;可以考虑使用 Monaco Editor&a…

vue3-父子通信

一个简单的vue3子组件调用父组件方法的demo <template> <div> <h2>Parent Component父组件</h2> <ChildComponent notify-parent"handleParentMethod" /> </div> </template> <script> import { ref } fr…

LVGL开发教程-objects对象

知不足而奋进 望远山而前行 目录 知不足而奋进 望远山而前行​ 文章目录 前言 1.图层 2.objects 2.1 位置 2.2 尺寸 2.3 align 2.4 样式 总结 前言 在嵌入式 GUI 开发中&#xff0c;LVGL&#xff08;Light and Versatile Graphics Library&#xff09;是一个强大的工…

电脑丢失dll文件一键修复的方法有哪些?分析dll文件修复的多种策略

我们经常会遇到各种各样的问题&#xff0c;其中之一就是DLL文件的丢失。DLL文件&#xff08;动态链接库&#xff09;是操作系统和应用程序正常运行所必需的文件&#xff0c;当这些文件丢失或损坏时&#xff0c;可能会导致软件无法正常启动&#xff0c;甚至影响系统的稳定性。对…

SpringMVC系列二: 请求方式介绍

RequestMapping &#x1f49e;基本使用&#x1f49e;RequestMapping注解其它使用方式可以修饰类和方法可以指定请求方式可以指定params和headers支持简单表达式支持Ant 风格资源地址配合PathVariable 映射 URL 绑定的占位符注意事项和使用细节课后作业 上一讲, 我们学习的是Spr…

植物大战僵尸杂交版2024最新手机版下载!功能全面升级,战斗更刺激!

植物大战僵尸杂交版2024——让游戏更加有趣&#xff01; 嘿&#xff0c;各位游戏爱好者们&#xff01;&#x1f31f;今天我要给你们介绍的是一个全新版本的植物大战僵尸——植物大战僵尸杂交版2024。这款游戏不仅保留了原版的经典元素&#xff0c;还增加了许多新的特性和玩法&a…

操作系统 大作业

1、现有成绩文件按“姓名 学校 年级 班级 分数”五列组成&#xff0c;编写Shell脚本&#xff0c;将某目录下所有成绩文件&#xff08;≥3个&#xff09;合并为一个&#xff0c;形成“姓名 班级 分数”三列&#xff0c;并按成绩排序&#xff0c;输出年级排名前十。同时输出60以下…

实现一个渐进优化的 Linux cp 命令

1&#xff0c;第1版 copy 先写个轮廓 selfcp.c &#xff1a; #include <stdio.h>int main() {FILE *source, *destination;char ch;source fopen("H222.txt", "r");if (source NULL) {printf("Error opening source file!\n");retur…