NDK中动态注册JNI方法
更新日期 2022-6-21
- 2022-6-21 更新例子
- 2016-8-20 创建文档
Java中定义了native方法后,在C/C++中使用JNI_OnLoad
函数来注册相应的方法。
一般做法如下:
- Java中定义native方法,确定Java文件的包名和路径
- 编写C/C++文件
- 实现相应的jni方法
- 根据Java文件路径和方法签名确定
JNINativeMethod
- 实现
JNIEXPORT int JNICALL JNI_OnLoad(JavaVM *vm,void *reserved)
方法
- 编译生成so文件
- Java中加载so库文件
- Java中调用native方法
相比于之前的静态注册,这里没有用javah
生成头文件。
关于查询Java方法签名
关于查询Java方法签名,可以使用javap -s
命令查询相应的class文件。
例如查看DynamicJNI.java
的方法签名,先编译出DynamicJNI.class
文件,再查询。
$ javap -s ./build/intermediates/classes/debug/com/rustfisher/appndkground/jni/DynamicJNI.class
Compiled from "DynamicJNI.java"
public class com.rustfisher.appndkground.jni.DynamicJNI {
public com.rustfisher.appndkground.jni.DynamicJNI();
descriptor: ()V
public static native java.lang.String getHello();
descriptor: ()Ljava/lang/String;
public static native int meaningOfTheUniverse();
descriptor: ()I
static {};
descriptor: ()V
}
查询得知getHello()
的方法签名为()Ljava/lang/String
;
meaningOfTheUniverse()
方法签名为()I
;
如果方法签名错了,编译能通过,但运行时会报NoSuchMethod异常
动态注册native方法示例1
主要文件:
dynamic_jni.cpp
方法实现文件
DynamicJNI.java
jni接口
DynamicJNI.java
中定义native方法。ndkground
是模块名称。
public class DynamicJNI {
static {
System.loadLibrary("ndkground");
}
public static native String getHello();
public static native int meaningOfTheUniverse();
}
文件路径是"com/rustfisher/appndkground/jni/DynamicJNI"
,这个路径确定后一般不再改动。
dynamic_jni.cpp
实现相关的方法
| #include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <jni.h>
#define JNI_REG_CLASS "com/rustfisher/appndkground/jni/DynamicJNI" // path of Java file
JNIEXPORT jstring JNICALL get_hello(JNIEnv *env, jclass clazz) {
return env->NewStringUTF("hello from jni");
}
JNIEXPORT jint JNICALL meaning_of_the_universe(JNIEnv *env, jclass clazz) {
return 42;
}
static JNINativeMethod g_methods[] = {
{ "getHello", "()Ljava/lang/String;", (void*)get_hello},
{ "meaningOfTheUniverse", "()I", (void*)meaning_of_the_universe},
};
// must define this function
JNIEXPORT int JNICALL JNI_OnLoad(JavaVM *vm,void *reserved) {
JNIEnv *env;
if (vm->GetEnv((void **) &env,JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR;
}
jclass javaClass = env->FindClass(JNI_REG_CLASS);
if (javaClass == NULL){
return JNI_ERR;
}
int method_count = sizeof(g_methods) / sizeof(g_methods[0]);
if (env->RegisterNatives(javaClass, g_methods, method_count) < 0) {
return JNI_ERR;
}
return JNI_VERSION_1_6;
}
|
这里使用Cygwin执行ndk-build
来编译生成so文件。
调用动态注册的jni方法 DynamicJNI.getHello()
相应代码参见 https://github.com/RustFisher/android-Basic4/tree/master/appNdkGround
动态注册native方法示例2
这是一个修改老版本webrtc代码的例子。在原来的基础上增加动态注册的native方法。
头文件加入方法声明
.h头文件 |
---|
| static void JNICALL VerticeToNegStatic(JNIEnv * env,jobject,jlong context);
void VerticeToNeg();
static void JNICALL VerticeToPosStatic(JNIEnv * env,jobject,jlong context);
void VerticeToPos();
|
cpp代码中注册,先找到Java的类_javaRenderClass
;然后调用注册的方法env->RegisterNatives
.cc文件 动态注册部分 |
---|
| // get the ViEAndroidGLES20 class
jclass javaRenderClassLocal =
env->FindClass("org/webrtc/videoengine/ViEAndroidGLES20");
if (!javaRenderClassLocal) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
"%s: could not find ViEAndroidGLES20", __FUNCTION__);
return -1;
}
// create a global reference to the class (to tell JNI that
// we are referencing it after this function has returned)
_javaRenderClass =
reinterpret_cast<jclass> (env->NewGlobalRef(javaRenderClassLocal));
if (!_javaRenderClass) {
WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,
"%s: could not create Java SurfaceHolder class reference",
__FUNCTION__);
return -1;
}
// Delete local class ref, we only use the global ref
env->DeleteLocalRef(javaRenderClassLocal);
// ....
JNINativeMethod nativeFunctions[5] = {
{ "DrawNative",
"(J)V",
(void*) &AndroidNativeOpenGl2Channel::DrawNativeStatic, },
{ "CreateOpenGLNative",
"(JII)I",
(void*) &AndroidNativeOpenGl2Channel::CreateOpenGLNativeStatic },
{ "ChangeMirrorXNative",
"(J)V",
(void*) &AndroidNativeOpenGl2Channel::ChangeMirrorXNativeStatic },
{ "VerticeToNegNative",
"(J)V",
(void*) &AndroidNativeOpenGl2Channel::VerticeToNegStatic },
{ "VerticeToPosNative",
"(J)V",
(void*) &AndroidNativeOpenGl2Channel::VerticeToPosStatic },
};
if (env->RegisterNatives(javaRenderClass, nativeFunctions, sizeof(nativeFunctions) / sizeof(nativeFunctions[0])) == 0) {
// 注册成功
} else {
// 报警告..
}
|
.cc文件调用代码 |
---|
| void JNICALL AndroidNativeOpenGl2Channel::VerticeToNegStatic(
JNIEnv * env, jobject, jlong context) {
// 业务逻辑
}
void AndroidNativeOpenGl2Channel::VerticeToNeg() {
// 业务逻辑
}
void JNICALL AndroidNativeOpenGl2Channel::VerticeToPosStatic(
JNIEnv * env, jobject, jlong context) {
// 业务逻辑
}
void AndroidNativeOpenGl2Channel::VerticeToPos() {
// 业务逻辑
}
|
Java代码中对应的方法
Java里的native方法 |
---|
| private native int CreateOpenGLNative(long nativeObject,
int width, int height);
private native void DrawNative(long nativeObject);
private native void ChangeMirrorXNative(long nativeObject);
private native void VerticeToNegNative(long nativeObject);
private native void VerticeToPosNative(long nativeObject);
|
本文也发布在
简书
本站说明
一起在知识的海洋里呛水吧。广告内容与本站无关。如果喜欢本站内容,欢迎投喂作者,谢谢支持服务器。如有疑问和建议,欢迎在下方评论~
📖AndroidTutorial
📚AndroidTutorial
🙋反馈问题
🔥最近更新
🍪投喂作者
Ads