刚好在移植ArlinkPlayer工程到地面软件中需要用到一些NDK、JNI进行开发,就研究了一点入门基础,,纠结了好几天的问题,终于在昨天晚上解决了
分享一下技术成果,整理如下:
一、NDK基础:
NDK全称:Native Development Kit(原生开发工具集),因为java并不是完美的,其不足体现在运行速度要比传统的c/c++慢许多,且无法直接访问操作系统底层,为此,java同过navtive方法来扩展java程序的功能(可以将native方法比作java同c的接口方法)而ndk就是提供了一系列的工具来完成java程序中嵌入c/c++代码的。
这个过程如下(以下过程就叫JNI: java native interface (java本地调用)):
java源码中声明native方法
用javah生成.h文件
编写对应的.cpp文件来实现native定义的方法
将对应的.cpp文件编译成动态连接库
java中用System.LoadLibrary来载入动态链接库,这样就可以访问用c/c++实现的native方法了
而NDK就是提供了一系列的工具,帮助开发者快速开发c/c++的动态库,并能自动将so和java应用一起打包成apk,其集成了交叉编译器,并提供了相应的mk文件隔离平台、CPU、API等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。
二、NDK坏境搭建:
(1)下载安装NDK-r8c。
下载地址:http://developer.android.com/sdk/ndk/index.html
(2)指定ndk目录
直接点击工程右键按F12,如下图
输入ndk安装路径即可,顺便得配上环境变量,和配置jdk方式一样
三、NDK程序demo的开发
1.在droidplanner-master工程中新建一个ArtosynPlayerActivity.class(为了调用C/C++代码),其内容如下:
public class ArtosynPlayerActivity extends Activity implements SurfaceHolder.Callback,SwichLayoutInterFace {
native void stopVideo(); // 声明为native方法,后用c/c++来实现该方法
native void startVideoStream(Object id);
}
2.利用javah来生成 .h 的头文件
(1)用android studio中Terminal命令定位到ArtosynPlayerActivity.class 所在目录,输入“cd Android“后回车来到
工程目录下,接着输入javah -jni 包名.类名,然后Enter,会生成相应的.h文件,如下。(如果有多个类中新建了本地native方法,就分别重复以上操作,就会生成多个.h文件吧)该文件只是为了辅助我们写出相应的.c文件,使用完了即可删除。文件内容如下:
E:\studio_workspace\droidplanner-master\Android>javah -jni -classpath E:\sdk\platforms\android-21\android.jar;E:\studio_workspace\droidplanner-master\Android\bu
ild\intermediates\classes\debug com.playuav.android.activities.ArtosynPlayerActivity
有用的就是
/*
* Class: com_playuav_android_activities_ArtosynPlayerActivity
* Method: stopVideo
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_playuav_android_activities_ArtosynPlayerActivity_stopVideo
(JNIEnv *, jobject);
/*
* Class: com_playuav_android_activities_ArtosynPlayerActivity
* Method: startVideoStream
* Signature: (Ljava/lang/Object;)V
*/
JNIEXPORT void JNICALL Java_com_playuav_android_activities_ArtosynPlayerActivity_startVideoStream
(JNIEnv *, jobject, jobject);
仔细观察可以看到他是遵循“Java_包名类名本地方法名”来组织的(了解到这些后我们以后就可以不生成.h文件然后直接去写.c文件了)。
5、在Android下(或者app下)新建 jni文件夹,编写.c文件
在jni下新建.c文件,用于实现生成的.h文件中声明的方法,如下:
6、jni下编写Android.mk文件
LOCAL_MODULE := xx //要生成的so库的名称,但实际为libdemo.so
LOCAL_SRC_FILES := xx.c //要使用的文件,刚才编写的xx.c文件
7、生成so文件(重要)
在studio控制台中,进入到工程的Android(或者是app)目录下(就是jni所在目录的上一级),然后输入ndk-build(如下所示),不出问题即可编译成功。
或者进入cmd中操作是一样的。
编译完成后刷新工程,可以看到在app目录下生成的libs和obj文件夹,其中libs是有用的,obj文件夹无用可以删除。libs中的可以看到生成的libdemo.so文件。
8、加载so文件,调用本地方法
注意:在以上过程中可能会报错,需要进行一些设置(为什么要设置这一步要搞清楚 by RizHuang)
gradle.properities中添加代码如下:
android.useDeprecatedNdk=true
最后点击运行ok