Android中JNI的使用方法
首先看一下Android平台的框架图:(网上盗用)
可以看到Android上层的Application和ApplicationFramework都是使用Java编写,
底层包括系统和使用众多的LIiraries都是C/C++编写的。
所以上层Java要调用底层的C/C++函数库必须通过Java的JNI来实现。
下面将学习Android是如何通过Jni来实现Java对C/C++函数的调用。以HelloWorld程序为例:
- 第一步:
使用Java编写HelloWorld 的Android应用程序:
public class HelloWorld extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.v("dufresne", printJNI("I am HelloWorld Activity"));
}
static
{
//加载库文件
System.loadLibrary("HelloWorldJni");
}
//声明原生函数 参数为String类型 返回类型为String
private native String printJNI(String inputStr);
}
这一步我们可以使用eclipse来生成一个App;
因为eclipse会自动为我们编译此Java文件,后面要是用到。
第二步:
生成共享库的头文件:
进入到eclipse生成的Android Project中 :/HelloWorld/bin/classes/com/lucyfyr/ 下:
可以看到里面后很多后缀为.class的文件,就是eclipse为我们自动编译好了的java文件,其中就有:
HelloWorld.class文件。
退回到classes一级目录:/HelloWorld/bin/classes/
执行如下命令:
javah com.lucyfyr.HelloWorld
生成文件:com_lucyfyr_HelloWorld.h
/* DO NOT EDIT THIS FILE - it is machine generated */
include
一个完整模块编译
include (CLEAR_VARS)
LOCAL_SRC_FILES:=com_lucyfyr_HelloWorld.c
LOCAL_C_INCLUDES :=(JNI_H_INCLUDE)
LOCAL_MODULE := libHelloWorldJni
LOCAL_SHARED_LIBRARIES := libutils
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_TAGS :=optional
include $(BUILD_SHARED_LIBRARY)
系统变量解析:
LOCAL_PATH - 编译时的目录
(call目录,目录….)目录引入操作符 如该目录下有个文件夹名称src,则可以这样写
(call src),那么就会得到 src 目录的完整路径
include (CLEAR_VARS) -清除之前的一些系统变量
LOCAL_MODULE - 编译生成的目标对象
LOCAL_SRC_FILES - 编译的源文件
LOCAL_C_INCLUDES - 需要包含的头文件目录
LOCAL_SHARED_LIBRARIES - 链接时需要的外部库
LOCAL_PRELINK_MODULE - 是否需要prelink处理
include(BUILD_SHARED_LIBRARY) - 指明要编译成动态库
android.mk编译模块添加具体方法参考:http://blog.csdn.net/yili_xie/article/details/4906865
编译此模块:输入编译命令
./makeMtk mm packages/apps/HelloWorld/jni/
上面是我的工程根目录编译命令。具体编译方式根据自己系统要求执行。
编译输出: libHelloWorldJni.so (system/lib中视具体而定)
此时库文件编译好了可以使用,如果在eclipse中模拟器上使用,需要将 libHelloWorldJni.so导入到system/lib 下,
或者对应app的data/data/com.lucyfyr/lib/下;
但是在导入system/lib 下的时候,却始终提示out of memory。于是网上说使用emulator去搞,
但是此命令使用起来却有问题,始终没有解决。但是可以导入到data/data/com.lucyfyr/lib/下使用。但是我这里直接在真机上弄的。
看一下HelloWorld中Android.mk文件的配置
其中存在:
include $(LOCAL_PATH)/jni/Android.mk 表示编译库文件
LOCAL_JNI_SHARED_LIBRARIES := libHelloWorldJni 表示app依赖库,打包的时候会一起打包。
第五步:
验证执行
将编译好的apk安装到手机上
使用adb push到手机上去需要自己去导入库文件libHelloWorldJni.so到data/data/com.lucyfyr/lib/
使用adb install方式安装则会自动导入。
启动HelloWorld :输入命令 adb logcat |grep dufresne
输出log如下:
I/HelloWorld(28500): dufresne Hello World From libhelloworld.so!
I/HelloWorld(28500): dufresne—>I am HelloWorld Activity
V/dufresne(28500): Hello World! I am Native interface
符合调用打印顺序正确。
以上通过一个简单的例子学习了Android如何编写编译C库文件,以及如何使用库文件。
对于JNI的使用其中还涉及到其他方面的一些知识:C++接口如何调用,函数名注册表怎么回事,
参数类型如何匹配,JNI如何调用Java中的方法java<—>JNI等。