前几天,解决一个问题的时候,用到了JNI,所以记录下来,以便以后的查看!
1.遇到的问题是这样的,覆盖build.prop文件时手机突然断电,手机不能开机,当时是用java的os的文件读写实现的。开不了机的原因是build.prop为空,文件损坏了。但是,奇怪的java中,读文件和写文件的步棸,log都显示已经完成了,但是在手机突然掉电的时候,build.prop就是为空,导致开不了机。(至于为啥log显示读写完成,但是那个文件就是为空,现在也没有找到原因)
2.既然用java的os读写会有这个问题,后来,想到了用更高效的c来实现文件读写,自然这样就要联系到JNI了。那我们得明白,JNI是什么,有什么作用:
JNI是java Native Interface即JAVA本地调用接口。这种技术的主要作用是:java通过JNI调用底层语言的实现,比如java 和c,c++的通讯。
a.新建一个android工程(JNITest),在工程名下新建jni目录,用来放c或者c++文件。
b.在/src包下新建一个类JNITest.java,里面新建方法,方法都为publicstaticnative返回值函数名 (参数1,参数2...);
如publicstaticnativeStringWriteFile(StringoldPath,StringnewPath);
c.写好JNITest.java后,那么我们怎么去写我们jni目录下的文件呢?这里先在eclipse中,运行下我们的程序,运行完后,
在JNITest中会生 成bin/classes/..这个目录,在这个目录下,有一个我们将要用到的文件JNITest.class。然后我们用终端在
进入到classes目录下打开,然后执行命令:javah包名.JNITest(如com.example.jnitest.JNITest)。之后我们可以看到classes
目录下多了com_example_jnitest_JNITest.h这个文件。这个文件就有我们需要在c或者c++中实现的函数。
d.打开这个.h文件,我们可以看到里面有我们在java文件中定义的对应函数,
如JNIEXPORTjstring JNICALL Java_com_example_jnitest_JNITest_WriteFile (JNIEnv *,jclass, jstring, jstring);
e.在建好的jni/目录下新建JNITest.c,对WriteFile这个函数实现,其中.h这个文件中对函数的修饰JNIEXPORT,JNICALL不需要,
要去掉,否则编译报错。如:
jstringJava_com_example_jnitest_JNITest_WriteFile(JNIEnv *env, jobject thiz,jstring oldpath, jstring
newpath) {//jstring对应java中的string,这里每个类型都有个对应,要查看具体的可以网上查具体资料。
//....内容实现, 具体的实现见后面的c语言的读写文件实现。
return(*env)->NewStringUTF(env, "opecccccccc!");//返回值的内容
}
f.在jni目录下建立Android.mk.其内容:
LOCAL_PATH:= $(callmy-dir)
include$(CLEAR_VARS)
LOCAL_MODULE:= libjnitest//这个是.so库文件的名字,一般比较规范的命名为:jnixxx。
LOCAL_SRC_FILES:= JNITest.c
LOCAL_LDLIBS+= -llog //如果需要打log,需要增加这个
include$(BUILD_SHARED_LIBRARY)
g.把工程放入已经编译过的项目下,编译jni,会生成out/target/product/e02_fake/system/lib/libjnitest.so这个.so,文件。
同时在项目下建立:lib/armeabi/目录。然后把生成的.so文件拷贝到这个目录下,编译整个项目
f.在.java文件中使用我们实现好的jni,在java文件中加入
static{
System.loadLibrary("jnitest");//这是加载这个lib库,注意这个名字比我们LOCAL_MODULE:= libjnitest
//中的名字前面少了lib
}
e.在需要的地方用JNITest.WriteFile(“”,“”);可以输出返回值。在整个项目的android.mk中,加入
LOCAL_JNI_SHARED_LIBRARIES:= libjnitest;编译整个项目,最后install。
这样一个简单的JNI就做好了。