已阅读:10,930 次
Android如何使用NDK进行JNI开发
ian | Android | 2012/04/10


所谓JNI就是Java Native Interface的缩写,即JAVA本地调用,它允许Java代码和其他语言写的代码进行交互,这里主要指的是C/C++这样的Native Code。

虽然Android平台下提供的Java的SDK一般情况下能满足开发者的需求,但是由于Java语言的效率问题,在我们漫长的开发过程中,总是会遇到一两个性能瓶颈的,这个时候我们就需要考虑使用NDK了。NDK是Android提供的一套工具,帮助我们编写、编译C代码并在Java中调用。可以这么说,不懂如何使用NDK的Android开发不能算是合格的Android开发者,下面简单介绍一下如何使用NDK。

前面有一篇文章介绍了如何配置NDK的开发环境,除了Android的开发环境外,NDK开发是需要额外安装一些工具的,不懂的朋友可以参考《Android NDK开发环境搭建》,在这篇文章中最后提到了NDK中提供的一些Sample,下面就来介绍如何自己一步一步实现自己的HelloJni,介绍按如下步骤进行:

1 新建Project
2 定义Java JNI接口
3 使用javah生成C接口
4 实现C方法
5 编译C代码
6 运行Android项目,调用JNI查看结果

下面开始具体的步骤讲解:

1 新建Project
首先进入Eclipse,新建一个Android Project,取名MyFirstJni吧,后面的步骤就不细述了。这里要提醒的是,为了方便,以及避免NDK环境变量冲突的问题,大家可以直接把项目所在目录放到NDK安装路径的Samples目录下。

结束新建向导后,此时整个项目只有一个Activity,然后就让我们尝试来加入一些新的代码吧。

2 定义Java JNI接口
新建一个JniEngine的class,然后添加一个有native前缀的方法,这个前缀就是告诉NDK工具这是一个JNI调用的接口,NDK工具会帮我们自动生成相应的C文件。新建JniEngine之后,为JniEngine.java添加一个接口,代码如下所示:

1
2
3
4
5
6
7
public class JniEngine{
    static {
        System.loadLibrary("JNITest");
    }
 
    public native String getResultFromJni();
}

上面的代码中,getResultFromJni()就是JNI调用的接口,System.loadLibrary(“JNITest”)是指定加载生成的动态链接库,当然参数就是我们的Android.mk指定的生成的so文件的名称的,这个可以自己指定的。

3 使用javah生成C接口
首先Build一下项目,不然本步骤无法成功。Build成功后,打开Console进入项目的根目录,然后输入如下命令:

1
javah -classpath bin/classes -d jni com.spore.meitu.jni.JniEngine

最后一个参数就是指定为JniEngine这个类生成相应的C代码,这里需要指定这个类的完整包路径。由于javah是通过编译后的.class文件中的信息查找相应的类及其接口的,所以在执行这个命令之前需要先编译一下工程以更新class文件。-classpath这个参数就是指定class文件所在路径,android中直接指定bin/classes即可。

上面的命令执行成功后,我们会发现在项目根目录下多了一个jni目录,目录下有一个文件”com_spore_jni_JniEngine.h”,这个头文件包含一个函数的声明:
JNIEXPORT jstring JNICALL com_spore_jni_JniEngine_getResultFromJni(JNIEnv *, jobject);
这个接口对上面的JniEngine.java中定义的接口相对应。

4 实现C方法
既然C方法声明已经帮我们生成了,接下来我们要做的就是实现它,下面的步骤就跟写C代码是一样的。
新建一个文件com_spore_jni_JniEngine.c,添加代码如下并保存:

1
2
3
4
5
6
7
#include <stdlib.h>
#include "com_spore_jni_JniEngine.h"
 
jstring Java_com_spore_jni_JniEngine_getResultFromJni(JNIEnv* env, jobject thiz)
{
	return (*env)->NewStringUTF(env, "This is my first ndk code!!!");
}

5 编译C代码
编译是通过ndk-build工具,其实就是调用gcc来编译的,这里我们还需要编写一个Android.mk文件,指定一些编译的参数。此处示例很简单,可以直接拿NDK Samples中的mk改一改就可以了。Android.mk的内容如下所示:

1
2
3
4
5
6
7
8
9
10
11
LOCAL_PATH := $(call my-dir)
 
include $(CLEAR_VARS)
 
LOCAL_SRC_FILES:= \com_spore_jni_JniEngine.c
LOCAL_C_INCLUDES := \ $(JNI_H_INCLUDE) 
LOCAL_SHARED_LIBRARIES := libutils 
LOCAL_PRELINK_MODULE := false 
LOCAL_MODULE := libJNITest
 
include $(BUILD_SHARED_LIBRARY)

然后在Console中,在项目根目录下,直接输入ndk-build,回车,即开始编译。编译成功后,会在项目根目录下生成一个libs的目录,编译生成的libJNITest.so就在这个目录下。

6 运行Android项目,调用JNI查看结果

要查看从C代码返回的结果,我们还需要添加一些代码。在Activity的onCreate中添加如下代码:

1
2
JniEngine jniEngine = new JniEngine();
Toast.makeText(this,jniEngine.getResultFromJni(),Toast.LENGTH_LONG).show();

然后Build项目,运行,进入应用后,会出现一条Toast提示”This is my first ndk code!!!”。

上面的例子,虽然功能很简单,但是这个字符串却是从C代码中传过来的。熟悉了这个NDK开发的流程之后,我们就可以定义更多更复杂的接口,将更多功能放到Native Code空间,由C代码来实现,这样必将大大提升程序的性能!

原创文章,转载请注明:转载自ian的个人博客[http://www.icodelogic.com]
本文链接地址: http://www.icodelogic.com/?p=551

tags:

2条评论

  1. leafisme 说:

    实现C方法 里面y应该是:
    Java_com_spore_jni_JniEngine_getResultFromJni

发表评论

你需要先 登录 才能回复