怎么记Android开发的函数,Android JNI开发详解(2)-函数注册

1. JNI开发流程创建Native C++工程,这部分可用参考Android JNI开发详解(2)-开发环境搭建-开发环境搭建.md)

创建Java层本地接口调用类,并定义好相应的本地函数。

将Java源代码编译成class字节码文件(Android studio会自动生成)。

创建对应的本地函数接口,并注册本地函数,Jni函数注册有两种方式,静态注册和动态注册,静态注册使用javah工具自动生成对应的本地接口函数定义,动态注册则需要在JNI_OnLoad函数中调用RegisterNatives来完成注册。

实现本地函数接口函数的具体功能实现。

修改CMakeLists.txt或Android.mk。

编译测试。

71722770d910adf6815ed5795f74fcec.png

2. JNI函数注册

2.1 JVM查找native方法有两种方式

JNI技术是Java世界与Native世界的通信桥梁,具体到代码,Java层的代码如何同Native层的代码进行调用的呢?我们都知道,在调用native方法之前,首先要调用System.loadLibrary接口加载一个实现了native方法的动态库才能正常访问,否则就会抛出java.lang.UnsatisfiedLinkError异常 。 那么,在Java中调用某个native方法时,JVM是通过什么方式,能正确的找到动态库中C/C++实现的那个native函数呢?

JVM查找native方法有两种方式:按照JNI规范的命名规则。

调用JNI提供的RegisterNatives函数,将本地函数注册到JVM中。

第一种方式,可用使用javah工具按照Java类中定义的native方法,按照JNI规范的命名规则的方式自动生成Jni本地C/C++头文件。第二种方式则需要在本地库的JNI_OnLoad函数中调用RegisterNatives来动态注册。

JNI函数注册是将Java层声明的Native方法同实际的Native函数绑定起来的实现方式,也就是说,只要通过JNI函数注册机制注册了本地方,Java层就可以直接调用定义的这些本地方法了。对应上述JVM查找native方法的两种方式,JNI函数注册方式一般分为静态注册和动态注册两种方式。

2.2 javah工具和javap工具

为了方便我们进行完成注册操作,我们经常还会用到javah和javap两个命令行工具。javah工具用于生产本地方法头文件

在JDK1.7中,在src目录(android studio工程在src/main/java目录)下执行javah 全类名

在JDK1.6中,在bin/classes目录下执行

执行前需要先编译通过(编译为class文件),大多数IDE会自动执行编译,因此不需要在手动进行编译javap工具用于打印方法签名

2.3 静态注册

静态注册实际十分简单,就是使用上面提到的javah工具为我们生产本地方法头文件,然后在根据生成的头文件完成相应的函数即可。静态注册即本地函数按照特定的命名规则命名本地方法,使得这些本地方法与Java类中定义的本地方法一一对应,在执行JNI调用时,只需要根据命名规则去调用so库中对应的方法即可。

下面时一个使用静态注册的例子,Test类定义了Java中的本地方法。package cc.ccbu.jnitest;

public class Test {

static {

System.loadLibrary("native-lib");

}

public native String textFromJni();

}

使用javah生成对应的本地方法头文件。#include

/* Header for class cc_ccbu_jnitest_Test */

#ifndef _Included_cc_ccbu_jnitest_Test

#define _Included_cc_ccbu_jnitest_Test

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class: cc_ccbu_jnitest_Test

* Method: textFromJni

* Signature: ()Ljava/lang/String;

*/

JNIEXPORT jstring JNICALL Java_cc_ccbu_jnitest_Test_textFromJni

(JNIEnv *, jobject);

#ifdef __cplusplus

}

#endif

我们只用在我们的.c或cpp文件实现Java_cc_ccbu_jnitest_Test_textFromJni方法即可。

2.4 动态注册

对应与上面的静态注册方法,还有一种动态注册JNI函数的方式,即动态注册。动态注册是当Java层调用System.loadLibrary方法加载so库后,本地库的JNI_OnLoad函数会被调用,在JNI_OnLoad函数中通过调用RegisterNatives函数来完成本地方法的注册。

本地so库加载和卸载时,会调用JNI_OnLoad和JNI_OnUnload函数,函数原型如下:JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved);

JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved);

动态注册本地方法的函数RegisterNatives原型如下:jint RegisterNatives(JNIEnv *env, jclass clazz, const JNINativeMethod *methods, jint nMethods);

其中JNINativeMethod结构体用来描述本地方法结构,其定义如下:typedef struct {

const char* name; // Java方法名

const char* signature; // Java方法签名

void* fnPtr; // jni本地方法对应的函数指针

} JNINativeMethod;

下面通过一个例子来展示jni动态注册本地方法的过程。还是以上面静态注册的Test类为例在Java文件中定义本地方法,加载本地so库package cc.ccbu.jnitest;

public class Test {

static {

System.loadLibrary("native-lib");

}

public native String textFromJni();

}在JNI_OnLoad函数中注册本地方法jstring textFromJni(JNIEnv* env, jobject thiz) {

return env->NewStringUTF("text from jni");

}

static JNINativeMethod gMethods[] = {

{"textFromJni", "()Ljava/lang/String;", (void*)textFromJni}

};

int registerMethod(JNIEnv *env) {

jclass test = env->FindClass("cc/ccbu/jnitest/Test");

return env->RegisterNatives(test, gMethods, sizeof(gMethods)/ sizeof(gMethods[0]));

}

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

JNIEnv* env = NULL;

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

return JNI_ERR;

}

if (registerMethod(env) != JNI_OK) {

return JNI_ERR;

}

return JNI_VERSION_1_6;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中,当Fragment需要调用JNI接口函数时,可以通过以下步骤实现: 1. 首先,在Java中创建一个JNI接口类并使用static类型,以便在不同的Fragment中简便地调用JNI函数。 2. 在JNI接口类中,定义所需的JNI函数,并使用native关键字标这些函数,表示它们将在C / C++中实现。 3. 在C / C++中,实现JNI函数的功能。可以使用CMakeLists文件来配置和构建通过JNI调用的C / C++代码。 4. 在Java中,通过调用JNI接口类的静态方法来调用JNI函数。根据具体的需求,可以传递参数给JNI函数,并将其结果返回到Java中。 5. 在Fragment中,根据需要处理JNI函数的返回结果,并进行相应的操作。例如,可以将返回的byte数组转换为String类型,并在界面上显示相应的数据。 通过以上步骤,Android Fragment可以成功调用JNI接口函数,并实现与C / C++代码的交互。这样可以在APP开发中使用JNI调用C / C的基本架构,并为开发者提供有益的参考借鉴。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [《“透视”个人大数据》项目开发 --(三)Android APP 开发(3)使用jni调用c++/c 应用实例浅析](https://blog.csdn.net/m0_69502339/article/details/127995223)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [自己平时做的android相关的总结](https://download.csdn.net/download/mars_cheng/8724303)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值