Android JNI开发解析

1.JNI简介

JNI的含义:Java native interface,是为了方便Java调用C、C++本地代码所封装的一层接口

2.JavaVM和JNIEnv

JNI定义了两个关键数据结构,“JavaVM”和“JNIEnv”。这两者基本上都是指向函数表指针的指针。(在C ++版本中,它们是带有指向函数表的指针的类,以及用于指向表中的每个JNI函数的成员函数。)

JavaVM提供“调用接口”函数,允许您创建和销毁JavaVM的。理论上,每个进程可以有多个JavaVM,但Android只允许一个。

JNIEnv提供了大多数JNI功能。本地函数都接收JNIEnv作为第一个参数。

3.jclass,jmethodID和jfieldID

如果要从本机代码访问对象的字段,请执行以下操作:

  • 获取类的类对象引用 FindClass
  • 获取该字段的字段ID GetFieldID
  • 使用适当的内容获取字段的内容,例如 GetIntField

4.JNI的注册方式

JVM 查找 native 方法有两种方式:

  • 按照 JNI 规范的命名规则(静态注册)
  • 调用 JNI 提供的 RegisterNatives 函数,将本地函数注册到 JVM 中(动态注册)

4.1静态注册实现:

com_ad_jnidemo_JniUtils.h代码如下:
#ifndef _Included_com_ad_jnidemo_JniUtils
#define _Included_com_ad_jnidemo_JniUtils
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_ad_jnidemo_JniUtils
 * Method:    getJniString
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_ad_jnidemo_JniUtils_getJniString
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

注意:以上的com_ad_jnidemo_JniUtils.h文件是根据执行命令javah com.ad.jnidemo.JniUtils .java所生成的文件。

com_ad_jnidemo_JniUtils.cpp代码如下:
#include "com_ad_jnidemo_JniUtils.h"

JNIEXPORT jstring JNICALL Java_com_ad_jnidemo_JniUtils_getJniString
        (JNIEnv *env, jclass) {
    // new 一个字符串,返回Hello World
    return env -> NewStringUTF("Hello World From Jni");
}
Java调用实现, JniUtils.java代码如下:
public class JniUtils {

    static {
        System.loadLibrary("JNIUtils");
    }

	//native接口,将调用com_ad_jnidemo_JniUtils.cpp中的Java_com_ad_jnidemo_JniUtils_getJniString()方法
	//静态注册
    public static native String getJniString();
}

4.1动态注册实现:

com_ad_jnidemo_JniUtils.h代码不变,跟上面静态注册代码一样;
com_ad_jnidemo_JniUtils.cpp代码如下:
#include <assert.h>
#include "com_ad_jnidemo_JniUtils.h"

///////////////////////////////////////////////////////////////////////
/*
 * Static register
 */
JNIEXPORT jstring JNICALL Java_com_ad_jnidemo_JniUtils_getJniString
        (JNIEnv *env, jclass) {
    // new 一个字符串,返回Hello World
    return env -> NewStringUTF("Hello World From Static Reg Jni");
}

///////////////////////////////////////////////////////////////////////
/*
 * Dynamic register
 */
 
//步骤一:定义需要注册的java文件
#define JNIREG_CLASS "com/ad/jnidemo/JniUtils"

//步骤二:编写C++层的实现函数
jstring dynamic_reg_getJniString(JNIEnv* env, jobject thiz){
    return env -> NewStringUTF("Hello World From Dynamic Reg Jni");
}

//步骤三:方法对应表
//"getJniStringFromDynamicReg",注册java文件"com/ad/jnidemo/JniUtils"中的接口
//dynamic_reg_getJniString,C++层的实现函数
static JNINativeMethod gMethods[] = {
        {"getJniStringFromDynamicReg", "()Ljava/lang/String;", (void *) dynamic_reg_getJniString},
};

//步骤四:为某一个类注册本地方法,主要注册"com/ad/jnidemo/JniUtils"文件
static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods) {
    jclass clazz;
    clazz = (env)->FindClass( className);
    if (clazz == NULL) {
        return JNI_FALSE;
    }
    if ((env)->RegisterNatives(clazz, gMethods, numMethods) < 0) {
        return JNI_FALSE;
    }
    return JNI_TRUE;
}

//同步骤四,为所有类注册本地方法
static int registerNatives(JNIEnv* env) {
    return registerNativeMethods(env, JNIREG_CLASS, gMethods,sizeof(gMethods) / sizeof(gMethods[0]));
}

//步骤五:执行动态注册
/*
* System.loadLibrary("lib")时调用
* 如果成功返回JNI版本, 失败返回-1
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
    JNIEnv* env = NULL;
    jint result = -1;
    if (( vm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK)) {
        return -1;
    }
    assert(env != NULL);
    if (!registerNatives(env)) {//注册
        return -1;
    }

    result = JNI_VERSION_1_6;
    return result;
}

实现关键步骤,请参照代码注释中的步骤一、二、三、四、五。

Java调用实现, JniUtils.java代码如下:
package com.ad.jnidemo;

public class JniUtils {

    static {
        System.loadLibrary("JNIUtils");
    }

	//native接口,将调用com_ad_jnidemo_JniUtils.cpp中的Java_com_ad_jnidemo_JniUtils_getJniString()方法
	//静态注册
    public static native String getJniString();

	//动态注册接口
    public static native String getJniStringFromDynamicReg();
}

猜你喜欢

转载自blog.csdn.net/Sunxiaolin2016/article/details/89918581
今日推荐