现在的位置: 首页 > 综合 > 正文

JNI技术与Android应用

2013年10月02日 ⁄ 综合 ⁄ 共 3408字 ⁄ 字号 评论关闭

JNI技术与Android应用

 

1. 什么是 JNI 

    JNIJava Native Interface的缩写。从Java 1.1开始,JNI标准成为java平台的一部分,它允许Java和其他语言进行交互。JNI一开始为CC++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。关于 JNI 的用法很简单,有点像 java 里的 reflect 的工作机制,有兴趣的朋友可以参看Java 本地接口规范 http://linux.computersci.net/articles/jdk1.2/docs/guide/jni/spec/jniTOC.doc.html

2.  Jni程序开发的一般操作步骤如下:

(1) 编写带有native声明的方法的java

(2) 使用javac IDE(JBuilder,eclipse)编译所编写的java

(3) 使用javah -jni java类名生成扩展名为h的头文件

(4) 使用C++ 实现本地方法,对调用签名可用 javap –s –p [类全名] 查看(开发 C++ 动态链接库本例是用的 VC6

注意要从 JDK下面的 include 文件夹中把 jni.h jni_md.h 两个文件 copy 到你的 VC 工程里

(5) Java load 动态链接库文件,调用 native 方法.

或者说将项目依赖的所有原生库和资源加入到java项目的java.library.path,生成java程序

3. 开发实例

(1). 编写 Java :

package org.jm.jni;

import java.util.ArrayList;

public class BackgroundProcess {

static {

System.loadLibrary("org_jm_jni_BackgroundProcess");

}

// 三个 native 方法和一个 int 变量

public native boolean checkValid();

public native void processData(BackgroundProcess bg);

public native void processGarbage(String[] bg);

public int num = 5;

// C++ 中可以调用的方法

public String backProcess(ArrayList<String> p) {

System.out.println("这是 Java 里的方法,在 C++ 中调用。");

System.out.println("这个方法,是 java native checkValid 方法调用的。");

return "look up process ->" + p;

}

public static void main(String[] args) {

String[] array = new String[4];

array[0] = "jack";

array[1] = "maggie";

array[2] = "rocket";

array[3] = "tom";

BackgroundProcess bgP = new BackgroundProcess();

// 调用 C++ DLL 中定义的方法。

bgP.checkValid();// 该方法回调 java 中的 backProcess 方法,java::checkValid->c++::checkValid->java::backProcess

bgP.processData(bgP);

bgP.processGarbage(array);

// C++ DLL 改变了该变量

System.out.println("number 现在的值是: " + bgP.num);

}

}

2. 生成 C++ 的头文件(javah 命令生成,用javap –s –p [类全名] 命令查看java 方法签名)

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

#include "jni.h"

/* Header for class org_jm_jni_BackgroundProcess */

#ifndef _Included_org_jm_jni_BackgroundProcess

#define _Included_org_jm_jni_BackgroundProcess

#ifdef __cplusplus

extern "C" {

#endif

/*

* Class: org_jm_jni_BackgroundProcess

* Method: checkValid

* Signature: ()Z

*/

JNIEXPORT jboolean JNICALL Java_org_jm_jni_BackgroundProcess_checkValid

(JNIEnv *, jobject);

/*

* Class: org_jm_jni_BackgroundProcess

* Method: processData

* Signature: (Lorg/jm/jni/BackgroundProcess;)V

*/

JNIEXPORT void JNICALL Java_org_jm_jni_BackgroundProcess_processData

(JNIEnv *, jobject, jobject);

/*

* Class: org_jm_jni_BackgroundProcess

* Method: processGarbage

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

*/

JNIEXPORT void JNICALL Java_org_jm_jni_BackgroundProcess_processGarbage

(JNIEnv *, jobject, jobjectArray);

#ifdef __cplusplus

}

#endif

#endif

    这里JNIEXPORTJNICALL都是JNI的关键字,表示此函数是要被JNI调用的。例如jint是以JNI为中介使JAVAint类型与本地的int沟通的一种类型,我们可以视而不见,就当做int使用。函数的名称是JAVA_再加上java程序的package路径再加函数名组成的。参数中,我们也只需要关心在JAVA程序中存在的参数,至于JNIEnv*jclass我们一般没有必要去碰它。

3. 开发 C++ DLL 的原文件 (记得要加入 jni.h jni_md.h 两个文件)

发布 DLL 文件, 我是配置了 path 环境变量

#include "org_jm_jni_BackgroundProcess.h"

#include <iostream.h>

#include <windows.h>

#include "string.h"

char* jstringTostring(JNIEnv* env, jstring jstr)

{

char* rtn = NULL;

jclass clsstring = env->FindClass("java/lang/String");

jstring strencode = env->NewStringUTF("utf-8");

jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");

jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);

jsize alen = env->GetArrayLength(barr);

jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);

if (alen > 0)

{

rtn = (char*)malloc(alen + 1);

memcpy(rtn, ba, alen);

rtn[alen] = 0;

}

env->ReleaseByteArrayElements(barr, ba, 0);

return rtn;

}

//char* to jstring

jstring stoJstring(JNIEnv* env, const char* pat)

{

jclass strClass = env->FindClass("Ljava/lang/String;");

抱歉!评论已关闭.