1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
| 1️⃣ 什么是 JNI
JNI(Java Native Interface)是 Java 调用 C/C++ 代码 的接口。 在 Android 上,JNI 通常用于: 大量数学运算、图像处理、音视频编解码、机器学习推理等 视频滤镜、OpenCV 图像处理 比如操作蓝牙、摄像头底层驱动、DSP 加速等
调用现有 C/C++ 库
访问底层硬件或系统 API(超出 Java 层能力)
Android 本身用 Java 访问底层功能不方便,或者第三方库只提供 C 接口。 典型例子:BaiduMap、腾讯 IM、游戏引擎。
2️⃣ JNI 的基本流程 步骤 1:创建 native 方法
在 Java/Kotlin 中声明一个 native 方法:
public class NativeLib { static { System.loadLibrary("mylib"); // 加载 .so }
// 声明 native 方法 public native int addNumbers(int a, int b); }
步骤 2:生成 C/C++ 函数签名
JNI 方法在 C/C++ 层定义时,需要 特定签名:
#include <jni.h>
extern "C" JNIEXPORT jint JNICALL Java_com_example_myapp_NativeLib_addNumbers(JNIEnv *env, jobject thiz, jint a, jint b) { return a + b; }
JNIEXPORT 和 JNICALL 是宏,确保函数正确导出
JNIEnv* 是 JNI 环境指针,用于调用 Java 方法或访问对象
jobject thiz 对应 Java 的实例对象(非静态方法)
参数类型对应 jint, jstring, jobject 等 JNI 类型
步骤 3:构建 .so 库
使用 CMake 或 ndk-build:
CMake 示例(CMakeLists.txt):
cmake_minimum_required(VERSION 3.4.1)
add_library(mylib SHARED native-lib.cpp)
find_library(log-lib log)
target_link_libraries(mylib ${log-lib})
然后在 build.gradle 中集成:
externalNativeBuild { cmake { path "CMakeLists.txt" } }
步骤 4:调用 NativeLib lib = new NativeLib(); int sum = lib.addNumbers(3, 5); Log.d("JNI", "sum = " + sum);
3️⃣ 常用 JNI 类型映射 Java 类型 JNI 类型 int jint long jlong float jfloat double jdouble boolean jboolean byte[] jbyteArray String jstring Object jobject int[] jintArray 4️⃣ JNI 常用函数
字符串转换
const char* str = env->GetStringUTFChars(jstringObj, 0); // 使用完释放 env->ReleaseStringUTFChars(jstringObj, str);
数组操作
jint *arr = env->GetIntArrayElements(jintArrayObj, 0); // 操作数组 env->ReleaseIntArrayElements(jintArrayObj, arr, 0);
调用 Java 方法
jclass cls = env->GetObjectClass(obj); jmethodID mid = env->GetMethodID(cls, "callback", "(I)V"); env->CallVoidMethod(obj, mid, 100);
|