Java 程序可以通过 JNI(Java Native Interface,Java 本地调用)访问本地的动态链接库,从而扩展其功能、保护关键代码、提高运行效率。可以通过NDK工具生成so库
1. 什么情况下需要使用 JNI Java 本机接口(Java Native Interface (JNI))是一个本机编程接口,它是 Java 软件开发工具箱(Java SoftwareDevelopment Kit (SDK))的一部分,JNI 它提供了若干的 API,实现了和 Java 和其他语言的通信(主要是 C&C++)。 JNI 允许 Java 代码使用以其它语言(譬如 C 和 C++)编写的代码和代码库。注意本使用都是 C 的代码和库。 Invocation API(JNI 的一部分)可以用来将 Java 虚拟机(JVM)嵌入到本机应用程序中,从而允许程序员从本机代码内部调用 Java 代码。 我们知道 Java 是一种平台无关性的语言,平台对于上层的 java 代码来说是透明的,所以在 Android 上层应用中,大部分情况是不需要 JNI 的。但是在嵌入式 Android 开发中,以下两种情况肯定需要用到 JNI。 第一种情况,用户需要直接调用开发板底层中的驱动实现特定功能,那么怎么实现?因为底层 Kernel 中都是用 C 编写的。Java 是没有办法直接调用底层的,那么这种情况下就需要用到 JNI。 第二种情况,用户有现成的应用,但是都是基于 C 写的,那么想要尽快的完成任务,那么就需要用到 JNI。将 C 的程序移植到 JNI 中,然后制作好 API 接口,供上层 Java 的应用程序调用。jni.h→com.topeet.ledtest.h
jni.c→com.topeet.ledtest.c
lib.so→libled.so
Android.mk→Android.mk
源码还需要编译成 lib.so 库才能使用,编译成库就涉及到 Makefile 文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := led
LOCAL_SRC_FILES := com_topeet_ledtest_led.c
LOCAL_LDLIBS += -llog
LOCAL_LDLIBS +=-lm
include $(BUILD_SHARED_LIBRARY)
解析一下这几行代码
1、LOCAL_PATH := $(call my-dir)
一个 Android.mk file 首先必须定义好 LOCAL_PATH 变量。它用于查找源文件。在这个例子中,宏函数‘my-dir’,由编译系统提供,用于返回当前路径(即包含 Android.mk file文件的目录)。
2、include $(CLEAR_VARS)
CLEAR_VARS 由编译系统提供((可以在 android 安装目录下的/build/core/config.mk文件看到其定义,为 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk)),指定让 GNUMAKEFILE 为你清除许多 OCAL_XXX 变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES,LOCAL_STATIC_LIBRARIES, 等等…),除 OCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个 GNU MAKE 执行环境中,所有的变量都是全局的。
3、LOCAL_MODULE := led
LOCAL_MODULE 变量必须定义,以标识你在 Android.mk 文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。注意编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为’led’的共享库模块,将会生成“libled.so”文件(也可以直接使用 libled 命名好)。
4、LOCAL_SRC_FILES := com_topeet_ledtest_led.c
LOCAL_SRC_FILES 变量必须包含将要编译打包进模块中的 C 或 C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。
5、LOCAL_LDLIBS += -llog
6、LOCAL_LDLIBS +=-lm
编译模块时要使用的附加的链接器选项。使用“-l”前缀传递指定库的名字是有用的。
LOCAL_LDLIBS := -llog 表示告诉链接器生成的模块要在加载时刻链接到“/system/lib/liblog.so”
可查看 docs/STABLE-APIS.TXT 获取使用 NDK 发行版能链接到的开放的系统库列表。
这里表示生成的是动态库。
7、include $(BUILD_SHARED_LIBRARY)
会生成依赖关系,当库不存在时会去编译这个库。
这里主要介绍的是基于 C 的 Makefile 文件的编写,如果用户使用的是 C++代码,Makefile 文件中的变量以及宏定义就会有所不同
如何生成基于 Linux 的 libxx.so 库。如下图所示,最后用户需要放在“libs/armeabi”中的库文件。