NDK JNI--学习笔记

作者: Kevin_Curry | 来源:发表于2016-03-31 14:42 被阅读387次

    JNI    是java语言提供的Java和C/C++相互沟通的机制,Java可以通过JNI调用本地的C/C++代码,本地的C/C++的代码也可以调用java代码。

    JNI 是本地编程接口,Java和C/C++互相通过的接口。Java通过C/C++使用本地的代码的一个关键性原因在于C/C++代码的高效性。

    NDK  是一系列工具的集合。它提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk。

    这些工具对开发者的帮助是巨大的。它集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。它可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。

    Java通过JNI机制和C/C++沟通的具体步骤

    1、编写包含native本地方法的java类

    2、通过javah工具生成C/C++语言的头文件

    3、使用C/C++语言实现头文件

    4、使用交叉编译工具对C/C++本地代码进行编译,最后通过链接生成*.so可执行的C/C++库

    5、实际执行Java代码去和本地的C/C++代码互相沟通

    JNI是Java调用Native机制,是Java语言自己的特性全称为Java Native Interface,类似的还有微软.Net Framework上的p/invoke,可以让C#或Visual Basic.Net可以调用C/C++的API,所以说JNI和Android没有关系,在PC上开发Java的应用,如果运行在Windows平台使用JNI是是经常的,比如说读写Windows的注册表。而NDK是Google公司推出的帮助Android开发者通过C/C++本地语言编写应用的开发包,包含了C/C++的头文件、库文件、说明文档和示例代码,我们可以理解为Windows Platform SDK一样,是纯C/C++编写的,但是Android并不支持纯C/C++编写的应用,同时NDK提供的库和函数功能很有限,仅仅处理些算法效率敏感的问题,所以推荐初学者学好Java后再学习JNI。

    简单点说,用C语言生成一个库文件,在java中调用这个库文件的函数。JNI的过程比较复杂,生成.so需要大量操作,而NDK就是简化了这个过程。

    ---------------------------------------------------------------------------------------------------------------------------------------

    1. 首先创建MainActivity,添加native方法:

    2. 在main目录下创建一个jni目录,用来放头文件,可以用下面的方法:

    3. 编译头文件
    在Terminal中进入到项目的根目录,对于Android Studio来说,切换到app\src\main就行,按照网上的说法,直接执行下面的命令:

    javah -d jni com.jackie.hellondk.MainActivity(-d jni 指定头文件生成在jni目录下,如果没有第二步创建jni文件夹,也会自动创建)

    很明显,找不到MainActivity的.class字节码文件,然后按照官网的方法,指定MainActivity.class的路径,在Android Studio中,所有的.class文件都生成在app\build\intermediates\classes\debug下面,所以,执行下面的命令:

    javah -classpath ..\..\build\intermediates\classes\debug -d jni com.jackie.hellondk.MainActivity

    这是什么原因呢?这是由于我们上面的MainActivity继承了AppCompatActivity,这个类是在Android v7的兼容包下,所以还需要v7的兼容包加入到classpath中:

    javah -classpath D:\DevTools\studio_sdk\extras\android\support\v7\appcompat\libs\android-support-v7-appcompat.jar;..\..\build\intermediates\classes\debug -d jni com.jackie.hellondk.MainActivity

    同样,也需要将v4的兼容包加入到classpath中:

    javah -classpath D:\DevTools\studio_sdk\extras\android\support\v4\android-support-v4.jar;D:\DevTools\studio_sdk\extras\android\support\v7\appcompat\libs\android-support-v7-appcompat.jar;..\..\build\intermediates\classes\debug -d jni com.jackie.hellondk.MainActivity

    无语了,真是处处都是坑啊,继续把android.jar添加到classpath中呗!

    javah -classpath D:\DevTools\studio_sdk\platforms\android-23\android.jar;D:\DevTools\studio_sdk\extras\android\support\v4\android-support-v4.jar;D:\DevTools\studio_sdk\extras\android\support\v7\appcompat\libs\android-support-v7-appcompat.jar;..\..\build\intermediates\classes\debug -d jni com.jackie.hellondk.MainActivity终于成功生成了头文件,如下:

    4. 实现native方法
    在jni目录新建一个hello.c文件,实现头文件中的方法:

    5. 编写Android.mk文件

    6. 编译动态链接库so,注意要切换到jni所在的目录,执行ndk-build之前,还需要配置环境变量。

    7. 引用

    编译会出现下面的错误:

    在gradle.properties添加下面一句:

    android.useDeprecatedNdk=true

    继续编译,错误如下:

    配置如下:

    编译后,安装完成后,还是会出现java.lang.UnsatisfiedLinkError couldn't find libhello.so的错误。

    修改build.gradle配置,在defaultConfig里面新增一下代码:

    ndk {    moduleName"hello"abiFilters"armeabi","armeabi-v7a","x86"}

    注意,这里的moduleName一定要和System.loadLibrary以及Android.mk中定义的名称一致。

    最后一次运行,终于看到了久违的界面啊!走了很多弯路,真是处处都是坑,做个记录,希望对你们有所帮助。最后说一点,上面用ndk-build来编译生成动态链接库libhello.so,然后在Java中通过loadLibrary来加载。在实际开发过程中,完全可以省去ndk-build这一步,开发好jni程序后,直接运行程序,Android Studio会自动帮我们编译动态链接库,亲测成功!

    Android Studio NDK开发 - - 博客频道 - CSDN.NET

    相关文章

      网友评论

        本文标题:NDK JNI--学习笔记

        本文链接:https://www.haomeiwen.com/subject/zdmzkttx.html