jni理解

发布于:2025-07-31 ⋅ 阅读:(33) ⋅ 点赞:(0)
  1. 定义 JNI 方法映射表(注册表)
    对应原文件中的 sScreenCaptureMethods 数组,用于声明 Java native 方法与 C++ 函数的映射关系:
// ... 其他代码(如结构体定义、工具函数)...

// ----------------------------------------------------------------------------

// JNI 方法映射表(动态注册核心)
static const JNINativeMethod sMyDynamicMethods[] = {
    // { Java层native方法名, 方法签名, C++函数指针 }
    {"nativeAddNumbers", "(II)I", (void*)nativeAddNumbers},          // 示例1:两数相加
    {"nativeGetDeviceInfo", "()Ljava/lang/String;", (void*)nativeGetDeviceInfo}, // 示例2:获取设备信息
};

// ... 后续注册函数 ...
  1. 实现 C++ 函数
// ... 其他代码 ...

// 示例1:两数相加(对应 Java 的 nativeAddNumbers(int a, int b))
static jint nativeAddNumbers(JNIEnv* env, jclass clazz, jint a, jint b) {
    return a + b; // 简单业务逻辑
}

// 示例2:获取设备信息(对应 Java 的 nativeGetDeviceInfo())
static jstring nativeGetDeviceInfo(JNIEnv* env, jclass clazz) {
    std::string info = "Model: RK3576; SDK: 33"; // 模拟设备信息
    return env->NewStringUTF(info.c_str()); // 返回 Java String
}

// ... JNI 方法映射表(见步骤1)...
  1. 实现注册函数
    对应原文件中的 register_android_window_ScreenCapture 函数,将映射表注册到 JVM:
// ... JNI 方法映射表(见步骤1)...

// 注册函数:将 sMyDynamicMethods 映射表注册到 Java 类
int register_com_example_MyDynamicJni(JNIEnv* env) {
    // 1. 指定 Java 类全路径(需与 Java 层包名+类名一致)
    const char* javaClassName = "com/example/MyDynamicJni";
    
    // 2. 注册映射表(通过 RegisterMethodsOrDie 完成注册)
    int err = RegisterMethodsOrDie(
        env, 
        javaClassName,                // Java 类名
        sMyDynamicMethods,            // JNI 方法映射表
        NELEM(sMyDynamicMethods)      // 映射表长度(自动计算元素个数)
    );

    // 3. (可选)初始化 Java 类的字段/方法 ID(如原文件中的 gCaptureArgsClassInfo)
    jclass myClass = FindClassOrDie(env, javaClassName);
    // ... (如需操作 Java 对象字段,可在此获取 fieldID/methodID)...

    return err; // 返回注册结果(0 表示成功)
}

} // namespace android
  1. Java 层配套代码(需手动编写)
    动态注册需对应 Java 类中声明 native 方法,例如 MyDynamicJni.java
package com.example;

public class MyDynamicJni {
    // 加载 native 库(对应编译生成的 libxxx.so)
    static {
        System.loadLibrary("my_dynamic_jni"); // 库名需与 Android.bp 中定义一致
    }

    // 声明 native 方法(方法名、参数、返回值需与 JNI 映射表完全匹配)
    public native int nativeAddNumbers(int a, int b);
    public native String nativeGetDeviceInfo();

    // 测试调用
    public static void main(String[] args) {
        MyDynamicJni jni = new MyDynamicJni();
        System.out.println("1+2=" + jni.nativeAddNumbers(1, 2)); // 输出 3
        System.out.println("Device Info: " + jni.nativeGetDeviceInfo()); // 输出设备信息
    }
}
原文件关键元素 示例对应部分 作用说明
sScreenCaptureMethods sMyDynamicMethods 定义 Java 方法名与 C++ 函数的映射关系,无需依赖 Java_xxx 命名规则
nativeCaptureDisplay nativeAddNumbers C++ 业务逻辑的具体实现,函数名可自定义(通过映射表与 Java 方法关联)
register_android_window_ScreenCapture register_com_example_MyDynamicJni 将映射表注册到虚拟机,完成 Java 与 C++ 方法的绑定

为什么需要动态注册?

  1. 灵活命名:C++ 函数名无需遵循冗长的 Java_包名_类名_方法名 格式(如原文件中直接使用 nativeCaptureDisplay,而非 Java_android_window_ScreenCapture_nativeCaptureDisplay)。

  2. 批量管理:通过映射表统一管理所有 native 方法,便于维护(如原文件中 sScreenCaptureMethods 集中声明了 6 个方法映射)。

  3. 性能优化:动态注册比静态注册(依赖虚拟机查找函数名)效率更高,尤其适合系统框架层存在大量 JNI 方法的场景


网站公告

今日签到

点亮在社区的每一天
去签到