NDK开发之JNI开发流程

JNI(Java Native Interface)Java本地化接口,Java调用C/C++,C/C++调用Java的一套API接口

实现步骤

  • 在Java源文件中编写native方法

    1
    public native static String getStringFromC();
  • 到Java源代码src路径下,使用javah命令生成.h头文件
    注意:此处的参数为包名+类名

    1
    2
    //生成的头文件为:com_cj5785_jni_JniTest.h
    javah com.cj5785.jni.JniTest
  • 复制.h头文件到CPP工程中,修改文件包含

    1
    2
    //生成的C函数名:Java_完整类名_函数名
    #include "jni.h" //将#include <jni.h>修改
  • 复制jni.h和jni_md.h文件到CPP工程中
    jni.h和jni_md.h位于Java安装目录下

  • 实现.h头文件中声明的函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //为与头文件相匹配,此时将实现文件取名为:com_cj5785_jni_JniTest.c
    #include "com_cj5785_jni_JniTest.h"
    //函数实现
    JNIEXPORT jstring JNICALL Java_com_cj5785_jni_JniTest_getStringFromC
    (JNIEnv *env, jclass jcls)
    {
    //将C的字符串转换为Java的字符串
    return (*env)->NewStringUTF(env, "C String");
    }
  • 生成dll文件,供Java调用
    Debug -> 平台(x64) -> 确定
    项目(右键) -> 属性 -> 配置属性 -> 常规 -> 生成dll动态库

  • 将生成的dll文件放在Java的src目录同级下,加载动态库

    1
    2
    3
    static{
    System.loadLibrary("");
    }

整个java项目文件源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.cj5785.jni;

public class JniTest {

static {
System.loadLibrary("JNITest");
}

public native static String getStringFromC();

public static void main(String[] args) {

String str = getStringFromC();
System.out.println(str);

}
}

运行以后在控制台输出:C String
在生成的dll过程中,会生成在相应配置的目录下

JNI说明

JNIEnv与env

JNIEnv:结构体指针
env:二级指针
JNIEnv代表Java运行环境,调用Java中的代码

  • 在C中
    JNIEnv:结构体指针别名
    env:二级指针

  • 在C++中
    JNIEnv:一个结构体指针的别名
    env:一级指针

  • 为何需要传入JNIEnv?
    C函数执行过程中需要JNIEnv

  • C++为何没有传入?
    C++中有this指针,可以拿到当前指针,对C语言而言,要修改指针的值,只能通过二级指针
  • C++对C进行封装,给一个变量赋值为指针,这个变量就是二级指针
    1
    2
    3
    4
    5
    6
    7
    struct JNINativeInterface_;
    struct JNIEnv_;
    #ifdef __cplusplus
    typedef JNIEnv_ JNIEnv;
    #else
    typedef const struct JNINativeInterface_ *JNIEnv;
    #endif

jclass说明

jclass代表native方法所属类的class对象,这里代表了JniTest.class

C与C++的实现

在函数实现的时候是不一样的
c实现:

1
2
3
4
5
6
#include "com_cj5785_jni_JniTest.h"
JNIEXPORT jstring JNICALL Java_com_cj5785_jni_JniTest_getStringFromC
(JNIEnv *env, jclass jcls)
{
return (*env)->NewStringUTF(env, "C String");
}

C++实现

1
2
3
4
5
JNIEXPORT jstring JNICALL Java_com_cj5785_jni_JniTest_getStringFromC
(JNIEnv *env, jclass jcls)
{
return env->NewStringUTF("C String");
}

JNIEnv实现模拟

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//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");
}
Donate comment here