android JNI的使用示例详解

来源:互联网 发布:mac电脑显示器分辨率 编辑:程序博客网 时间:2024/06/11 16:53


众所周知,android是使用java进行开发,但是在开发过程中可能会用到之前的c,c++代码,或者乳沟你想一套代码同时在iphone和android平台复用就会用到JNI啦。

JNI起的是一个桥梁的作用,可以转化java与c/c++的一些区别,比如数据类型等。之后我们将转换好的c代码生成动态链接库,供java调用。

下面以一个示例做说明,希望对刚接触的童鞋有所帮助。

1、安装NDK环境:这个可以参照我的前一篇文章“windows系统上安装与使用Android NDK r5”。这是一个童鞋写的,照着做就可以完全没有问题的安装好。

2、当你按照步骤1安装好环境后,比如安装在了D盘D:\android-ndk-r6,本文以下默认此路径,如果你的路径不同 做相应改变就好了。然后在D:\android-ndk-r6下新建apps文件夹,里面存放的就是你将来要搞的android jni 工程相关文件啦。

现在我在D:\android-ndk-r6\apps 下创建我的第一个工程目录Angry,注意这个Angry并不是你的android工程的根目录,在Angry下创建project文件,这下面存放的将是你的android工程。 以下是我的目录结构:

 

之所以这样是因为,大家可以看到在Angry下还有个Application.mk文件(下面讲这个文件的生成),这个文件里是我们将c/c++编译成动态链接库(.so)的时候需要使用到的配置信息。除这个文件外我们还会用到一个Android.mk文件,在下面会讲到。

3.好了,接下来就创建我们的android工程吧。创建Android工程,指定工程路径:D:\android-ndk-r6\apps\Angry\project,以下是我创建的工程:

              

创建好了之后就可以写我们的java接口了(相当于函数声明),真正的功能实现是要用c/c++实现的吆。你可以新建一个java文件,或者直接在你继承Activity的那个java中直接写,我是新建了一个Jni.java文件:

                                                               

Jni.java中的代码如下:
package com.Angry;public class Jni {public native String getString ();}

注意接口要声明成native的吆。如果你不想单独放在一个文件中也可以直接放在MainAct.java中,将 public native String getString (); 放进去就好了。

4.生成头文件以及源文件:

将Jni.java复制到D:\android-ndk-r6\apps\Angry\project\bin下面,然后在D:\android-ndk-r6\apps\Angry\project\bin用“javac jni.java”编译生成Jni.class文件,将生成的Jni.class复制到 D:\android-ndk-r6\apps\Angry\project\bin\com\Angry下覆盖掉原先的Jni.class文件。

然后再在D:\android-ndk-r6\apps\Angry\project\bin下使用命令 "javah -jni com.Angry.Jni" 这是将会在bin下生成一个com_Angry_Jni.h的头文件,大家可以看一下我的生成:、

/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class com_Angry_Jni */#ifndef _Included_com_Angry_Jni#define _Included_com_Angry_Jni#ifdef __cplusplusextern "C" {#endif/* * Class:     com_Angry_Jni * Method:    getString * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_Angry_Jni_getString  (JNIEnv *, jobject);#ifdef __cplusplus}#endif#endif

其实就是将我们原先Jni.java中的public native String getString ();函数声明形式做了些许改动,使之符合JNI规则。

之后我们要在D:\android-ndk-r6\apps\Angry\project下即Android工程下新建jni文件夹,将com_Angry_Jni.h文件放入其中。这个jni文件夹将是盛放我们c/c++源文件以及头文件和Android.mk文件的场所。

接下来就是实现我们的函数功能了:新建c/c++源文件:com_Angry_Jni.c(同样放在jni文件夹下):

#include <stdio.h>#include <stdlib.h>#include "com_Angry_Jni.h"JNIEXPORT jstring JNICALL Java_com_Angry_Jni_getString  (JNIEnv *env, jobject thiz) { return (*env)->NewStringUTF(env, "I,M ANGRY");}

像我就只是单纯的实现了返回一字符串的功能,具体功能大家可以自己添加。程序中的jstring 等数据类型其实jni对c/c++的数据类型做了形式的改变,jstring 就是String。

现在功能都实现好了,我们可以将上面的c代码编译成so文件供java调用(因为android是基于linux的,而linux的动态链接库文件是以.so为后缀,windows以.dll为后缀)。

5、编译生成.so文件需要两个.mk文件,就是我们上面提到的Application.mk文件和Android.mk,在D:\android-ndk-r6\apps\Angry\project\jni下创建Android.mk,内容如下:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := AngryLOCAL_SRC_FILES := com_Angry_Jni.cinclude $(BUILD_SHARED_LIBRARY)


LOCAL_PATH: 表示位于工程的根目录。

include $(CLEAR_VARS) 功能还不太清楚我。

LOCAL_MODULE := Angry 这个表明你的一个动态链接库的名字,所以你的链接库生成后会叫libAngry.so,libxxx.so是系统加的,xxx即此处的名字。

LOCAL_SRC_FILES := com_Angry_Jni.c 这是你要编译的源文件。

还有好多配置指令,有兴趣大家可以自己查。

然后再在D:\android-ndk-r6\apps\Angry 下创建Applicetion.mk文件:

APP_PROJECT_PATH := $(call my-dir)/projectAPP_MODULES := Angry

APP_MODULES := Angry  指明了你的应用模块。

6、到此为止,我们都把准备工作做好了,接下来生成.so文件:

启动cygwin,进入NDK根目录:D:\android-ndk-r6,运行命令:make APP=Angry   如果显示:

                                                                                        

则表示.so生成并安装成功,你可以看到在 D:\android-ndk-r6\apps\Angry\project 下多了一个两层目录libs\armeabi\ 下面放着我们生成的libAngry.so。

7、到此为止,基本大功告成,下面我们验证一下c函数的功能能否实现:

在MainAct.java中实现如下简单代码:

package com.Angry;import android.app.Activity;import android.os.Bundle;import android.widget.TextView;public class MainAct extends Activity { private TextView tv;    /** Called when the activity is first created. */ static {  System.loadLibrary("Angry"); }    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);                Jni jni = new Jni();        tv = (TextView)findViewById(R.id.tv);                tv.setText(jni.getString());    }}

运行下,看看效果:


 
已经正确调用了呀。大家试试吧!微笑

原创粉丝点击