利用JNI实现安卓的Java代码调用C语言API。

JNI是Java Native Interface的缩写,也就是Java本地接口的意思。Java为什么需要JNI这种呢?我们知道Java是一种平台无关性的语言,平台对于上层的java代码来说是透明的,在大部分的情况下是不需要JNI的,但是我们可能遇到如下一下情况:

1.java代码需要得到一个文件的属性,但是找不到相关的API;

2.在java代码中需要用到某种算法,但是这种算法时用C实现并封装在动态链接库文件中的。

如果没有JNI,上面的问题就会变得很棘手.举个例子说明:在Android中我们想要操作串口的时候会发现当前的Android SDK并没有提供任何写串口的API,对于底层的串口操作需要使用C来完成。而Android的应用程序是基于java实现的,应用程序想要访问到串口就需要JNI技术了。

接下来通过实际的例子来说明java如何通过JNI实现C\C++的函数调用

1.开发环境介绍:主机系统为64位Ubuntu 14.04, jdk版本jdk1.8.0_45。
2.程序清单1~/jni_test/com/magc/jni/HelloWorld.java
package com.magc.jni;

public class HelloWorld
{
    static
    {
        System.loadLibrary("Hello");
    }
    public native void DisplayHello();
    
    public static void main(String[] args)
    {
        new HelloWorld().DisplayHello();
    }
}
3.进如jni目录后,编译该java类,命令:

javac HelloWorld.java

执行后在该目录下生成 HelloWorld.class 文件

4.进入jni_test目录,使用javah命令生成头文件:

javah -jni com.magc.jni.HelloWorld

在当前目录下生成 com_magc_jni_HelloWrold.h 头文件

5.程序清单2 com_magc_jni_HelloWrold.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_magc_jni_HelloWorld */

#ifndef _Included_com_magc_jni_HelloWorld
#define _Included_com_magc_jni_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
    
/*
 * Class:     com_magc_jni_HelloWorld
 * Method:    DisplayHello
 * Signature: ()V
 */
    
JNIEXPORT void JNICALL Java_com_magc_jni_HelloWorld_DisplayHello
    (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

此头文件中的Java_com_magc_jni_HelloWorld_DisplayHello(JNIEnv *, jobject)方法,是将来与动态链接库交互的接口,并需要名字保持一致。

6.程序清单3 jni_HelloWroldlmpl.cpp

在jni_test目录下新建jni_HelloWroldlmpl.cpp源文件

#include <jni.h>
#include "com_magc_jni_HelloWorld.h"
#include "stdio.h"

JNIEXPORT void JNICALL Java_com_magc_jni_HelloWorld_DisplayHello
    (JNIEnv *, jobject)
{
    printf("From jni_helloworldImpl.cpp :");
    printf("Hello world !\n");
}

此C++文件实现了上述头文件中的函数,注意方法函数名要保持一致。

7.编译生成动态库libHello.so,命令:

g++ jni_helloworldImpl.cpp -o libHello.so

成功后,便会在当前目录下生成动态链接库libHello.so文件。

本人在执行这一步的过程中遇到了头文件”jni.h”和”jni_md.h”未找到的情况,这两个头文件路径伟jdk安装目录下include 及include/linux 使用”g++ -shared -I 头文件路径”解决.

8.有了具体实现的动态库后,就可以运行JAVA调用JNI程序类的native方法了。命令:

java -Djava.library.path=. com.magc.jni.HelloWorld

输入结果即为:From jni_helloworldImpl.cpp :Hello world !