Android JNI 动态注册:获取系统内存页大小

之前是用静态注册方式,通过 javac -h 生成头文件,函数名必须严格遵循 Java_包名_类名_方法名 的命名规则,这种方式如果 Java 类重命名或包路径调整,所有 native 函数名都要同步修改。再试下动态注册,它通过 JNI_OnLoad 和 RegisterNatives 手动绑定 Java 方法与 C++ 函数,解耦命名约束,是大型项目和生产级 SDK 的首选方案。

新建一个工程试下, 创建获取系统内存页的类,包名和类名没有约束。 如下

java 复制代码
package com.example.nativedemo3;

public class PageSizeHelper { // 这个类命名没有任何约束。
    static {
        System.loadLibrary("page_size_dynamic");
    }

    // 获取页大小
    public static native long getPageSize();
}

再在main目录下创建cpp目录:

在cpp目录下创建page_size_dynamic.cpp, 内容如下:

cpp 复制代码
#include <jni.h>
#include <unistd.h>
#include <android/log.h>

#define TAG "PageSize"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)

// 实际的函数实现,函数名可以任意
static jlong GetPageSize(JNIEnv *env, jclass clazz) {
    return (jlong) sysconf(_SC_PAGESIZE);
}

// JNI 方法数组
static const JNINativeMethod methods[] = {
        {"getPageSize", "()J", (void*)GetPageSize},
};

// 加载库时自动调用
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env = nullptr;
    if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }

    // 找到要注册的 Java 类(全限定名,注意点号改为斜杠)
    jclass clazz = env->FindClass("com/example/nativedemo3/PageSizeHelper");
    if (clazz == nullptr) {
        LOGI("FindClass failed");
        return JNI_ERR;
    }

    // 注册 native 方法
    if (env->RegisterNatives(clazz, methods, sizeof(methods)/sizeof(methods[0])) < 0) {
        LOGI("RegisterNatives failed");
        return JNI_ERR;
    }

    LOGI("RegisterNatives success!");

    return JNI_VERSION_1_6;
}

重点看下:

复制代码
// JNI 方法数组
static const JNINativeMethod methods[] = {
        {"getPageSize", "()J", (void*)GetPageSize},
};

其中JNINativeMethod 是一个结构体,作用是表示java方法和c++函数的映射关系。 该结构体在jni.h文件中,如下:

(1)name为java类中的 native 方法名,这里是getPageSize。

(2)signature 为Java 方法签名(参数和返回类型的编码字符串) ,() 表示无参数,J 表示返回类型为 long(对应 Java 的 long,JNI 中的 jlong)。

常见方法签名:

(3) fnPtr为c/c++的函数指针,这里是GetPageSize 函数。

再在 src/main/cpp/ 下创建 CMakeLists.txt,内容如下:

bash 复制代码
cmake_minimum_required(VERSION 3.4.1)
project("nativeDemo3")  #工程名,随意

add_library(
        page_size_dynamic
        SHARED
        page_size_dynamic.cpp
)

find_library(log-lib log)
target_link_libraries(page_size_dynamic ${log-lib})

其中 find_library(log-lib log) 意思是找到系统自带的 log 库(liblog.so),并把它命名为 log-lib 。

target_link_libraries(page_size_dynamic ${log-lib}) 意思是 把自己的库 和 系统 log 库 链接到一起。

再配置 build.gradle.kts :

build.gradle.kts 完整代码如下

Groovy 复制代码
plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.kotlin.compose)
}

android {
    namespace = "com.example.nativedemo3"
    compileSdk {
        version = release(36)
    }

    defaultConfig {
        applicationId = "com.example.nativedemo3"
        minSdk = 29
        targetSdk = 36
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

        ndk {
            abiFilters.addAll(listOf("arm64-v8a", "armeabi-v7a"))
        }

        externalNativeBuild {
            cmake {
                cppFlags("-std=c++17")
            }
        }
    }

    externalNativeBuild {
        cmake {
            path = file("src/main/cpp/CMakeLists.txt")
        }
    }

    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
    buildFeatures {
        compose = true
    }
}

dependencies {
    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.lifecycle.runtime.ktx)
    implementation(libs.androidx.activity.compose)
    implementation(platform(libs.androidx.compose.bom))
    implementation(libs.androidx.compose.ui)
    implementation(libs.androidx.compose.ui.graphics)
    implementation(libs.androidx.compose.ui.tooling.preview)
    implementation(libs.androidx.compose.material3)
    testImplementation(libs.junit)
    androidTestImplementation(libs.androidx.junit)
    androidTestImplementation(libs.androidx.espresso.core)
    androidTestImplementation(platform(libs.androidx.compose.bom))
    androidTestImplementation(libs.androidx.compose.ui.test.junit4)
    debugImplementation(libs.androidx.compose.ui.tooling)
    debugImplementation(libs.androidx.compose.ui.test.manifest)
}

MainActivity加上测试代码:

运行:

这个是c++日志:

ok.

相关推荐
2601_963771379 小时前
Offloading WP-Cron and Securing Ticket Webhooks on Enterprise IT Sites
android
花燃柳卧10 小时前
跨平台路由组件工程源码补充上传
android·flutter·kotlin
apihz10 小时前
随机驾考题目(C 照科一 / 科四 2000+ 题)免费API调用教程
android·java·c语言·开发语言·网络协议·tcp/ip
宸翰11 小时前
uni-app 设置 Android 底部虚拟导航栏背景色
android·前端·uni-app
TechNomad11 小时前
Kotlin类对象与接口详解
android·kotlin
QiLinkOS16 小时前
QiLink OS的失败数据共享平台的运作模式是否适用于所有行业?
android·开发语言·人工智能·算法·重构·开源
杉氧16 小时前
Framework 补完计划 (2):BufferQueue 与 SurfaceFlinger —— 像素的跨进程“接力赛”
android·架构·android jetpack
牢七16 小时前
RCE?复现成功
android
一化十16 小时前
Android16 自定义全局手势 任意界面依次点击屏幕四个角返回Home界面
android
三少爷的鞋18 小时前
Android 面试系列:Kotlin 协程的 delay 到底发生在哪个线程?
android