那些鼓吹碎片化学习的人,登上了高楼,撤掉了梯子,然后对楼下众人说道:我们就是这样飞上来的。 真正重要的收获,往往都来自持续艰难的思考。
Native 方法的静态注册
NDK 开发中,通过 javah -jni 命令生成的包含 JNI 的头文件,接口的命名方式一般是: Java_<PackageName>_<ClassName>_<MethodName> 。
程序执行时系统会根据这种命名规则来调用对应的 Native 方法,这种注册方式称之为静态注册。
package com.haohao.framework;
public class NDKFramework {
private native int native_CreateFramework(String packageName);
private native void native_DestroyFramework();
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_haohao_framework_NDKFramework */
#ifndef _Included_com_haohao_framework_NDKFramework
#define _Included_com_haohao_framework_NDKFramework
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_haohao_framework_NDKFramework
* Method: native_CreateFramework
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL Java_com_haohao_framework_NDKFramework_native_1CreateFramework
(JNIEnv *, jobject, jstring);
/*
* Class: com_haohao_framework_NDKFramework
* Method: native_DestroyFramework
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_haohao_framework_NDKFramework_native_1DestroyFramework
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
静态注册方式的优点:方便简单,IDE (高版本 AndroidStudio)就可以自动帮你完成;缺点:若 Native 方法名字过长,可读性差,由于命名规则的限制,不能灵活改变。
Native 方法的动态注册
由于静态注册存在命名局限性,生产环境中一般不采用静态注册的方式。动态注册的优点是可以自由命名 Native 方法,缺点是如果 Native 方法过多,操作比较麻烦。
动态注册的时机是在加载函数库(.a 或 .so)的时候进行注册,即在 JNI_OnLoad 方法里进行注册。
重新命名后的 Native 方法:
#include <jni.h>
#include <string>
#define CLASS_NAME_NDK_FRAMEWORK "com/haohao/framework/NDKFramework"
extern "C"
JNIEXPORT jint JNICALL
CreateFramework(JNIEnv *env, jobject instance, jstring jPackageName)
{
LOGCATE("native_CreateFramework");
jint jRet = JNI_ERR;
const char *packageName = env->GetStringUTFChars(jPackageName, 0);
//if(NDKFramework::CreateFramework(packageName) != NULL)
// jRet = JNI_OK;
env->ReleaseStringUTFChars(jPackageName, packageName);
return jRet;
}
extern "C"
JNIEXPORT void JNICALL
DestroyFramework(JNIEnv *env, jobject instance)
{
LOGCATE("native_DestroyFramework");
//NDKFramework::DestroyFramework();
}
定义 Native 方法数组:
//{"Java 方法名", "JNI 签名", "重命名的 Native 方法"}
static JNINativeMethod g_NDKFrameMethods[] = {
{ "native_CreateFramework", "(Ljava/lang/String;)I", (void *)CreateFramework},
{ "native_DestroyFramework", "()V", (void *)DestroyFramework}
};
//定义注册函数
static int RegisterNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* methods, int methodNum)
{
LOGCATE("RegisterNativeMethods");
jclass clazz = env->FindClass(className);
if (clazz == NULL)
{
return JNI_FALSE;
}
if (env->RegisterNatives(clazz, methods, methodNum) < 0)
{
return JNI_FALSE;
}
return JNI_TRUE;
}
在 JNI_OnLoad 方法里进行注册:
extern "C" jint JNI_OnLoad(JavaVM *jvm, void *p)
{
LOGCATE("================ JNI_OnLoad ================");
jint jniRet = JNI_ERR;
JNIEnv *env = NULL;
if (jvm->GetEnv((void **)(&env), JNI_VERSION_1_6) != JNI_OK)
return jniRet;
jint regRet = RegisterNativeMethods(env, CLASS_NAME_NDK_FRAMEWORK, g_NDKFrameMethods, sizeof(g_NDKFrameMethods) /
sizeof(g_NDKFrameMethods[0]));
if(regRet != JNI_TRUE)
return JNI_ERR;
return JNI_VERSION_1_6;
}
以上 3 步便可实现动态注册。
-- END --