NDK开发 从入门到放弃(二:动态注册JNI、多JNI调用)
来源:互联网 发布:知乎 霍顿 孙杨 编辑:程序博客网 时间:2024/05/24 02:27
一、前言
上一篇我们讲了NDK开发的最简单的一个入门流程,且写了一个实例。实例中java的native方法与C/C++代码函数是通过Java_<包名>_<类名>_<方法名>这种方式对应的,称为静态注册。在上一篇的例子中,我们是通过javah -jni命令来自动生成.h头文件的,自动帮我们写好了方法名,所以虽然函数名很长(手写的话容易写错),但是自动生产然后copy到C++类中,倒也没什么麻烦的。但是若是我们需要调用之前就早已写好的C++代码,方法名肯定就不满足静态注册的规则了,就需要用到动态注册JNI的方法了。这篇文章将介绍动态注册JNI的方式以及同时多个JNI时的处理方式(这里一个静态注册,一个动态注册),NDK开发流程以及静态注册请查看文章:NDK开发 从入门到放弃(一、基本流程入门了解)
二、实例
同样,我们先写一个本地方法的Java类。
public class JNIDynamicUtils { /** * 调用C++代码的方法,返回对应的字符串 * @return */ public static native String getHelloStringFromJNI(); /** * 加载so库或jni库 */ static { System.loadLibrary("JNI_DYNAMIC_ANDROID_TEST"); }}
在静态注册的时候,我们会对该类做javah -jni
操作,生产对应的.h的头文件,在cpp文件中使用头文件中自动给我们生成好的C++方法名,因为此处我们要使用动态注册的方式,则不需要做这个操作了。我们直接在jni目录下新建jnidynamicutils.cpp
文件,假设我们已经有了一个C++代码的native_hello
函数,该函数返回一个字符串(Java与C++之间的类型对应与字符串操作将在下一节讲解),我们现在希望当我们调用JNIDynamicUtils
的getHelloStringFromJNI
方法时调用这个native_hello
函数,则需要在JNI_OnLoad
方法内进行动态注册绑定,相关注释见代码。
#include <stdio.h>#include <jni.h>#include <stdlib.h>//C++层 native函数jstring native_hello(JNIEnv *env, jclass clz) { return env->NewStringUTF("Hello java, this is C++. ---jni");}/** * JNINativeMethod由三部分组成,可添加多组对应: * (1)Java中的函数名; * (2)函数签名,格式为(输入参数类型)返回值类型; * ()Ljava/lang/String; ()表示无参,Ljava/lang/String;表示返回String,在对象类名(包括包名,‘/’间隔)前面加L,分号结尾 * (3)native函数名 */static JNINativeMethod gMethods[] = { { "getHelloStringFromJNI", "()Ljava/lang/String;", (void *) native_hello } };//System.loadLibrary过程中会自动调用JNI_OnLoad,在此进行动态注册JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { JNIEnv *env = NULL; jint result = JNI_FALSE; //获取env指针 if (jvm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK) { return result; } if (env == NULL) { return result; } //获取类引用,写类的全路径(包名+类名)。FindClass等JNI函数将在后面讲解 jclass clazz = env->FindClass("***/***/JNIDynamicUtils"); if (clazz == NULL) { return result; } //注册方法 if (env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) < 0) { return result; } //成功 result = JNI_VERSION_1_6; return result;}
这里给出另一静态注册的相关代码,但不再解释(JNIStaticUtils.java 文件与 jnistaticutils.cpp文件,jnistaticutils.h文件就不给出了,只是申明了一个函数名而已)。
public class JNIStaticUtils { /** * 调用C++代码的方法,返回对应的字符串 * @return */ public static native String getStringFromJNI(); /** * 加载so库或jni库 */ static { System.loadLibrary("JNI_STATIC_ANDROID_TEST"); }}
#include <stdio.h>#include <jni.h>#include <stdlib.h>#include "jnistaticutils.h"JNIEXPORT jstring JNICALL Java_<包名>_JNIStaticUtils_getStringFromJNI(JNIEnv *env, jclass clazz) { return env->NewStringUTF("this is string from jni.");}
同上篇文章讲过的,需要Android.mk和Application.mk文件,Android.mk的代码如下:
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := JNI_STATIC_ANDROID_TESTLOCAL_SRC_FILES =: jnistaticutils.cppinclude $(BUILD_SHARED_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := JNI_DYNAMIC_ANDROID_TESTLOCAL_SRC_FILES =: jnidynamicutils.cppinclude $(BUILD_SHARED_LIBRARY)
然后我们在jni目录下可以任意选择一个文件右键来执行ndk-build操作,在main/libs目录下生成了libJNI_DYNAMIC_ANDROID_TEST.so文件与libJNI_STATIC_ANDROID_TEST.so文件,我们复制去jniLibs目录下。
我们在Activity中分别调用测试(点击对应的按钮,分别执行不同的操作,将C++返回的字符串在界面上累加显示出来,代码简单,就不贴了):
- NDK开发 从入门到放弃(二:动态注册JNI、多JNI调用)
- NDK开发 从入门到放弃(五:JNI抛异常)
- NDK开发 从入门到放弃(四:JNI函数、C与C++调用函数的区别)
- 二---JNI入门 - NDK从入门到精通(2)
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- Android 开发 之 JNI入门 - NDK从入门到精通
- effective c++ 读书笔记
- easyui-datagrid 使用大杂烩
- java中静态代码块的用法 static用法详解
- 深圳绘制SVG地图数据
- Linux中的Xargs命令,支持|管道传递参数
- NDK开发 从入门到放弃(二:动态注册JNI、多JNI调用)
- 笔记1.0
- android个人笔记之leakcanary初始化
- Json字符串和Json对象
- static用法
- 使用java中replaceAll方法替换字符串中的反斜杠
- java数组
- JAVA设置HttpOnly Cookies
- java二叉树