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
1
2
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//生成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

1
2
3
4
5
6
7
8
#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++中为什么有区别?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//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");
}

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2020 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :