Android之JNI初级篇

Android之JNI初级篇

JNI – Java Native Interface: Java平台中一个用于和本地C代码进行互操作的API,称为Java本地接口。也就是用来实现java程序中调用C函数。实质是将本地C代码编译到一个动态装载库中(如libHello.so/Hello.dll)。

Android JNI: 在Android工程中调用C的过程,称为Native Development。

本文档通过在Android APP中调用C函数执行Liniux 的Shell命令来简单介绍一下Native Development。

一、  准备

1、OS:Windows

2、Eclipse:略。

3、NDK(Native Development Kit):用来将C/C++生成的原生代码库嵌入到.apk文件中。下载地址:android-ndk-1.6_r1 ,解压即可。此外,NDK中还包含了从C / C++生成原生代码库所需要的工具和build files。要执行这些build,需要借助下面的Cygwin工具。

4、 Cygwin:是一个在windows平台上运行的unix模拟环境,使用gnu工具集在windows上进行嵌入式系统开发的优秀工具。下面着重介绍其安装方法:

首先下载安装工具:http://www.cygwin.com/setup.exe

点击执行它,下面是几个关键步骤的截图: 
Android之JNI初级篇

点击下一步 –> 选择Install from Internet  –> 下一步 –>选择安装目录 –> 下一步 –> 选择下载文件存放的目录 –> 下一步 –> 选择上网代理:Use Internet Explorer Proxy Settings  –> 下一步出现下图:
Android之JNI初级篇 

选择一个下载网站,通过测试,从http://mirrors.163.com下载速度较快,如果列表中没有,可以Add进去。

然后点击下一步,就进入了一个漫长的阶段Downloading,完成后会出现下图:
Android之JNI初级篇

将箭头指向的Devel@Default点成install然后下一步, 又进入一个漫长的阶段,包括解包,Checking,Running…
Android之JNI初级篇

好几个小时后,该阶段结束,直接下一步点击完成安装。桌面出现图标:
Android之JNI初级篇
 

点击测试,如果出现下图,则表示安装成功:
Android之JNI初级篇
 

接下来用Cygwin执行NDK/build下的host-setup.sh完成NDK的安装。方法:在窗口中通过cd命令进入NDK目录,然后执行build/host-setup.sh.

user@lizq /cygdrive/e/eclipse/android-ndk-1.6_r1

$build/host-setup.sh
Android之JNI初级篇
 

出现以上信息表示 Host setup complete。可以先编译一下NDK/apps文件夹中的工程实例,检查NDK是否正常工作.

选择apps/hello-jni做实验, 在NDK根目录下执行:make APP=hello-jni -B,其中-B参数是始终执行build, 不管C/C++代码是否有修改。如下图:
Android之JNI初级篇
 

从执行结果中可以看到:

SharedLibrary  : libhello-jni.so

Install        : libhello-jni.so => apps/hello-jni/project/libs/armeabi

生成了一个动态装载库libhello-jni.so,并且在libs/目录下NDK新建了一个armeabi文件夹,然后把libhello-jni.so放进去。

 

二、工程实践 – MyJni

1. 在NDK/apps/目录下新建一个文件夹:MyJni

2. 在MyJni下新建一个文件夹:project,用来存放实际工程

3. 在MyJni下新建一个文件:Application.mk, 内容如下:

     APP_PROJECT_PATH  := $(call my-dir)/project

APP_MODULES      := Hello       #最终.so文件的名字,如(Hello对应libHello.so)

4.在Eclipse中新建一个Android工程,Location选择上面的../apps/Myjni/project

5. 代码:

HelloJni.java

package com.jni.hello;

public class HelloJni {

     public native String cmd(String c);

}

执行javac HelloJni.java  ->  javah HelloJni,生成HelloJni.h文件, 内容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class HelloJni */

 

#ifndef _Included_ HelloJni

#define _Included_HelloJni

#ifdef __cplusplus

extern "C" {

#endif

/*

 * Class:     HelloJni

 * Method:  cmd

 * Signature: (Ljava/lang/String;)Ljava/lang/String;

 */

JNIEXPORT jstring JNICALL Java_ HelloJni_cmd

  (JNIEnv *, jobject, jstring);

 

#ifdef __cplusplus

}

#endif

#endif

 

注意几个地方jstringLjava/lang/String;

在C和Java之间传递数据时,应该知道彼此之间的对应类型。如jstring 对应Ljava/lang/String;

6. 在project/目录下新建一个文件夹:jni,用来存放C/C++文件,把上面的HelloJni.h放进去。

7. 实现HelloJni.c

#include “HelloJni.h”

JNIEXPORT jstring JNICALL Java_HelloJni_cmd(JNIEnv * env, jobject obj, jstring cmd)

{

    //略,参考附件源代码

}

8. 在jni目录下新建一个Android.mk, 内容如下:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := Hello                       #最终.so文件的名字,如(Hello对应libHello.so)

LOCAL_SRC_FILES   := HelloJni.c

LOCAL_LDLIBS += -llog

include $(BUILD_SHARED_LIBRARY)

 

9. 用Cygwin编译生成动态装载库

打开Cygwin,cd进入NDK目录,如/cygdrive/e/eclipse/android-ndk-1.6_r1

执行make APP=MyJin,如图:
Android之JNI初级篇

生成了libHello.so,并被放到../libs/armeabi目录下。

 

10. 在Android工程中调用JNI,如下Hello.java 代码片段:

public class Hello extends Activity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

              //…

      System.loadLibrary("Hello");                            //对应libHello.so

         HelloJni hjni = new HelloJni();

         String cmd = “cat /proc/meminfo”;          //shell 命令,查看内存信息

         _tv.setText("excute " + cmd + "\n" + hjni.cmd(cmd)); //在界面上显示执行结果

              setContentView(_tv);

}

}

11. 模拟器运行结果:
Android之JNI初级篇

12.源代码及工具包

参考附件。

 

一、   

二、   

三、  总结/问题

本文档是Android工程使用JNI之实践的初级篇,许多地方都是按部就班,比较死板。像

下面的一些问题都没有做深入的研究。

1.       为什么一定要把工程放在NDK/apps/下?

2.       如果工程的目录结构变化了,该如何写Application.mk和Android.mk?

能否将Cygwin和NDK都“集成”到Eclipse中,实现一键编译?

相关推荐