JNI代码两种注册编写方式

来源:互联网 发布:javascript数组定义 编辑:程序博客网 时间:2024/06/07 05:02

样例java类
HelloJni.java

package com.example.test;public class HelloJni {    public native String  stringFromJNI();    static {        System.loadLibrary("helloJni");    }}

方法一:静态注册

遵守JNI标准规函数命名方式, JNI中方法命名为 Java_包名_类名_方法名, 可以使用javah生成签名头文件, 靠这种方式实现Native方法与JNI方法之间的映射关系,即应用直接与框架层进行交互,这种规范常用与应用开发;

javah -jni 自动生成.h文件

<project>\bin\classes目录下执行

javah -classpath .;<sdkPath>\sdk\platforms\android-19\android.jar -jni com.pachong.test.Hello(pakageName.className)

即可生成对应的.h头文件,在这个头文件中就有我们需要实现的c&c++方法了,这里加上<sdkPath>\sdk\platforms\android-19\android.jar是因为我们的类中有引用到系统相关的一些类或方法需要加上android.jar才能生成对应.h文件。
这里写图片描述
com_example_test_HelloJni.h

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

在项目根目录下新建jni文件夹,将刚刚生成的.h文件拷贝到这个目录下,同时新建一个对应的.cpp文件和Android.mk文件用于编译生成so文件。

com_example_test_HelloJni.cpp

/* DO NOT EDIT THIS FILE - it is machine generated */#include "com_example_test_HelloJni.h"/* Header for class com_example_test_HelloJni *//* * Class:     com_example_test_HelloJni * Method:    stringFromJNI * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_example_test_HelloJni_stringFromJNI  (JNIEnv *, jobject) {    return env->NewStringUTF("Hello from JNI !");}

Android.mk

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := libhelloJniLOCAL_SRC_FILES := com_example_test_HelloJni.cppinclude $(BUILD_SHARED_LIBRARY)

注:LOCAL_MODULE := libhelloJni要和System.loadLibrary(“helloJni”);对应起来。
这里写图片描述

javap -s -p 查看函数签名

-s: 显示签名(只显示public类型的签名) -p:显示所有函数、成员变量的签名

javap -classpath .;<sdkPath>\sdk\platforms\android-19\android.jar -s -p com.pachong.test.Hello(pakageName.className)

(注:<sdkPath>\sdk\platforms\android-19\android.jar是可选项),通过签名我们就可以在写jni相关的代码时写入相应的签名即可。
这里写图片描述

方法二:动态注册

这是Android自定义的一种规范, 应用框架层采用该规范, 即应用框架层 与 框架层 进行交互, 底层源码开发多使用该规范;

动态注册是通过调用JNI_OnLoad方法,去注册相关类的方法来实现的,来看下具体的实现。
customHelloJni.cpp

#include <jni.h>static jstring  hello(JNIEnv* evn, jobject thiz) {    return env->NewStringUTF("Hello from JNI !");}//需要调用实现JNI的类static const char* classPathName = "com/example/test/HelloJni";//绑定相应的方法static JNINativeMethod methods[] = {        {"stringFromJNI", "()Ljava/lang/String",(void*)hello},};//注册指定类的相关方法static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods, int numMethods) {    jclass clazz;    clazz = env->FindClass(className);    if (class == NULL) {        return JNI_FALSE;    }    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {        return JNI_FALSE;    }    return JNI_TRUE;}static int registerNatives(JNIEnv* env) {    if (!registerNativeMethods(env, classPathName, methods, sizeof(methods)/sizeof(methods[0]))) {        return JNI_FALSE;    }    return JNI_TRUE;}//注册JNI方法入口jint JNI_OnLoad(JavaVM* vm, void* reserved) {    JNIEnv* env = NULL;    jint result = -1;    if (vm->GetEnv(&env, JNI_VERSION_1_4) != JNI_OK) {        return result;    }    if (registerNatives(env) != JNI_TRUE) {        return result;    }    result = JNI_VERSION_1_4;    return result;}

通过上面的代码实现,我们知道动态注册比静态注册在实现函数命名上更加自由,我们不需要按照JNI的那套标准规则来命名相关方法,只需要在绑定方法函数时与Java类中方法对应即可,即JNINativeMethod数组中对应相应的方法关系即可。

原创粉丝点击