Solarex's Blog

我只想过,平平淡淡的生活,欲望啊,请放过脆弱的我

在Mac下进行JNI开发

| Comments

本文主要讲述如何在Mac开发环境下进行JNI开发。

首先编写好Java文件,示例程序主要示范了Java访问C,C访问Java静态与非静态域。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class HelloJni{
    static{
        System.loadLibrary("HelloJni");
    }
    public native static String getStringFromCStatic();
    public native String getStringFromCNonStatic();
    public String key = "key";
    public static int count = 5;
    public native String accessField();
    public native void accessStaticField();
    public static void main(String[] args){
        System.out.println(getStringFromCStatic());
        HelloJni hello = new HelloJni();
        System.out.println(hello.getStringFromCNonStatic());
        System.out.println("change before key: " + hello.key);
        hello.accessField();
        System.out.println("change after key: " + hello.key);
        System.out.println("change before count: " + count);
        hello.accessStaticField();
        System.out.println("change after count: " + count);
    }
}

在这个类的static代码块中加载的动态库是HelloJni,类库的名字前面需要加lib,在linux系统上面类库的扩展名为so,在Mac系统上面扩展名为jnilib,也就是说我们待会要生成的库的名字是libHelloJni.jnilib

执行javac HelloJni.java生成class文件,执行javah HelloJni生成HelloJni.h头文件。其实生成的头文件都是有套路的,我们其实可以自己手动写。

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloJni */

#ifndef _Included_HelloJni
#define _Included_HelloJni
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloJni
 * Method:    getStringFromCStatic
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_HelloJni_getStringFromCStatic
  (JNIEnv *, jclass);

/*
 * Class:     HelloJni
 * Method:    getStringFromCNonStatic
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_HelloJni_getStringFromCNonStatic
  (JNIEnv *, jobject);

/*
 * Class:     HelloJni
 * Method:    accessField
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_HelloJni_accessField
  (JNIEnv *, jobject);

/*
 * Class:     HelloJni
 * Method:    accessStaticField
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloJni_accessStaticField
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

接下来进行c文件的编写,示例程序演示了C访问java静态与非静态域。

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
29
30
31
32
#include "HelloJni.h"
#include <stdio.h>
#include <string.h>

JNIEXPORT jstring JNICALL Java_HelloJni_getStringFromCStatic(JNIEnv * env, jclass clz){
    return (*env)->NewStringUTF(env, "C String static");
}

JNIEXPORT jstring JNICALL Java_HelloJni_getStringFromCNonStatic(JNIEnv * env, jobject obj){
    return (*env)->NewStringUTF(env, "C string non static");
}

JNIEXPORT jstring JNICALL Java_HelloJni_accessField(JNIEnv * env, jobject obj){
    jclass jclz = (*env)->GetObjectClass(env, obj);
    jfieldID fid = (*env)->GetFieldID(env, jclz, "key", "Ljava/lang/String;");
    jstring jstr = (*env)->GetObjectField(env, obj, fid);
    char* c_str = (*env)->GetStringUTFChars(env, jstr, NULL);
    char text[30] = "solarex";
    strcat(text, c_str);
    jstring new_str = (*env)->NewStringUTF(env, text);
    (*env)->SetObjectField(env, obj, fid, new_str);
    (*env)->ReleaseStringChars(env, new_str, c_str);
    return new_str;
}

JNIEXPORT void JNICALL Java_HelloJni_accessStaticField(JNIEnv * env, jobject obj){
    jclass jclz = (*env)->GetObjectClass(env, obj);
    jfieldID fid = (*env)->GetStaticFieldID(env, jclz, "count", "I");
    jint count = (*env)->GetStaticIntField(env, jclz, fid);
    count++;
    (*env)->SetStaticIntField(env, jclz, fid, count);
}

接下来就是编译c文件了,在HelloJni.h中有#include <jni.h>,编译的时候我们需要指出jni.h的路径。在Mac系统中jni.h/System/Library/Frameworks/JavaVM.framework/Headers目录下。

1
2
gcc -I/System/Library/Frameworks/JavaVM.framework/Headers -c HelloJni.c //生成.o文件
gcc -dynamiclib -o libHelloJni.jnilib HelloJni.o

上面两条命令就生成了动态库。

然后我们再执行java HelloJni就可以看到java和c交互的输出了:

1
2
3
4
5
6
C String static
C string non static
change before key: key
change after key: solarexkey
change before count: 5
change after count: 6

Demo参见HelloJni

Comments