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全栈技术分享
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论