• android - jni (native) 接口


    一、概述

    android有两个世界,一个世界在app,jvm java/koltin, 另一个世界在linux c/c++/rust。 跨过了jni 就是另一个世界。
    jni 的全称是 java native interface,分为java部分和c 部分。 java 部分就是关键字native 开头的这些。c部分写在c代码里,打包成so 给java 调用。

    二、jni 的样板代码

    jni的样板代码其实也很简单,就分两块 java 调c。 和c 回调java。

    2.1、样板代码

    #include 
    #include 
    #include 
    #include "log.h"
    
    
    static JavaVM *local_jvm = NULL;
    static jclass local_jni_connector_class = NULL;
    
    static gboolean attachThreadToJvm(JNIEnv **env) {
        gboolean attached = FALSE;
        int rs2 = 0;
        int rs1 = (*local_jvm)->GetEnv(local_jvm, (void **) env, JNI_VERSION_1_6);
        switch (rs1) {
            case JNI_OK:
                break;
            case JNI_EDETACHED:
                rs2 = (*local_jvm)->AttachCurrentThread(local_jvm, env, NULL);
                if (rs2 != JNI_OK) {
                    LOG_DEBUG("ERROR: Could not attach current thread to local_jvm.");
                } else {
                    attached = TRUE;
                }
                break;
        }
        return attached;
    }
    
    static void detachThreadFromJvm() {
        (*local_jvm)->DetachCurrentThread(local_jvm);
    }
    
    static gboolean jvmAndMethodReferences(JNIEnv *env) {
        // Get a reference to the JVM to get JNIEnv from in (other) threads.
        if (local_jvm != NULL){
            return TRUE;
        }
        jint rs = (*env)->GetJavaVM(env, &local_jvm);
        if (rs != JNI_OK) {
            LOG_DEBUG("ERROR: Could not obtain local_jvm reference.");
            return FALSE;
        }
    
        jclass local_class = (*env)->FindClass(env, "com/ruijie/est/client/SpiceCommunicator");
        local_jni_connector_class = (jclass) ((*env)->NewGlobalRef(env, local_class));
        return TRUE;
    }
    
    

    2.2、简单的接口代码示例

    static jmethodID jni_auth_callback = NULL;
    
    
    static void registerJavaCallback(JNIEnv *env){
        jvmAndMethodReferences(env);
        jni_auth_callback = (*env)->GetStaticMethodID(env, local_jni_connector_class, "onXxxAuthCallback","(I)V");
    }
    
    /*
     * 授权回调
     */
    static void uiAuthCallback(int code){
        LOG_DEBUG("uiAuthCallback");
        JNIEnv * env;
        gboolean attached = attachThreadToJvm(&env);
        (*env)->CallStaticVoidMethod(env, local_jni_connector_class, jni_auth_callback, code);
    
        if (attached) {
            detachThreadFromJvm();
        }
    }
    
    static void callback(EST_AUTH_WORK_STATE_EVENT_TYPE event_type, char *msg, void *context){
        LOG_DEBUG("uiAuthCallback %d ", event_type);
        uiAuthCallback(event_type);
    }
    
    
    /**
     * 初始化
     */
    JNIEXPORT void JNICALL
    Java_com_yy_xxx_client_SxCommunicator_xxxAuthInit(JNIEnv *env,
                                                             jobject cls,
                                                             jstring logPath){
        LOG_DEBUG("xxxAuthInit");
        registerJavaCallback(env);
        char *c_logPath=(*env)->GetStringUTFChars(env, logPath, NULL);
        LOG_DEBUG("xxxAuthInit %s", c_logPath);
        xxx_auth_init(c_logPath, callback, NULL);
        (*env)->ReleaseStringUTFChars(env, logPath, c_logPath);
    }
    
    
    JNIEXPORT void JNICALL
    Java_com_yy_xxx_client_SxCommunicator_xxxAuthRegisterStart(
            JNIEnv *env,
            jobject cls,
            jstring app_id,
            jint mode,
            jstring activation_code,
            jstring auth_server_addr,
            jstring auth_server_pwd,
            jstring domain,
            jstring key,
            jstring secret
            ){
                LOG_DEBUG("xxxAuthRegisterStart");
                int c_mode = mode;
                char *c_app_id = (*env)->GetStringUTFChars(env, app_id, NULL);
                char *c_activation_code = (*env)->GetStringUTFChars(env, activation_code, NULL);
                char *c_auth_server_addr=(*env)->GetStringUTFChars(env, auth_server_addr, NULL);
                char *c_auth_server_pwd=(*env)->GetStringUTFChars(env, auth_server_pwd, NULL);
                char *c_domain=(*env)->GetStringUTFChars(env, domain, NULL);
                char *c_key=(*env)->GetStringUTFChars(env, key, NULL);
                char *c_secret=(*env)->GetStringUTFChars(env, secret, NULL);
    
    			//调用c模块函数
                xxx_auth_register_start(c_app_id,
                                        c_mode,
                                        c_activation_code,
                                        c_auth_server_addr,
                                        c_auth_server_pwd,
                                        c_domain,
                                        c_key,
                                        c_secret);
    
    			//释放char*
                (*env)->ReleaseStringUTFChars(env, app_id, c_app_id);
                (*env)->ReleaseStringUTFChars(env, activation_code, c_activation_code);
                (*env)->ReleaseStringUTFChars(env, auth_server_addr, c_auth_server_addr);
                (*env)->ReleaseStringUTFChars(env, auth_server_pwd, c_auth_server_pwd);
                (*env)->ReleaseStringUTFChars(env, domain, c_domain);
                (*env)->ReleaseStringUTFChars(env, key, c_key);
                (*env)->ReleaseStringUTFChars(env, secret, c_secret);
    }
    
    JNIEXPORT void JNICALL
    Java_com_yy_xxx_client_SxCommunicator_xxxAuthRegisterStop(JNIEnv *env, jobject cls){
        LOG_DEBUG("xxxAuthRegisterStop");
        xxx_auth_register_stop();
    }
    
    

    2.3、业务代码对应的java 层jni

    class SxCommunicator{
    
        public native void xxxAuthInit(String logPath);
        
        public native void xxxAuthRegisterStart(
                String app_id,
                int mode,
                String activation_code,
                String auth_server_addr,
                String auth_server_pwd,
                String domain,
                String key,
                String secret);
                
        public native void xxxAuthRegisterStop();
    
        private static void onXxxAuthCallback(int code) {
            Logger.i(TAG, "onAuthCallback code=" + code);
        }
    
    
    }
    

    三、说明

    上文示例代码是,一个简单的鉴权模块的jni。
    其中:

    • 1、xxxAuthInit 函数进行了基础的模块初始化,初始化的时候把c回掉java的回调函数onXxxAuthCallback注册到c 层变量:jni_auth_callback 中。鉴权模块自己的回调uiAuthCallback传给鉴权模块c的代码。当uiAuthCallback被调用时也去调用java层的回调函数
    • 2、xxxAuthRegisterStart 函数进行了启动授权,传到鉴权模块C中,进行一系列逻辑触发回调函数
    • 3、xxxAuthRegisterStop java业务退出的时候调用。

    该示例中涉及了,java调c, c调java。 java的int string类型到 c 的int,char*数据类型的转换与回收(string类型回收)。
    【注】样板代码中的jbool 是glib的类型,可以直接改成int 或者unsigned char

  • 相关阅读:
    最新接口自动化面试题
    Worthington丨Worthington 磷酸酶,碱性
    终于有人把HDFS架构和读写流程讲明白了
    python学习之【深拷贝】
    队列--二叉树层序遍历
    基于云的移动设备管理(MDM)解决方案
    聊聊 C# 中的多态底层 (虚方法调用) 是怎么玩的
    python小tips
    用于Python降维的线性判别分析
    Golang 的锁机制
  • 原文地址:https://blog.csdn.net/lckj686/article/details/127126522