转载

JNI使用进阶

Java 原生接口 (JNI):JNI 是 Java 和 C++ 组件用以互相通信的接口。

理解JNI

先说说JNIEnv

现在说的是C里的JNIEnv,不是C++里的JNIEnv,有点区别,但是理解了C里的JNIEnv,就理解了C++里的JNIEnv

# include "jni_study_com_jnibsetpractice_Jni.h"

JNIEXPORT jstring JNICALL Java_jni_study_com_jnibsetpractice_Jni_sayHello
        (JNIEnv *env, jobject instance) {
    return (*env)->NewStringUTF(env, "Hello from C");
}
复制代码

上面的代码里第一个参数是JNIEnv,这是个什么东西,顾名思义jni环境,点进去跳到了

JNI使用进阶

这个文件里

JNI使用进阶

发现 JNIEnv是JNINativeInterface*的别名,JNINativeInterface是什么,发现他是一个结构体,里面列出了许多方法指针,相当于java里的一个类,类里定义了很多方法,这些方法在jni开发中非常重要

JNI使用进阶

看看这个方法是不是很眼熟,NewStringUTF

JNI使用进阶
(*env)->NewStringUTF(env, "Hello from C");

调用了这个方法,制造了一个字符串返给了java,你会问不就是一个字符串吗,我直接"Hello from C"返回不就行了吗?不行的,你知道C里是没有过String类型的,C里的"xxx",java并不认识,这就需要jni (java native interface),即【java 与本地语言(C/C++)接口】来解决这个问题

看看这个方法,传入一个*env和char *,char*就是C里的字符串类型,返回了jstring(jstring是java里的String的等价物),这样就把C里的字符串转换成java可以是别的字符串,你说这个方法重要吗,他是结构体JNINativeInterface提供的。

除了这个方法,其他很多方法都很重要,他的作用基本上就是一些jni开发中,常用到的一些方法,为我们在C和Java之间搭建了一座桥梁,让彼此互相沟通

下图是JNINativeInterface结构体的一个图示

JNI使用进阶

JNINativeInterface里所有方法的说明看这里:官方文档

所有方法分为以下几类

JNI使用进阶

看看NewStringUTF的文档

JNI使用进阶

以后会用到很多方法,都可以在这里查询

JNI里的数据类型

在上面的方法里,看到了很多奇奇怪怪的数据类型 jboolean jstring...,他们与java、c是如何对应的

我们在jin.h里还发现了这段代码

JNI使用进阶
JNI使用进阶

查看数据类型的官方文档 文档截图:

JNI使用进阶

参考类型 JNI包含许多与不同类型的Java对象相对应的引用类型。JNI引用类型按层次结构组织,如图3-1所示。

JNI使用进阶

JNIENV在C与C++的区别

我直接复制了上篇博客的内容

  1. 创建实现头文件的.cpp源文件 接下来要写个c++代码,实现这个jni接口

˙注意这里新建的是c++代码,c++代码对应下面的代码

//引入刚才生成的头文件
#include "ndkold_study_com_ndkolddemo_Java2CJNI.h"

//复制头文件里的要实现的方法名及其参数
JNIEXPORT jstring JNICALL
Java_ndkold_study_com_ndkolddemo_Java2CJNI_java2C(JNIEnv *env, jobject instance) {
//    实现这个方法,返回一个字符串
    return env->NewStringUTF("Hello from C++");
}
复制代码
  1. 你也可以写个.c源文件,其对应代码为
//引入刚才生成的头文件
#include "ndkold_study_com_ndkolddemo_Java2CJNI.h"

//复制头文件里的要实现的方法名及其参数
JNIEXPORT jstring JNICALL
Java_ndkold_study_com_ndkolddemo_Java2CJNI_java2C(JNIEnv *env, jobject instance) {
//    实现这个方法,返回一个字符串
    return (*env)->NewStringUTF(env, "Hello from C");
    //注意这里是(*env),而且需要传递一个参数(env)
}
复制代码

说明:c与c++就这点区别,查看jni.h文件,发现在c里的JNIEnv是结构体指针JNINativeInterface*的别名,所以JNIEnv *env相当于二级指针,现在要调用JNINativeInterface*里的方法,要用(*env)->xxx

在c++里JNIEnv是_JNIEnv的别名,在_JNIEnv内部里有个属性为结构体指针JNINativeInterface*,然后他把所有c里的方法都重新定义了一下,定义方式就是通过JNINativeInterface*调了一遍所有c里的方法,而且把JNINativeInterface*的对象以this方式传递进去了,可见这里的JNIEnv *env是一个一级指针,所以通过env就可以直接调用对应的方法了(有点绕)

JNI使用进阶
JNI使用进阶
JNI使用进阶

Android.mk文件

Android.mk是Android提供的一种makefile文件,用来指定诸如编译生成so库名、引用的头文件目录、需要编译的.c/.cpp文件和.a静态库文件等。要掌握jni,就必须熟练掌握Android.mk的语法规范。

参考自Android.mk用法详解

JNI使用进阶

这个文件rebuild后 androidstudio会自动生成,看我的上篇博客可以找到他的生成的路径,有小坑请注意

原文  https://juejin.im/post/5d03032cf265da1bc4144ebf
正文到此结束
Loading...