android动态注册ndk,Android JNI和NDK学习(三):动态注册

概述

当执行java的native方法时,虚拟机怎么知道要调用so中那个方法呢?这个就需要注册,通过注册把java的方法和so的方法绑定在一起,这样就可以找到对应的方法了,此篇文章仅作为笔记,以防以后忘记

有俩种注册的方式即 静态注册和动态注册

静态注册

我们之前自动生成的项目就是静态注册的,我们看下代码

extern "C" JNIEXPORT jstring JNICALL

Java_com_text_ndk1_MainActivity_stringFromJNI(

JNIEnv *env,

jobject /* this */) {

std::string hello = "Hello from C++";

return env->NewStringUTF(hello.c_str());

}

复制代码

当第一次调用调用java的native方法时,虚拟机会搜索对应的native函数,如果存在就会建立一个关联,以后再次调用,这部分操作就会由虚拟机完成

对应的规则

Java+包名+类名+方法名

其中用下划线进行分割,包名也用下划线进行分割

这样做会有点缺点:

名字太长

第一次调用需要搜索,影响效率

动态注册

需要我们手动建立联系,增加了代码量但提高效率

允许自己定义函数名字

加载动态库

java层通过System.loadLibrary()方法可以加载一个动态库,此时虚拟机就会调用jni库中的JNI_OnLoad()函数

jint JNI_OnLoad(JavaVM* vm, void* reserved);

复制代码

返回值代表,动态库需要的jni版本,如果虚拟机不能识别这个版本,那么就不可以加载这个动态库

目前的返回值有,JNI_VERSION_1_1, JNI_VERSION_1_2, JNI_VERSION_1_4, JNI_VERSION_1_6。

如果动态库没有提供 JNI_OnLoad()函数会默认使用JNI_VERSION_1_1版本,但是这个版本太老,很多新函数没有,最好返回版本

注册函数

JNI_OnLoad()函数经常用来做一些初始化操作,动态注册就是在这里进行的

动态注册通过_JNIEnv的RegisterNatives()函数来完成

函数原型为

jint RegisterNatives(JNIEnv *env, jclass clazz,

const JNINativeMethod *methods, jint nMethods);

复制代码第一个参数:JNIEnv *指针

第二个参数:代表一个java类

第三个参数:代表JNINativeMethod结构体数组,JNINativeMethod定义了java层函数和native层函数的映射关系

第四个参数:代表第三个参数methods数组的大小

返回值 0代表成功,负值代表失败

JNINativeMethod结构体

RegisterNatives函数最重要的就是JNINativeMethod结构体,我们看下这个结构体

typedef struct {

const char* name;

const char* signature;

void* fnPtr;

} JNINativeMethod;

复制代码name:代表java的native方法的名字

signature:表示方法的签名

fnPtr:是一个函数指针,指向jni层的一个函数,也就是java层和native层建立联系的函数

实践

现在我们有一个java类,里面有俩个native方法,下面我们来完成这俩个方法的动态注册

public class TextJni {

static {

System.loadLibrary("textjni_lib");

}

native int text(String message);

static native int static_text(String message);

}

复制代码

首先手动书写C的对应的方法

jint native_text(JNIEnv *env, jobject jobject1, jstring msg)

jint native_staic_text(JNIEnv *env, jobject jclass1, jstring meg)

复制代码

native_text对应java层的text方法,native_staic_text对应java层的static_text方法

那么是如何写出来的的呢?

native方法名,这个可以随便起

返回值和java中的对应,java中是int,jni就是jint

第一个参数是固定的是JNIEnv指针

第二个参数目前我理解为固定jobject

后面参数就是java的参数转化过来的

然后需要填充JNINativeMethod

static const JNINativeMethod nativeMethod[] = {

{"text", "(Ljava/lang/String;)I", (void *) native_text},

{"static_text", "(Ljava/lang/String;)I", (void *) native_staic_text}

};

复制代码

这个上面已经讲过了

然后开始注册

static int registNativeMethod(JNIEnv *env) {

int result = -1;

//找到native方法所在的class

jclass class_text = env->FindClass("com.taobao.alinnkit.ndk1.TextJni");

if (env->RegisterNatives(class_text, nativeMethod,

sizeof(nativeMethod) / sizeof(nativeMethod[0])) == JNI_OK) {

result = 0;

}

return result;

}

复制代码

这样就动态注册成功

看下完整代码

java代码

public class TextJni {

static {

System.loadLibrary("textjni_lib");

}

native int text(String message);

static native int static_text(String message);

}

复制代码

C代码

#include

#include

#include

jint native_text(JNIEnv *env, jobject jobject1, jstring msg) {

const char *p_msg = env->GetStringUTFChars(msg, JNI_FALSE);

__android_log_print(ANDROID_LOG_INFO, "mmm", "method = %s, msg = %s", __FUNCTION__, p_msg);

return 0;

}

jint native_staic_text(JNIEnv *env, jobject jclass1, jstring meg) {

const char *p_msg = env->GetStringUTFChars(meg, JNI_FALSE);

__android_log_print(ANDROID_LOG_INFO, "mmm", "method = %s, msg = %s", __FUNCTION__, p_msg);

return 0;

}

static const JNINativeMethod nativeMethod[] = {

{"text", "(Ljava/lang/String;)I", (void *) native_text},

{"static_text", "(Ljava/lang/String;)I", (void *) native_staic_text}

};

static int registNativeMethod(JNIEnv *env) {

int result = -1;

jclass class_text = env->FindClass("com.taobao.alinnkit.ndk1.TextJni");

if (env->RegisterNatives(class_text, nativeMethod,

sizeof(nativeMethod) / sizeof(nativeMethod[0])) == JNI_OK) {

result = 0;

}

return result;

}

jint JNI_OnLoad(JavaVM *vm, void *reserved) {

JNIEnv *env = NULL;

int result = -1;

if (vm->GetEnv((void **) &env, JNI_VERSION_1_1) == JNI_OK) {

if (registNativeMethod(env) == JNI_OK) {

result = JNI_VERSION_1_6;

}

return result;

}

}

复制代码

调用

public class MainActivity extends AppCompatActivity {

// Used to load the 'native-lib' library on application startup.

static {

System.loadLibrary("native-lib");

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

TextJni.static_text("我是静态方法,哈哈");

new TextJni().text("我是普通方法,哈哈");

}

}

复制代码

看下打印信息

mmm: method = native_staic_text, msg = 我是静态方法,哈哈

mmm: method = native_text, msg = 我是普通方法,哈哈

复制代码

参考

juejin.im/post/5d1f16…

blog.csdn.net/afei__/arti…

www.jianshu.com/p/b71aeb4ed…

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[Android JNI和NDK学习(三):动态注册]http://www.zyiz.net/tech/detail-138406.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值