android jni动态注册实例,Android JNI的动态注册

我们知道Androd 使用JNI的注册方法包括两个,静态注册和动态注册。

静态注册就是通过javah命令生成.h文件,然后实现声明的函数即可,但此类函数的函数名都比较长:Java+包名+类名+方法名。而动态注册则没有这一限制。先以下面这个例子进行说明,例子中的jni函数参考了Android M源码。

我们新建一个的Android工程,包含一个默认的MainActivity。代码如下:

package com.example.jnidynamic;

import android.app.Activity;

import android.os.Bundle;

import android.widget.TextView;

public class MainActivity extends Activity {

private TextView mTextView;

// 声明一个jni函数,待会去实现

private native String getStringFromJni();

static {

System.loadLibrary("myJNI"); // 加载库,待会会用NDK去生成该库

}

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mTextView = (TextView)findViewById(R.id.my_text_view);

mTextView.setText(getStringFromJni()); // 原理很简单,显示一个从JNI层返回的字符串

}

}

右键工程, Android tools -> Add native …,库的名字填写上面的myJNI即可。eclipse要先配置好NDK,这里不再说明。其实也可以不用在eclipse配置NDK,自己用NDK命令去编译也可以。

myJNI.cpp

#include

#include

#include

#include

#include

#include

/* 定义了一些宏,这里用来输出Log用的,JNI层输出Android LOG, JNI层输出LOG可以参考我以前写的,LOG_TAG是tag */

#ifndef LOG

#define LOG_TAG "myJNI"

#define ALOGD(...) \

__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__);

#define ALOGE(...) \

__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__);

#define ALOGV(...) \

__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__);

#endif LOG

#ifndef NELEM

# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))

#endif

// c函数

jstring native_hello(JNIEnv* env, jobject thiz)

{

return env ->NewStringUTF("hello world from jni~");

}

// java类的位置

static const char *classPathName = "com/example/jnidynamic/MainActivity";

// 映射表,这里将我们java函数和c函数对应起来

static JNINativeMethod gMethods[] = {

{"getStringFromJni", "()Ljava/lang/String;", (void*)native_hello},

};

/* 下面的可以说,基本上是模板了,以后直接copy就行 */

static int jniRegisterNativeMethods(JNIEnv* env, const char* className,

JNINativeMethod* gMethods, int numMethods)

{

jclass clazz;

clazz = env->FindClass(className);

if (clazz == NULL) {

ALOGE("Native registration unable to find class '%s'", className);

return JNI_FALSE;

}

if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {

ALOGE("RegisterNatives failed for '%s'", className);

return JNI_FALSE;

}

return JNI_TRUE;

}

static int register_my_jni_methods(JNIEnv* env) {

return jniRegisterNativeMethods(env, classPathName, gMethods, NELEM(gMethods));

}

// 在我们load该so库的时候,JNI_OnLoad将会自动被调用,来注册JNI函数

jint JNI_OnLoad(JavaVM* vm, void*)

{

JNIEnv* env = NULL;

jint result = -1;

if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {

ALOGE("ERROR: GetEnv failed\n");

goto bail;

}

assert(env != NULL);

if (register_my_jni_methods(env) < 0) {

ALOGE("ERROR: native registration failed\n");

goto bail;

}

/* success -- return valid version number */

ALOGE("SUCCESS: native registration successed\n");

result = JNI_VERSION_1_4;

bail:

return result;

}

Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog

LOCAL_MODULE := myJNI

LOCAL_SRC_FILES := myJNI.cpp

include $(BUILD_SHARED_LIBRARY)

其实这里的重点是JNINativeMethod这里结构体

typedef struct {

const char* name; //Java中函数的名字

const char* signature; //用字符串描述的函数的参数和返回值

void* fnPtr; //指向C函数的函数指针

} JNINativeMethod;

这里面我觉得比较难书写的是signature, 反映的是函数的参数和返回值。括号内()为参数,最后为返回值。

具体的每一个字符的对应关系如下

字符

Java类型

C类型

V

void

void

Z

jboolean

boolean

I

jint

int

J

jlong

long

D

jdouble

double

F

jfloat

float

B

jbyte

byte

C

jchar

char

S

jshort

short

[I

jintArray

int[]

[F

jfloatArray

float[]

[B

jbyteArray

byte[]

[C

jcharArray

char[]

[S

jshortArray

short[]

[D

jdoubleArray

double[]

[J

jlongArray

long[]

[Z

jbooleanArray

boolean[]

上面的都是基本类型。如果Java函数的参数是java的某个类,则以”L”开头,以”;”结尾,中间是用”/” 隔开的包名和类名。而其对应的C函数名的参数则统一为jobject。但String类是个例外,其对应的类为jstring。

举下面几个例子:

字符

Java类型

C类型

Ljava/lang/String;

String

jstring

Ljava/net/Socket;

Socket

jobject

L包名/类名;

类名

jobject

如果java类是一个内部类的话,则用$作为类名间的分隔符。

例如 :

“(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z”

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值