美文网首页
2020-03-26-Android的jni调用

2020-03-26-Android的jni调用

作者: 耿望 | 来源:发表于2020-03-28 19:22 被阅读0次

编译so库文件

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


1.png

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


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

添加so依赖

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


6.png

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


4.png
有个最简单的方法,就是写一个NativeHelper类,把需要的内容都写进去,这样就可以直接复制到别的应用项目中使用。
5.png
最后看一下我们定义的这个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;
}

参考:

向您的项目添加 C 和 C++ 代码
JNI 静态注册和动态注册
Android NDK 从入门到精通(汇总篇)

相关文章

网友评论

      本文标题:2020-03-26-Android的jni调用

      本文链接:https://www.haomeiwen.com/subject/apsquhtx.html