您的位置:首页 > 移动开发 > Android开发

Android中JNI创建实例

2015-01-04 22:18 423 查看
参考文档:
http://blog.sina.com.cn/s/blog_a11f64590101924l.html
/article/4895291.html
/article/4823473.html
http://blog.csdn.net/zhenyongyuan123/article/details/5862054

Android通过JNI来实现Java层调用C层代码。当我们在进行NDK开发时候,并且提供Java层接口,则我们必须创建c代码,然后编译*.so库,编写JNI中的代码,最后Java层通过System.loadLibrary()方法加载*.so动态库,即可实现。
编写一个具有*.so, jni , java整体模块,一般有个步骤:(1)编写Java层代码,里面主要实现两个步骤,一个是定义native方法,另一个是调用System.loadLibrary()方法加载C层要写的动态库;(2)由Java代码所生层的class文件,使用javah命令生成JNI中所需的*.h头文件;(3)实现上面所生存的*.h头文件;(4)编写Android.mk文件,生存*.so库(5)编译整个工程生成apk。

第一:编写Java文件
根据我们需要实现的Java程序,来编写native方法和调用System.loadLibrary()方法加载动态库,一般开发Android工程我们都在Eclipse环境下,因此,这里也在该环境下编写一个Demo。
packagecom.example.nativetest;

publicclassNativeClass {
static
{
System.loadLibrary("NativeClassJni");
}
privatestaticnativeintnativeGetResult(intsrc);
publicintgetResult(intsrc){
returnnativeGetResult(src);
}

}


当我们编写好Java代码后,Eclipse会自动在工程bin目录中生成对应的class文件,里面包含了所有Java文件所生的.class文件。

第二:由javah命令生成JNI中所需的*.h头文件
javah命令是将Java源文件生存C头文件,具体原理可参考:/article/2968089.htmlhttp://blog.csdn.net/archfree/article/details/6155995

在第一步中,我们知道在工程的bin/classes/*目录里有生成的.class文件,这里就需要使用javah命令将对应的NativeClass.class生成*.h文件,我们进入到工程根目录里面,执行如下命令:
javah-classpath
./bin/classes -d jni com.example.nativetest.NativeClass

该命令解析如下:-classpath选项表示工程Java文件所生成的所有.class所在的目录,必须指定bin/classes目录下面,即所有.class所在的目录,不能是它的子目录或者父目录,否则就会出现错误:error:cannot
access com.example.nativetest.NativeClass ,这点非常重要。-djni表示在当前的目录下新建一个jni文件夹,然后将生成的*.h文件放入到该目录中,因为测试当前目录是工程的根目录,因此,会在根目录中新建jni文件夹;若无该选先,则生成的.h文件会在当前目录中。

当我们进入jni文件中,就会发现所生成的头文件com_exmaple_nativetest_NativeTest.h。

/*DO NOT EDIT THIS FILE - it is machine generated */
#include<jni.h>
/*Header for class com_example_nativetest_NativeClass */

#ifndef_Included_com_example_nativetest_NativeClass
#define_Included_com_example_nativetest_NativeClass
#ifdef__cplusplus
extern"C" {
#endif
/*
*Class: com_example_nativetest_NativeClass
*Method: nativeGetResult
*Signature: (I)I
*/
JNIEXPORTjint JNICALL Java_com_example_nativetest_NativeClass_nativeGetResult
(JNIEnv*, jclass, jint);

#ifdef__cplusplus
}
#endif
#endif


第三:实现.h头文件,编写c/c++文件
我们要在前面所生成的.h文加夹目录中编写c/c++文件来实现该头文件,*.c和*.cpp文件的名称由用户自己定义,但是必须要在Android.mk文加中的LOCAL_SRF_FILES指向该文件即可,一般情况下,取和*.h相同的名字。
上面实现的.cpp文件内容如下:
#include<jni.h>
#include<com_example_nativetest_NativeClass.h>
/*
*Class: com_example_nativetest_NativeClass
*Method: nativeGetResult
*Signature: (I)I
*/
JNIEXPORTjint JNICALL Java_com_example_nativetest_NativeClass_nativeGetResult
(JNIEnv* env, jclass obj, jint in)
{
returnin + in;
}


很多人在最终成功编译so并载入so后,在java层调用native方法时会出现java.lang.UnsatisfiedLinkError这个异常.原因是就在第一行,这里c和c++是有些区别的,如果用c实现的话,只需要includejni.h即可,但是如果用c++实现,那么必须要include你刚刚生成的.h文件,而不是jni.h.虽然编译可以通过,但是调用时你会发现报了java.lang.UnsatisfiedLinkError这个异常.原因就是java层没找到对应的方法.还有就是c和c++语法上的一些小区别,但这些错误是可以在编译so期间发现的.
第四:编写Android.mk文件,生成*.so动态库
当我们实现好.c或者.cpp文件后,编写Android.mk文件,来生成动态库,一般使用NDK工具进行生成,首先是下载ndk包,然后设计全局变量,进入Android.mk文件夹中执行ndk编译命令即可。
ndk编译命令使用参考:
/article/5041440.html
/article/9583861.html

我们进入.c,.h, Android.mk所在的文件下面,然后执行ndk编译命令:
ndk-build

信息如下:

abc@abc:~/workspace/NativeTest/jni$ndk-build
AndroidNDK: WARNING: APP_PLATFORM android-19 is larger thanandroid:minSdkVersion 8 in/home/archermind/workspace/NativeTest/AndroidManifest.xml
[armeabi]Compile++ thumb: NativeClassJni <=com_example_nativetest_NativeClass.cpp
[armeabi]StaticLibrary : libstdc++.a
[armeabi]SharedLibrary : libNativeClassJni.so
[armeabi]Install : libNativeClassJni.so =>libs/armeabi/libNativeClassJni.so

我们可以看到,在工程目录libs生成了一个armeabi文件夹,里面有一个libNativeClassJni.so文件,就是NDK生成的动态库,注意,这个名称前面的lib是系统自动加上去的,在Java代码中的System.loadLibrary()中是不需要,即只是System.loadLibrary(NativeClassJni).

第五:编译整个工程
当.so库编译好之后,我们在Eclipse里面对整个工程进行编译,生成apk,导入到Devices里面即可运行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: