Jni(java nativeinterface)是java与本地c/c++相互调用的一种方式,称之为java本地调用,由于java是夸平台的,所以在windows与linux以及其他不同的平台,即使是相同的jni函数,他们调用底层c/c++接口也存在差异,但是他们都是先将c/c++代码变成具体平台的动态链接库,供java调用,至于java是怎样去调用动态链接库的,我也不明白,以后研究。这里就先总结一下android工程中java调用linux平台的c/c++代码的一个HelloWorld例子,大体的步骤如下:
1、编写含有native方法的java文件
2、将这个文件生成对应的.class文件,进而生成.h文件
3、将.h文件改写成.c或.cpp文件并且完成jni函数的编写,这里需要的就是从java-->c/c++本地调用的函数的形式以及与.h文件的关联。
4、编写生成动态链接库的mk文件
5、在android工程中新建一个目录如jni,将.c或.cpp和.h和.mk文件放进去
6、编写完整的android工程
7、编写整个android工程的mk文件
8、将整个工程放在源码编译环境下
9、首先进入工程的jni目录执行mk文件,然后返回工程目录执行工程的mk文件
编写含有native方法的java文件
这里编写一个类Myjni.java
packagecom.example.jnitest;
public class Myjni {
public native String getStr();
}
将这个文件生成对应的.class文件,进而生成.h文件
将这个文件拷贝到D盘,用命令行的方式生成.h文件。
这里我们的java文件是带包的,所以我们在编译的时候需要带-d参数,如果没有包名则直接javac
Javac -d . Myjni.java
将生成的.class文件转变成.h文件
由于java文件是带包名的,所有这里需要在class文件前添加包名,才能找到具体的class文件
就在当前目录执行:Javah -classpath . com.example.jnitest.Myjni
《这个是之后加的图,对于包名为com.dxd.test的ABC.java源文件的生成.h文件的过程》
当然,如果想自己给生成的.h文件重新一个命名的话,可以指定-o参数
将.h文件改写成.c或.cpp文件并且完成jni函数的编写,这里需要的就是从java-->c/c++本地调用的函数的形式以及与.h文件的关联
生成的com_example_jnitest_Myjni.h头文件的内容如下
/*DO NOT EDIT THIS FILE - it is machine generated */
#include<jni.h>
/*Header for class com_example_jnitest_Myjni */
#ifndef_Included_com_example_jnitest_Myjni
#define_Included_com_example_jnitest_Myjni
#ifdef__cplusplus
extern "C" {
#endif
/*
* Class: com_example_jnitest_Myjni
* Method: getStr
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_jnitest_Myjni_getStr
(JNIEnv *, jobject);
#ifdef__cplusplus
}
#endif
#endif
我们可以看出,我们需要完善的函数,就是java_com_example_jnitest_Myjni_getStr,那么我们复制一份.h文件,改名为com_example_jnitest_Myjni.c,这里对这个文件稍做修改,这是c方面的知识了,这里就不多说。
#include "com_example_jnitest_Myjni.h"
JNIEXPORT jstring JNICALL Java_com_example_jnitest_Myjni_getStr
(JNIEnv* env, jobject obj)
{
return(*env)->NewStringUTF(env, (char *)"JNITest Native String");
}
编写生成动态链接库的mk文件
当这里,jni方面的事情就做的差不多了,再需要一个Android.mk文件,我们就可以在linux源码编译环境下生成.so动态链接库了。编写一个Android.mk文件,内容如下。
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE)
LOCAL_SRC_FILES:= \
com_example_jnitest_Myjni.c
LOCAL_MODULE_TAGS:= optional
LOCAL_MODULE := libjni_dxd
include $(BUILD_SHARED_LIBRARY)
在android工程中新建一个目录如jni,将.c或.cpp和.h和.mk文件放进去
将刚编写好的Android.mk文件和com_example_jnitest_Myjni.h和com_example_jnitest_Myjni.c文件放置于jni目录下
编写完整的android工程
这只是个例子,所有这里就只需要调用一下我们的native方法即可。
Log.e("jnitestgetStr = ", new Myjni().getStr());
编写整个android工程的mk文件
这里需要的是在源码环境下编译整个工程的Android.mk文件,内容如下
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS:= optional
LOCAL_SRC_FILES:= $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME:= JNITest
LOCAL_JNI_SHARED_LIBRARIES:= libjni_dxd
include $(BUILD_PACKAGE)
将这个Android.mk文件放置于android工程的目录之下。
将整个工程放在源码编译环境下
拷贝整个工程到packages/apps/目录下,去掉工程中的gen、bin、libs目录。
首先进入工程的jni目录执行mk文件,然后返回工程目录执行工程的mk文件
首先进入jni目录mm编译jni的mk文件以便生成libjni_dxd.so动态库。
然后返回到工程目录下,mm编码整个android工程,如果成功了的话,就会生成对应的apk文件 。这里必须要先生成动态库,应该编译整个工程时需要这个动态库,如果不事先编译好,整个工程是不能编译通过的,会报找不到动态库的错误。
总结:将jni相关的文件放置于工程的jni目录中,在源码下编译工程时是非常方便的!当然这依赖于NDK环境的配置。这里我只做了在linux平台上的jni例子,如果再windows平台的话,需要安装一个在windows平台上模拟linux平台环境的软件cygwin。
2743

被折叠的 条评论
为什么被折叠?



