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.

相关推荐
Dovis(誓平步青云)1 天前
DevEco Studio 6.1.1 Windows 安装实录:从下载校验到首次启动
android·开发语言·数据库·人工智能·windows·harmonyos
Zender Han1 天前
Flutter 自适应(Adaptive)与响应式(Responsive)设计实践:官方推荐方案详解
android·flutter·ios
我命由我123451 天前
Android 开发问题:TopAppBar 和 topAppBarColors API is experimental...
android·java·java-ee·kotlin·android studio·android jetpack·android-studio
造火箭1 天前
Android UI自动化测试可行性评估SKILL
android·功能测试·ui
hunterandroid1 天前
[Android 从零到一] ViewPager2 与 Fragment 生命周期协同:从预加载到状态一致性
android·前端
mmsx1 天前
一个黑边 Bug 修了两版:自己算矩阵直接黑屏,借库重建只用了一行 setZoom
android·前端
枢影Kernel1 天前
Android CLI 与 Android Skills 最佳实践:把 AI Agent 接入可验证的 Android 开发流程
android
Kapaseker1 天前
没想到吧!Skill 也可以测试 — 小白都看得懂的 Skill 教程
android·人工智能·kotlin
我命由我123451 天前
Android 开发问题:使用 AndroidTreeView 时,自定义视图无法撑满父容器
android·java·java-ee·kotlin·android studio·android-studio·android runtime
没文化的阿浩1 天前
【MySQL】数据类型
android·mysql·adb