android中的JNI的DEMO

news2024/11/17 16:29:23

一:源代码

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" {
#endif

JNIEXPORT 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);

    @Override
    protected 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.coloradmin.cn/o/1839112.html

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

相关文章

【Win】双系统新体验:Hyper-V上macOS安装攻略

在虚拟化的世界里&#xff0c;Hyper-V是探索不同操作系统的一扇大门。尽管macOS并不是Hyper-V官方支持的来宾操作系统&#xff0c;但这并未阻挡技术探索者的脚步。他们通过不懈努力&#xff0c;开辟出了一条条通往macOS的非官方路径。这些路径或许曲折&#xff0c;却为那些渴望…

《QT从基础到进阶·七十二》基于Qt开发的文件保险柜工具并支持文件各种加密和解密

1、概述 源码放在文章末尾 该项目实现了文件各种加密和解密的功能&#xff0c;能够有效的保障文件的安全&#xff0c;主要包含如下功能&#xff1a; 1、支持所有 AES 密钥长度&#xff1b; AES_128 AES_192 AES_256 2、支持ECB、CBC、CFB、OFB四种模式&#xff1b; 3、支持ZER…

【学习】程序员资源网站

1 书栈网 简介&#xff1a;书栈网是程序员互联网IT开源编程书籍、资源免费阅读的网站&#xff0c;在书栈网你可以找到很多书籍、笔记资源。在这里&#xff0c;你可以根据热门收藏和阅读查看大家都在看什么&#xff0c;也可以根据技术栈分类找到对应模块的编程资源&#xff0c;…

构建高效的大数据量延迟任务调度平台

目录 引言系统需求分析系统架构设计 总体架构任务调度模块任务存储模块任务执行模块 任务调度算法 时间轮算法优先级队列分布式锁 数据存储方案 关系型数据库NoSQL数据库混合存储方案 容错和高可用性 主从复制数据备份与恢复故障转移 性能优化 水平扩展缓存机制异步处理 监控与…

深度解析“科技信贷”:构建科技支行的五维模型

科技信贷是指金融机构为支持科技创新、技术改造和设备更新等领域提供的专项信贷服务&#xff0c;旨在促进科技企业的发展和技术的进步。科技信贷在推动科技企业和创新项目发展方面具有重要作用&#xff0c;其特点在于提供定制化的金融支持&#xff0c;以满足科技创新链条中的融…

nginx+tomcat负载均衡、动静分离群集【☆☆☆☆☆】

Nginx是一款非常优秀的HTTP服务器软件&#xff0c;性能比tomcat更优秀&#xff0c;它支持高达50 000个并发连接数&#xff0c;拥有强大的静态资源处理能力&#xff0c;运行稳定&#xff0c;内存、CPU等系统资源消耗非常低。目前很多大型网站都应用Nginx服务器作为后端网站程序的…

项目四 OpenStack身份管理

任务一 理解身份服务 1.1 •Keystone的基本概念 • 认证 &#xff08; Authentication &#xff09; —— 确认 用户身份的过程&#xff0c;又称身份验证 。 • 凭证 &#xff08; Credentials &#xff09; —— 又 称凭据&#xff0c;是用于确认用户身份的数据 。 • 令牌 …

小林图解系统-二.硬件结构 2.5CPU是如何执行任务的?

CPU如何读取数据的&#xff1f; CPU访问L1 Cache速度比访问内存快100倍&#xff0c;有高速缓存的目的&#xff1a;把Cache作为CPU与内存之间的缓存层&#xff0c;减少对内存的访问频率 所有CPU Cache Line是CPU从内存读取数据到Cache的单位。 64字节 CPU加载数组里面连续的多…

【千帆AppBuilder】你有一封邮件待查收|未来的我,你好吗?欢迎体验AI应用《未来信使》

我在百度智能云千帆AppBuilder开发了一款AI原生应用&#xff0c;快来使用吧&#xff01;「未来信使」&#xff1a;https://appbuilder.baidu.com/s/Q1VPg 目录 背景人工智能未来的信 未来信使功能介绍Prompt组件 千帆社区主要功能AppBuilderModelBuilder详细信息 推荐文章 未来…

【APP移动端性能测试】第一节.APP应用架构、环境和敏捷开发模型介绍

文章目录 前言一、APP应用架构二、APP项目环境 2.1 后端项目环境 2.2 前端项目环境三、Scrum敏捷开发模型 3.1 Scrum敏捷模型基础介绍 3.2 Scrum敏捷开发开发流程总结 前言 一、APP应用架构 &#xff08;1&#xff09;APP应用架构 &#xff08;2&#xff0…

C++240618

1> 思维导图 2> 完善对话框&#xff0c;点击登录对话框&#xff0c; 如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出**提示”登录成功“** &#xff0c;提供一个 **OK按钮**&#xff0c;用户点击**OK后**&#xff0c;**关闭登录界面**&#xff0c; 跳转…

Canonical Juju 的一个奇怪编排部署

一周前的一个项目扩容出现了异常&#xff0c;进行了操作回滚&#xff0c;未对线上业务造成损失。 现象是这样的&#xff1a; 通过基于 Canonical Juju-GUI 在一组节点上部署了某个组件&#xff0c;在把这组节点添加到集群后&#xff0c;有4个节点上出现了同一组件的2个instanc…

Postman文件数据导入导出

前言 不同的接口测试工具如Postman、Apipost、Apifox创建的接口文档都是互通的&#xff0c;都可以互相兼容使用。我们就不需要在3个不同测试工具都去创建&#xff0c;只要在一个工具上创建&#xff0c;想要在其他接口测试工具上使用就运用导入和导出功能即可。 Postman、Apip…

爆赞!GitHub首本Python开发实战背记手册,标星果然百万名不虚传

Python (发音:[ paiθ(ə) n; (US) paiθɔn ] n. 蟒蛇&#xff0c;巨蛇 )&#xff0c;是一种面向对象的解释性的计算机程序设计语言&#xff0c;也是一种功能强大而完善的通用型语言&#xff0c;已经具有十多年的发展历史&#xff0c;成熟且稳定。Python 具有脚本语言中最丰富…

【接口自动化测试】第二节.Requests库和接口对象封装

文章目录 前言一、Requests库 1.1 Requests介绍 1.2 Requests发送请求 1.3 Requests查看响应 1.4 案例1登录接口调试-获取验证码 1.5 案例2登录接口调试-登录 1.6 归纳小结二、接口对象封装 2.1 当前代码待优化问题 2.2 接口对象封装思…

互联网应用主流框架整合之SpingMVC运转逻辑及高级应用

Spring MVC处理器的执行过程 在SpringMVC的流程中&#xff0c;它会把控制器的方法封装为处理器(Handler)&#xff0c;为了更加灵活&#xff0c;SpringMVC还提供了处理器的拦截器&#xff0c;从而形成了一条包括处理器和拦截器的执行链&#xff0c;即HandlerExecutionChain&…

Linux-安装及管理程序

目录 一、Linux应用程序基础 1、应用程序与系统命令的关系 2、 典型应用程序的目录结构 3、常见的软件包封装类型 二、RPM包管理工具 1、RPM包管理器 2、RPM软件包 ​3、RPM的命令格式 4、RPM命令的常用选项 5、RPM安装 三、 yum安装 1、yum源介绍 1.1、本地yum源 …

给日期加上15天

// 给当前日期加上15天 function toAndTimeFifteen(params) {let startDate new Date(params); // 创建一个Date对象表示2024年5月31日startDate.setDate(startDate.getDate() 15); // 给当前日期加上15天let dateString formatDate(startDate)// 转换时间格式return dateSt…

自动水位雨量站:用于水库防汛预警

TH-SW2自动水位雨量站是一种现代化的监测设备&#xff0c;主要用于水库等水域的防汛预警系统。它通过集成水位和雨量监测功能&#xff0c;为水库的管理和调度提供实时、准确的数据支持。 工作原理&#xff1a; 自动水位雨量站通过内置的水位计和雨量计实时监测水库的水位变化和…

C++封装TCP类,包括客户端和服务器

头文件 XTcp.h #ifndef XTCP_H #define XTCP_H#ifdef WIN32 #ifdef XSOCKET_EXPORTS #define XSOCKET_API __declspec(dllexport) #else #define XSOCKET_API __declspec(dllimport) #endif #else #define XSOCKET_API #endif#include <string> XSOCKET_API std::string…