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.

相关推荐
CocoaKier2 小时前
X未提前通知,突然停用twitter授权登录域名,大量X三方登录异常!
android·ios
0pen13 小时前
android-sqlite3:从官方 SQLite 源码自动构建 Android 可用的 sqlite3
android·数据库·sqlite
测试开发-学习笔记4 小时前
adb命令
android·adb
plainGeekDev4 小时前
Android四大组件面试题,看完这篇就够了
android·面试·kotlin
私人珍藏库4 小时前
【Android】Todesk手机远控手机、电脑,无会员无广告!!
android·学习·智能手机·app·工具·软件·多功能
JohnnyDeng944 小时前
Android 动画体系:属性动画与 Compose 动画对比
android
独隅4 小时前
MySQL主从延迟根因诊断法:全面详解指南
android·mysql·adb
私人珍藏库4 小时前
【Android】图片工具箱-免费开源图片处理软件
android·人工智能·app·工具·软件·多功能
以身入局4 小时前
android Binder 讲解
android