您的位置:首页 > 其它

JNI基本使用

2016-05-21 16:30 302 查看

概述

从今天开始,准备研究一下JNI相关的开发,其实很早之前就想学习这方面的东西了,一个原因是平时开发中用的很少,就没研究,另外一个原因是因为其他方面的东西还是比较多的,所以没有时间来学习这部门内容。不过从今天起,为了向全面发展的道路上更迈进一步,开始学习JNI.

准备工作

开发JNI我们需要NDK这个东西?什么是NDK呢?简单给大家介绍一下,NDK是一系列工具的集合

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

NDK集成了交叉编译器,并提供了相应的mk文件隔离CPU、平台、ABI等差异,开发人员只需要简单修改mk文件(指出“哪些文件需要编译”、“编译特性要求”等),就可以创建出so。

NDK可以自动地将so和Java应用一起打包,极大地减轻了开发人员的打包工作。

首先我们去下载NDK,然后放在磁盘的某个路径下,这里我放在了

D:\develop\android-ndk-r10e


这是第一步,然后我们就可以在开发环境中进行配置了,很简单,只需要一句话,我们就可以开始JNI的编程了。具体做法如下,在当前项目的local.properties文件中添加你ndk的路径

# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
sdk.dir=D\:\\develop\\studioSDK
ndk.dir=D\:\\develop\\android-ndk-r10e


或者手动选择NDK目录也可以



这时候编译工具会自动在local.properties文件中添加ndk路径

编码

准备工作做完了,我们开始写代码。

在当前项目中新建一个类,如下所示:

public class NdkUtil {
public native String getString();
}


然后我们在MainActivity中进行方法的调用

public class MainActivity extends AppCompatActivity {

private TextView textView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textview);
NdkUtil ndkUtil = new NdkUtil();
textView.setText(ndkUtil.getString());
}
}


然后我们选择build-Make Project,然后会产生一个对应的class文件,目录F:\Studio\MyApplication2\MyApplication2\app\build\intermediates\classes\debug\com\example\hecun\myapplication\NdkUtil.class



然后接下来的步骤就是根据生成的class文件,利用javah生成对应的 .h头文件。

点开AS的Terminal标签,默认进入到该项目的项目名称文件夹下

然后我们输入如下命令,进入到class文件生成的中间路径

cd app\build\intermediates\classes\debug


然后执行下面的javah命令生成.h文件

javah -jni com.example.hecun.myapplication.NdkUtil






我们可以看到.h文件已经生成了。其内容为

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

#ifndef _Included_com_example_hecun_myapplication_NdkUtil
#define _Included_com_example_hecun_myapplication_NdkUtil
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:     com_example_hecun_myapplication_NdkUtil
* Method:    getString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_hecun_myapplication_NdkUtil_getString
(JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif


然后我们再main文件夹下新建一个jni目录,把刚才生成的.h文件剪切过来,接着新建一个.c文件,比如jnitest.c,名字可以随意取,编辑代码如下

#include "com_example_hecun_myapplication_NdkUtil.h"
JNIEXPORT jstring JNICALL Java_com_example_hecun_myapplication_NdkUtil_getString
(JNIEnv *env,jobject obj){
return (*env)->NewStringUTF(env,"This is a Test for JNI");
}


有的同学可能对上面的步骤有点疑问,为什么不直接把.h文件生成在jni目录下,还要复制过来,这不是多次一举吗,实际情况是这样的,因为我们的NdkUtil.class文件实在debug中的,所以我们只能进入到这个目录中去生成.h文件,如果不进入这个目录,去利用javah命令生成头文件,会出现找不到类的错误



最后我们再module的build.gradle文件中加入如下配置信息

defaultConfig {
.....
ndk{
moduleName "MyJniSo"         //生成的so名字
abiFilters "armeabi", "armeabi-v7a", "x86"  //输出指定三种abi体系结构下的so库。目前可有可无。
}
}


现在生成的so库的名字有了,然后我们去NdkUtil里面去加载这个库

public class NdkUtil {
public native String getString();
static {
System.loadLibrary("MyJniSo");
}
}


使用gradle的好处是,自动编译生成apk文件,并且把相关的.so文件打包到apk安装包中,一劳永逸

还有一种以前传统的手动编译方式,这里顺便也介绍一下

首先我们要配置环境变量,因为我们要使用ndk命令来进行编译,

接下来,创建两个文件,Android.mk和Application.mk

Androidmk

ndroid.mk文件用来指定源码编译的配置信息,例如工作目录,编译模块的名称,参与编译的文件等,大致内容如下:



Application.mk



我们导出apk,然后解压,看一下是否有so文件



可以看到,so文件已经打包到apk的lib中

好了,到此AS下NDK JNI开发的代码编写和设置就OK了,接下来就是编译工程运行就可以了。

效果图



最后总结一下JNI开发流程:

1.在类中定义Native方法

2. 利用javah命令将类所的class文件生成为.h头文件

3. 在main文件夹下新建一个jni目录,将生成的.h文件剪切过来,同时创建一个.c文件,目的就是实现JNI方法

4. 在gradle文件中配置so库的名字以及指定的abi体系
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: