之前是用静态注册方式,通过 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.