编译so库文件
Android Studio提供了非常完善的cpp代码编译环境,所以我们只需要新建一个native C++项目。

然后添加我们自己需要的cpp文件

实际上Android Studio会自动帮我们在build.gradle中配置好CMakeLists文件路径。接着在CMakeLists中通过addLibrary添加库文件。
最后,只需要一键build,就会生成不同CPU平台架构下的so库文件,并打包到apk中。我们可以通过build--analyze apk来解压缩apk包,看到里面的内容:

添加so依赖
上面讲了打包生成so的方法,接下来只需要将所有的so文件复制到libs文件目录下。
然后在build.gradle中声明jni库的目录:

这里需要注意的是,native调用的方法名,类名,包名必须跟so文件中的一模一样。

有个最简单的方法,就是写一个NativeHelper类,把需要的内容都写进去,这样就可以直接复制到别的应用项目中使用。

最后看一下我们定义的这个native方法:
#include <jni.h>
#include <string>
extern "C" JNIEXPORT jstring JNICALL
Java_com_one_nativelib_NativeHelper_getJNIString(JNIEnv *env, jobject thiz) {
std::string str = "123456";
return env->NewStringUTF(str.c_str());
}
可以看到方法名的格式是Java_[包名][类名][方法名]
native方法的动态与静态注册
前面介绍的jni方法,都是静态注册的方法,cpp中的方法名必须严格按照Java_[包名][类名][方法名]格式。
实际上还有一种方法,就是建立一个函数映射表,所有jni方法都通过函数映射表去查找。
我们看下之前提到过的AlarmManager中的native方法:
static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"init", "()J", (void*)android_server_AlarmManagerService_init},
{"close", "(J)V", (void*)android_server_AlarmManagerService_close},
{"set", "(JIJJ)I", (void*)android_server_AlarmManagerService_set},
{"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm},
{"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime},
{"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
{"getNextAlarm", "(JI)J", (void*)android_server_AlarmManagerService_getNextAlarm},
};
int register_android_server_AlarmManagerService(JNIEnv* env)
{
return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
sMethods, NELEM(sMethods));
}
这里维护了一个数组,是java方法和native方法的一一对应关系。然后通过jniRegisterNativeMethods方法进行注册,这个方法定义在JNIHelp中:
extern "C" int jniRegisterNativeMethods(C_JNIEnv* env, const char* className,
const JNINativeMethod* gMethods, int numMethods)
{
JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
ALOGV("Registering %s's %d native methods...", className, numMethods);
scoped_local_ref<jclass> c(env, findClass(env, className));
if (c.get() == NULL) {
char* tmp;
const char* msg;
if (asprintf(&tmp,
"Native registration unable to find class '%s'; aborting...",
className) == -1) {
// Allocation failed, print default warning.
msg = "Native registration unable to find class; aborting...";
} else {
msg = tmp;
}
e->FatalError(msg);
}
if ((*env)->RegisterNatives(e, c.get(), gMethods, numMethods) < 0) {
char* tmp;
const char* msg;
if (asprintf(&tmp, "RegisterNatives failed for '%s'; aborting...", className) == -1) {
// Allocation failed, print default warning.
msg = "RegisterNatives failed; aborting...";
} else {
msg = tmp;
}
e->FatalError(msg);
}
return 0;
}
在apk中,也可以模仿这种方式,实现动态注册。
extern "C" {
jstring stringFromJNI(JNIEnv *env, jobject instance) {
std::string str = "654321";
return env->NewStringUTF(str.c_str());
}
}
static const JNINativeMethod sMethods[] = {
/* name, signature, funcPtr */
{"stringFromJNI", "()Ljava/lang/String;", (void*)stringFromJNI}
};
extern "C" jint jniRegisterNativeMethods(JNIEnv* env)
{
jclass clazz = env->FindClass("com/one/nativelib/NativeHelper");
if (clazz == NULL) {
return JNI_ERR;
}
return env->RegisterNatives(clazz, sMethods, sizeof(sMethods) / sizeof(sMethods[0]));
}
jint JNI_OnLoad(JavaVM *vm, void * reserverd) {
JNIEnv *env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK) {
return result;
}
result = jniRegisterNativeMethods(env);
return JNI_VERSION_1_6;
}
网友评论