使用RegisterNatives注册原生代码
在Android开发本地代码时,有两种方式,一种是使用javah生成头文件,然后编辑源代码,另一种不用生成头文件,直接编辑代码后,使用RegisterNatives方法进行注册,下面是一个Demo:
Java代码:
- package com.example.jnitest;
- public class TestJni {
- static {
- System.loadLibrary("Hello");
- }
- // static method
- public static native String test();
- // member method
- public native String test2();
- }
这里定义了两个native方法,test是静态方法,test2是成员方法。
使用C++实现两个方法:
- static jstring test(JNIEnv *env, jclass clz)
- {
- LOGD("Hello1");
- return env->NewStringUTF("Hello1");
- }
- static jstring test2(JNIEnv *env, jobject obj)
- {
- LOGD("Hello2");
- return env->NewStringUTF("Hello2");
- }
实现了之后,需要注册两个方法
第一步:定义数据结构:
- // register methods:
-
JNINativeMethod内部数据结构
-
typedef struct {
const char* name;
const char* signature;
void* fnPtr;
} JNINativeMethod;第一个变量name是Java中函数的名字。
第二个变量signature,用字符串是描述了函数的参数和返回值
第三个变量fnPtr是函数指针,指向C函数。
- static JNINativeMethod methods[] = {
- {"test", "()Ljava/lang/String;", (void*) &test},
- {"test2", "()Ljava/lang/String;", (void*) &test2}
- };
签名或者用javap生成
第二步:在JNI_OnLoad方法中,对方法进行注册:
- int jniRegisterNativeMethods(JNIEnv* env,
- const char* className,
- const JNINativeMethod* gMethods,
- int numMethods)
- {
- jclass clazz;
- int tmp;
- LOGD("Registering %s natives\n", className);
- clazz = env->FindClass(className);
- if (clazz == NULL) {
- LOGD("Native registration unable to find class '%s'\n", className);
- return -1;
- }
- if ((tmp=env->RegisterNatives(clazz, gMethods, numMethods)) < 0) { //底层注册地方
- LOGD("RegisterNatives failed for '%s', %d\n", className, tmp);
- return -1;
- }
- return 0;
- }
- //修改的方法
- int registerNativeMethods(JNIEnv *env) { //registerNativeMethods作为外在接口,调用jniRegisterNativeMethods
- return jniRegisterNativeMethods(env, "com/example/jnitest/TestJni", methods, sizeof(methods) / sizeof(methods[0]));
- }
- JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { //JNI_OnLoad 调用 registerNativeMethods
- JNIEnv* env = NULL;
- jint result = JNI_ERR;
- if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
- return result;
- }
- if (registerNativeMethods(env) != JNI_OK) {
- return -1;
- }
- result = JNI_VERSION_1_4;
- LOGD("jni load start: %d", result);
- return result;
- }
Android.mk:
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_CFLAGS := -D__STDC_CONSTANT_MACROS
- LOCAL_LDLIBS += -lc -lm -llog
- LOCAL_SHARED_LIBRARIES += liblog libcutils libnativehelper
- LOCAL_MODULE := Hello