Android Jni(二)加载调用第三方 so 库

文章目录

      • Android Jni(二)加载调用第三方 so 库
      • 前置知识
        • CPU架构 ABI
      • 基本步骤
        • 1、将第三方 SO 库文件放入项目中的正确位置:
        • 2. 创建 JNI 接口
        • 3. 实现 JNI 层代码
        • 4、配置 CMake
      • 常见问题解决
        • 1、UnsatisfiedLinkError:
        • 2、函数找不到:
        • 3、ABI 不匹配:
      • 遇到的问题
        • 1、include 找不到头文件
        • 2、Jni 不同库的引入了重复 so,导致冲突
        • 3、多个本地库
        • 4、return NewStringUTF(char*) 报格式错误
        • 5、指针类型不一致报错
        • 6、Bitmap 转 yuv 反色
        • 7、接入的三方库头文件依赖了其他头文件找不到
      • 参考文章

Android Jni(二)加载调用第三方 so 库

前置知识

CPU架构 ABI

接入第三方 so 库时需要注意目标设备是否支持,不然会找不到 so 库

abiFilters是用于指定在构建Android应用程序时应包含哪些CPU架构ABI(Application Binary Interface)的一种配置参数。它的常见取值包括"armeabi-v7a"、“arm64-v8a”、“x86”、"x86_64"等,具体取决于应用程序要支持的目标设备的CPU架构。在构建Gradle/Android项目时,可以通过在build.gradle配置文件中设置abiFilters来指定所需的CPU架构ABI。

基本步骤

1、将第三方 SO 库文件放入项目中的正确位置:
app/src/main/jniLibs/armeabi-v7a/    // 32位 ARMlibthirdparty.soarm64-v8a/      // 64位 ARMlibthirdparty.sox86/            // x86libthirdparty.so

或者在 build.gradle 中指定库的位置:

android {sourceSets {main {jniLibs.srcDirs = ['libs']}}
}
2. 创建 JNI 接口
public class NativeWrapper {static {// 先加载依赖库(如果有)System.loadLibrary("dependency");// 然后加载目标库System.loadLibrary("thirdparty");// 最后加载你自己的JNI库System.loadLibrary("mylibrary");}// 声明native方法public native int callThirdPartyFunction(int param);
}
3. 实现 JNI 层代码

创建 jni/mylibrary.c 文件:

#include <jni.h>
#include <android/log.h>// 声明第三方库的函数
extern int third_party_function(int param);JNIEXPORT jint JNICALL
Java_com_example_NativeWrapper_callThirdPartyFunction(JNIEnv *env, jobject instance, jint param) {// 调用第三方库函数int result = third_party_function(param);return (jint)result;
}
4、配置 CMake
add_library(thirdparty SHARED IMPORTED)
set_target_properties(thirdparty PROPERTIES IMPORTED_LOCATION${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libthirdparty.so)add_library(mylibrary SHAREDmylibrary.c)target_link_libraries(mylibrary thirdparty)

常见问题解决

1、UnsatisfiedLinkError:

检查库文件名是否正确(前缀 lib,后缀 .so)
检查库是否放在正确的 ABI 目录下
检查是否有依赖库未加载

2、函数找不到:

使用 nm -D libthirdparty.so 检查导出的函数名

可能需要 extern “C” 包装

3、ABI 不匹配:

确保应用和所有库使用相同的 ABI

64位设备可以运行32位库,但反过来不行

遇到的问题

1、include 找不到头文件

原因: include_directories 设置的路径不对
解决方法:根据自己项目实际情况设置路径
在这里插入图片描述

2、Jni 不同库的引入了重复 so,导致冲突

确保项目中只包含一个libc++_shared.so版本。可以通过在项目的build.gradle文件中配置packagingOptions来选择第一个找到的libc++_shared.so文件,使用pickFirst策略5。

3、多个本地库

CMakeLists.txt 额外配置 target_link_libraries

target_link_libraries(local_lib1# List libraries link to the target libraryandroidlog)target_link_libraries(local_lib2# List libraries link to the target libraryandroidlog)
4、return NewStringUTF(char*) 报格式错误
对数组进行初始化赋值
char a[10] = {""};
5、指针类型不一致报错

严格按照 api 文档传入指针

6、Bitmap 转 yuv 反色

问题原因是如下代码中,g b 数据通道,赋值反了,如何保存的 ARGB_8888 注释中有写。
在这里插入图片描述

#include <android/bitmap.h>
#include <jni.h>
#include <cstdint>
#include <cstring>// ARGB 转 NV12 的函数
void ARGB_to_NV12(jint *argb, jbyte *nv12, jint width, jint height) {int frameSize = width * height;int yIndex = 0;int uvIndex = frameSize;for (int j = 0; j < height; ++j) {for (int i = 0; i < width; ++i) {int R = (argb[(j * width) + i] >> 16) & 0xFF;int G = (argb[(j * width) + i] >> 8) & 0xFF;int B = argb[(j * width) + i] & 0xFF;// 计算 YUV 分量int Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;int U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;int V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;// 存储 Y 分量nv12[yIndex++] = static_cast<jbyte>((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));// 存储 UV 分量(交错存储)if (j % 2 == 0 && i % 2 == 0) {nv12[uvIndex++] = static_cast<jbyte>((U < 0) ? 0 : ((U > 255) ? 255 : U));nv12[uvIndex++] = static_cast<jbyte>((V < 0) ? 0 : ((V > 255) ? 255 : V));}}}
}// JNI 函数
extern "C"
JNIEXPORT jbyteArray JNICALL
Java_com_example_YourClass_convertBitmapToNV12(JNIEnv *env, jobject thiz, jobject bitmap) {AndroidBitmapInfo info;void *pixels;jbyteArray nv12Array = nullptr;// 获取 Bitmap 信息if (AndroidBitmap_getInfo(env, bitmap, &info) != ANDROID_BITMAP_RESULT_SUCCESS) {return nullptr;}// 检查 Bitmap 格式是否为 RGBA_8888if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {return nullptr;}// 锁定 Bitmap 像素数据if (AndroidBitmap_lockPixels(env, bitmap, &pixels) != ANDROID_BITMAP_RESULT_SUCCESS) {return nullptr;}int width = info.width;int height = info.height;int frameSize = width * height;// 创建 NV12 数组(Y 分量占 width * height,UV 分量占 width * height / 2)nv12Array = env->NewByteArray(frameSize * 3 / 2);jbyte *nv12 = env->GetByteArrayElements(nv12Array, nullptr);// 将 ARGB 转换为 NV12ARGB_to_NV12(static_cast<jint *>(pixels), nv12, width, height);// 释放资源env->ReleaseByteArrayElements(nv12Array, nv12, 0);AndroidBitmap_unlockPixels(env, bitmap);return nv12Array;
}
7、接入的三方库头文件依赖了其他头文件找不到

算法给的头文件,可能会包含一些你不需要的代码,之间删除即可,不影响调用。

参考文章

Android jni引用第三方so动态库和.a静态库并且调用©方法

Android JNI学习-调用第三方SO库

Android 通过JNI调用三方so 高效教程

cmake使用详细教程(日常使用这一篇就足够了)

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

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

相关文章

服务器本地搭建

socket函数 它用于创建一个新的套接字&#xff08;socket&#xff09;。 函数原型 #include <sys/socket.h> int socket(int domain, int type, int protocol);参数解释 domain&#xff1a;它指定了通信所使用的协议族&#xff0c;常见的取值如下&#xff1a; AF_INET…

MIP-Splatting:全流程配置与自制数据集测试【ubuntu20.04】【2025最新版】

一、引言 在计算机视觉和神经渲染领域&#xff0c;3D场景重建与渲染一直是热门研究方向。近期&#xff0c;3D高斯散射&#xff08;3D Gaussian Splatting&#xff09;因其高效的渲染速度和优秀的视觉质量而受到广泛关注。然而&#xff0c;当处理大型复杂场景时&#xff0c;这种…

Redis 高可用集群搭建与优化实践

在分布式系统中,缓存技术用于提升性能和响应速度。 Redis 作为一款高性能的键值存储系统,广泛应用于缓存、消息队列和会话管理等场景。随着业务规模的扩大,单机 Redis 的性能和可用性逐渐无法满足需求。 因此,搭建高可用的 Redis 集群可以解决这一问题。我将详细介绍 Red…

专题十五:动态路由——BGP

一、BGP的基本概念 BGP&#xff08;Border Gateway Protocol&#xff0c;边界网关协议&#xff09;是一种用于在不同自治系统&#xff08;AS&#xff09;之间交换路由信息的外部网关协议&#xff08;EGP&#xff09;。通过TCP179端口建立连接。目前采用BGP4版本&#xff0c;IP…

【Flask开发】嘿马文学web完整flask项目第4篇:4.分类,4.分类【附代码文档】

教程总体简介&#xff1a;2. 目标 1.1产品与开发 1.2环境配置 1.3 运行方式 1.4目录说明 1.5数据库设计 2.用户认证 Json Web Token(JWT) 3.书架 4.1分类列表 5.搜索 5.3搜索-精准&高匹配&推荐 6.小说 6.4推荐-同类热门推荐 7.浏览记录 8.1配置-阅读偏好 8.配置 9.1项目…

在Mac上离线安装k3s

目录 首先是安装multipass。 1. 系统要求 2. 环境准备 本来想照着网上文档学习安装一下k3s&#xff0c;没想到在docker被封了之后&#xff0c;现在想通过命令行去下载github的资源也不行了&#xff08;如果有网友看到这个文档、并且知道问题原因的&#xff0c;请留言告知&am…

vscode+wsl 运行编译 c++

linux 的 windows 子系统&#xff08;wsl&#xff09;是 windows 的一项功能&#xff0c;可以安装 Linux 的发行版&#xff0c;例如&#xff08;Ubuntu&#xff0c;Kali&#xff0c;Arch Linux&#xff09;等&#xff0c;从而可以直接在 windows 下使用 Linux 应用程序&#xf…

基于源码分析 HikariCP 常见参数的具体含义

HikariCP 是目前风头最劲的 JDBC 连接池&#xff0c;号称性能最佳&#xff0c;SpringBoot 2.0 也将 HikariCP 作为默认的数据库连接池。 要想用好 HikariCP&#xff0c;理解常见参数的具体含义至关重要。但是对于某些参数&#xff0c;尽管官方文档给出了详细解释&#xff0c;很…

docker部署scylladb

创建存储数据的目录和配置目录 mkdir -p /root/docker/scylla/data/data /root/docker/scylla/data/commitlog /root/docker/scylla/data/hints /root/docker/scylla/data/view_hints /root/docker/scylla/conf快速启动拷贝配置文件 docker run -d \--name scylla \scylladb/…

golang 在windows 系统的交叉编译

基本交叉编译命令 GOOS目标操作系统 GOARCH目标架构 go build -o 输出文件名 包路径 编译 Linux 64位程序 set GOOSlinux set GOARCHamd64 go build -o myapp-linux main.go 编译 MacOS (Darwin) 64位程序 set GOOSdarwin set GOARCHamd64 go build -o myapp-macos main.go …

本地mock服务编写

确认有需要mock的接口文档后&#xff0c;本地可以mock服务编写&#xff1b; 用于测试UI事务、模拟对接组件等&#xff1b; 使用python FLASK可以轻松建立本地mock服务端&#xff0c;注册预期的接口响应&#xff01;flask会在接收端持续打印收到的请求&#xff01; 注意&#…

京东云智能体平台joybuilder v3.0.0测试

平台介绍&#xff1a; JoyBuilder 是京东云推出的 AI 原生应用开发平台&#xff0c;以下是对它的具体介绍&#xff1a; 开发方式便捷高效&#xff1a;将 AI 能力融入低代码平台&#xff0c;用户通过对话式交互方式&#xff0c;输入如 “创建客户反馈管理系统” 等需求&#x…

前端实现对接现成文件下载接口(xlsx)

针对于Ant Design 框架 1.在你的api文件下编写接口路径 import request from /utils/request import storage from storeimport {AUTHORIZATION} from /store/mutation-types const api {downloadVocabularyTemplate:/vocabulary/downloadVocabularyTemplate, }export funct…

TCPIP详解 卷1协议 六 DHCP和自动配置

6.1——DHCP和自动配置 为了使用 TCP/IP 协议族&#xff0c;每台主机和路由器需要一定的配置信息。基本上采用3种方法&#xff1a;手工获得信息&#xff1b;通过一个系统获得使用的网络服务&#xff1b;使用某种算法自动确定。 拥有一个IP 地址和子网掩码&#xff0c;以及 DN…

联想电脑开机出现Defalut Boot Device Missing or Boot Failed怎么办

目录 一、恢复bios默认设置 二、关机重启 三、“物理”方法 在图书馆敲代码时&#xff0c;去吃了午饭回来发现刚开机就出现了下图的问题&#xff08;崩溃&#xff09;&#xff0c;想起之前也发生过一次 这样的问题&#xff0c;现在把我用到的方法写在下面&#xff0c;可能对…

用户登陆UI

本节任务 完成用户登陆UI&#xff0c;点击登陆按钮跳转到应用主页 界面原型&#xff1a; 登陆页面&#xff1a; 登陆成功页面&#xff1a; 涉及知识点&#xff1a; 线性布局Image组件输入框复选框分割线按钮路由跳转背景色、内容对齐 1 新建项目 录入项目信息&#xff1a;…

linux多线(进)程编程——(1)前置知识

liunx多线程编程&#xff08;前置知识&#xff09;前置知识 前言 学习编程就像是修仙&#xff0c;分为宗门的正统修士&#xff08;计算机专业的学生&#xff09;&#xff0c;以及野修&#xff08;半路转码&#xff09;。正统修士有各大宗门的功法&#xff0c;保证一路修行畅通…

Npfs!NpFsdCreate函数分析之从NpCreateClientEnd函数分析到Npfs!NpSetConnectedPipeState

第一部分&#xff1a; 1: kd> g Breakpoint 5 hit Npfs!NpFsdCreate: baaecba6 55 push ebp 1: kd> kc # 00 Npfs!NpFsdCreate 01 nt!IofCallDriver 02 nt!IopParseDevice 03 nt!ObpLookupObjectName 04 nt!ObOpenObjectByName 05 nt!IopCreateFile 06…

【软件测试】bug 篇

本章思维导图&#xff1a; 1. 软件测试的生命周期 软件测试贯穿于整个软件的生命周期 流程阶段需求分析测试计划测试设计/开发测试执行测试评估上线运行维护具体工作内容1. 阅读需求文档 2. 标记可测试需求 3. 确定测试类型1. 制定测试范围 2. 选择测试工具 3. 分配资源1. 编写…

「Unity3D」图片导入选项取消Read/Write,就无法正确显示导入大小,以及Addressable打包无法正确显示的问题

如果在Edit -> Project Settings -> Editor中的“Load texture data on demand”勾选&#xff0c;就会让图片导入设置中&#xff0c;不勾选Read/Write&#xff0c;就无法正确显示纹理的大小数字。 更进一步的问题是&#xff0c;使用Addressable打包的时候&#xff0c; 如…