Android NDK基础10:JNI开发流程_JNIEnv

JNI

JNI(Java Native Interface)
Java调用C/C++,C/C++调用Java的一套API

  • 1.编写native方法
  • 2.javah命令,生成.h头文件,生成的C/C++的函数声明名称:Java_完整类名_函数名
  • 3.复制.h头文件到C/C++工程中
  • 4.复制jni.h和jni_md.h文件到C/C++工程中
  • 5.实现.h头文件中声明的函数
  • 6.生成dll文件
  • 7.将dll文件放置在项目工程根目录下
  • 8.重启Eclipse
jni.h:C:\Program Files\Java\jdk1.8.0_112\include\jni.h
jni_md.h:C:\Program Files\Java\jdk1.8.0_112\include\win32\jni_md.h

cn.appblog.JniTest

public class JniTest {

    public native static String getStringFromC();

    public static void main(String[] args) {
        String text = getStringFromC();
        System.out.println(text);
    }

    //加载动态库
    static {
        System.loadLibrary("JniTest");
        //System.load("D:/NDK/JniTest/JniTest.dll");
    }

}

cn_appblog_jni_JniTest.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class cn_appblog_jni_JniTest */

#ifndef _Included_cn_appblog_jni_JniTest
#define _Included_cn_appblog_jni_JniTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     cn_appblog_jni_JniTest
 * Method:    getStringFromC
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_cn_appblog_jni_JniTest_getStringFromC
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

C实现:main.c

//生成DLL动态链接库:
//平台选择x64或x86
//项目属性->配置属性->常规->项目默认值->配置类型:动态库(.dll)
#include "cn_appblog_jni_JniTest.h"

//函数实现
JNIEXPORT jstring JNICALL Java_cn_appblog_jni_JniTest_getStringFromC
  (JNIEnv *env, jclass jcls) {
    //JNIEnv 结构体指针
    //env 二级指针
    //代表Java运行环境,调用Java中的代码

    //简单的实现
    //将C的字符串转为一个java字符串
    return (*env)->NewStringUTF(env, "C String");
}

C++实现:main.cpp

#include "cn_appblog_jni_JniTest.h"

JNIEXPORT jstring JNICALL Java_cn_appblog_jni_JniTest_getStringFromC
  (JNIEnv *env, jclass jcls) {
    //JNIEnv 在C++中就是一个结构体的别名
    //env 在C++中一个结构体的一级指针
    return env->NewStringUTF("C String");
}

动态库与静态库

  • 静态库:在编译的时候加载生成目标文件,在运行时不用加载库,在运行时对库没有依赖性。
  • 动态库:在目标文件运行时加载,手动加载,且对库有依赖性。

简单讲,静态库就是直接将需要的代码连接进可执行程序;动态库就是在需要调用其中的函数时,根据函数映射表找到该函数然后调入堆栈执行。

做成静态库可执行文件本身比较大,但不必附带动态库;做成动态库可执行文件本身比较小,但需要附带动态库

Windows中静态库是以 .lib 为后缀的文件,共享库是以 .dll 为后缀的文件。

在Linux中静态库是以 .a 为后缀的文件,共享库是以 .so为后缀的文件。

JNIEnv

在C中:JNIEnv 结构体指针别名,参数env是二级指针

在C++中:JNIEnv 是一个结构体的别名,参数env是一级指针

  • 1.为什么需要传入JNIEnv,函数执行过程中需要JNIEnv
  • 2.C++为什么没有传入?因为存在this对象直接调用
  • 3.C++只是对C的那一套进行的封装,给一个变量赋值为指针,这个变量是二级指针

C/C++中为什么有区别?

//JNIEnv结构体的指针别名
typedef struct JNINativeInterface_* JNIEnv;

//结构体
struct JNINativeInterface_ {
    char* (*NewStringUTF)(JNIEnv*, char*);
};

//函数实现
char* NewStringUTF(JNIEnv* env, char* str) {
    //在NewStringUTF执行过程,仍然需要JNIEnv
    return str;
}

void main() {
    //实例化结构体
    struct JNINativeInterface_ struct_env;
    struct_env.NewStringUTF = NewStringUTF;

    //结构体指针
    JNIEnv e = &struct_env;

    //结构体的二级指针
    JNIEnv *env = &e;

    //通过二级指针调用函数
    char* str = (*env)->NewStringUTF(env,"abc");
}

版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/02/25/android-ndk-basic-jni-development-process-jnienv/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
海报
Android NDK基础10:JNI开发流程_JNIEnv
JNI JNI(Java Native Interface) Java调用C/C++,C/C++调用Java的一套API 1.编写native方法 2.javah命令,生成.h头文件,生成的C/C++的函数声明名称:Java……
<<上一篇
下一篇>>
文章目录
关闭
目 录