接入第三方 so 库时需要注意目标设备是否支持,不然会找不到 so 库
abiFilters是用于指定在构建Android应用程序时应包含哪些CPU架构ABI(Application Binary Interface)的一种配置参数。它的常见取值包括"armeabi-v7a"、“arm64-v8a”、“x86”、"x86_64"等,具体取决于应用程序要支持的目标设备的CPU架构。在构建Gradle/Android项目时,可以通过在build.gradle配置文件中设置abiFilters来指定所需的CPU架构ABI。
app/
src/
main/
jniLibs/
armeabi-v7a/ // 32位 ARM
libthirdparty.so
arm64-v8a/ // 64位 ARM
libthirdparty.so
x86/ // x86
libthirdparty.so
或者在 build.gradle 中指定库的位置:
android {
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
public class NativeWrapper {
static {
// 先加载依赖库(如果有)
System.loadLibrary("dependency");
// 然后加载目标库
System.loadLibrary("thirdparty");
// 最后加载你自己的JNI库
System.loadLibrary("mylibrary");
}
// 声明native方法
public native int callThirdPartyFunction(int param);
}
创建 jni/mylibrary.c 文件:
#include
#include
// 声明第三方库的函数
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;
}
add_library(thirdparty SHARED IMPORTED)
set_target_properties(thirdparty PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/libthirdparty.so)
add_library(mylibrary SHARED
mylibrary.c)
target_link_libraries(mylibrary thirdparty)
检查库文件名是否正确(前缀 lib,后缀 .so)
检查库是否放在正确的 ABI 目录下
检查是否有依赖库未加载
使用 nm -D libthirdparty.so 检查导出的函数名
可能需要 extern “C” 包装
确保应用和所有库使用相同的 ABI
64位设备可以运行32位库,但反过来不行
原因: include_directories 设置的路径不对
解决方法:根据自己项目实际情况设置路径
确保项目中只包含一个libc++_shared.so版本。可以通过在项目的build.gradle文件中配置packagingOptions来选择第一个找到的libc++_shared.so文件,使用pickFirst策略5。
CMakeLists.txt 额外配置 target_link_libraries
target_link_libraries(local_lib1
# List libraries link to the target library
android
log)
target_link_libraries(local_lib2
# List libraries link to the target library
android
log)
对数组进行初始化赋值
char a[10] = {""};
严格按照 api 文档传入指针
问题原因是如下代码中,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_8888
if (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 转换为 NV12
ARGB_to_NV12(static_cast<jint *>(pixels), nv12, width, height);
// 释放资源
env->ReleaseByteArrayElements(nv12Array, nv12, 0);
AndroidBitmap_unlockPixels(env, bitmap);
return nv12Array;
}
算法给的头文件,可能会包含一些你不需要的代码,之间删除即可,不影响调用。
Android jni引用第三方so动态库和.a静态库并且调用©方法
Android JNI学习-调用第三方SO库
Android 通过JNI调用三方so 高效教程
cmake使用详细教程(日常使用这一篇就足够了)