andriod的SDK
中没有包括
JNI
的支持,而且对如何支持
JNI
也没有任何文档说明。不过既然整个android平台
是开源的,我们可以通过
Google
发布的源代码来找到一些线索(比如
frameworks/base/media/jni/
目录),依葫芦画瓢的实现上层
JAVA
程序通过
JNI
来调用
Native C
程序中的函数。
依照下面的步骤可以实现一个非常简单的
JNI
的实例程序:
1.
首先编写
C
模块,实现动态库。(关于如何在
Android
中编译
C
模块的更多细节,请参考《Android编译Native C 模块
》。)
在
development
目录下添加新目录
hellolib
,并添加
hellolib.c
和
Android.mk
文件。
hellolib.c
的内容如下:
#define LOG_TAG "TestLib"
#undef LOG
#include <utils/Log.h>
JNIEXPORT void JNICALL Java_com_test_TestHelloLib_printHello(JNIEnv * env, jobject jobj)
{
LOGD("Hello LIB!/n");
}
注意这里的函数名需要按照
JNI
的规范(因此也可以用
javah -jni
工具来生成头文件,来保证函数名的正确性).
Java_com_test_TestHelloLib_printHello
的命名对应后面在
java
代码中,
package
名字是
com.test
,类名是
TestHelloLib
,
native
函数名是
printHello
。
另外,
LOGD
及
#define LOG_TAG "TestLib"
等打印
log
的方式是采用了
Android
所提供的
LOG
机制,这样才能通过
Android
的
logcat
工具看到
log
。
用于编译
C
模块的
Android.mk
文件内容如下:
LOCAL_SRC_FILES:= /
hellolib.c
LOCAL_C_INCLUDES := /
$(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES := /
libutils
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := libhello
include $(BUILD_SHARED_LIBRARY)
该文件中的一些变量分别对应的含义如下:
LOCAL_SRC_FILES
-
编译的源文件
LOCAL_C_INCLUDES
-
需要包含的头文件目录
LOCAL_SHARED_LIBRARIES
-
链接时需要的外部库
LOCAL_PRELINK_MODULE
-
是否需要
prelink
处理(参考
prelink
的详细介绍:《
动态库优化
——Prelink(预连接)技术
》,
Android
的
Toolchain, prelink
工具:《
Android Toolchain与
Bionic Libc
》
)
LOCAL_MODULE
-
编译的目标对象
BUILD_SHARED_LIBRARY
-
指明要编译成动态库。
接下来回到
Android
顶层目录,并执行
make libhello
来编译:
编译结果可得到位于
out/target/product/generic/system/lib/
目录的动态共享库
libhello.so
2
.编写
Java
模块,来通过
JNI
方式调用
C
接口。具体
Eclipse
环境的搭建请参考
Android SDK
文档中的详细说明,及
Hello Android
程序的创建过程,这里仅给出我们需要修改的
TestHelloLib.java
文件:
import android.app.Activity;
import android.os.Bundle;
public class TestHelloLib extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
printHello();
}
static {
System.loadLibrary("hello");
}
private native void printHello();
}
注意上面代码部分:
private native void printHello()
用来声明一个
native
接口;
static {
System.loadLibrary("hello");
}
用来加载上面步骤中生成
libhello.so
(注意
loadLibrary
方法的参数不是
”libhello.so”
,而是去掉前缀和后缀之后的
”hello”
),
onCreate()
方法中则调用了
printHello()
接口。
通过这一步骤可生成
Android
开发者所熟悉的
apk
文件:
TestHelloLib.apk
。
3
.集成测试
TestHelloLib.apk
和
libhello.so
。先运行
emulator
并将
TestHelloLib.apk
和
libhello.so
上传至
emulator
中。注意要将
libhello.so
上传到
emulator
的
/system/lib
目录,由于该目录是只读的,上传之前先要执行
adb remount
:
接下来在模拟器菜单中可以看到已经安装的
TestHelloLib
程序,运行即可。
由于
JNI
接口
printHello()
并没有作界面上的改动,要验证其效果需要用
Android
的
logcat
工具来查看。运行
”adb logcat”
可以找到下面的
log
片断:
这里包含了调用
printHello()
接口的
log
信息,其中
”
D/TestLib ( 174): Hello LIB!”
就是
printHello()
所打印的信息。至此成功完成
Android JNI
的实例验证。