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 <jni.h>
#include <string.h>
#include <android/log.h>
#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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中,当Fragment需要调用JNI接口函数时,可以通过以下步骤实现: 1. 首先,在Java中创建一个JNI接口类并使用static类型,以便在不同的Fragment中简便地调用JNI函数。 2. 在JNI接口类中,定义所需的JNI函数,并使用native关键字标记这些函数,表示它们将在C / C++中实现。 3. 在C / C++中,实现JNI函数的功能。可以使用CMakeLists文件来配置和构建通过JNI调用的C / C++代码。 4. 在Java中,通过调用JNI接口类的静态方法来调用JNI函数。根据具体的需求,可以传递参数给JNI函数,并将其结果返回到Java中。 5. 在Fragment中,根据需要处理JNI函数的返回结果,并进行相应的操作。例如,可以将返回的byte数组转换为String类型,并在界面上显示相应的数据。 通过以上步骤,Android Fragment可以成功调用JNI接口函数,并实现与C / C++代码的交互。这样可以在APP开发中使用JNI调用C / C的基本架构,并为开发者提供有益的参考借鉴。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [《“透视”个人大数据》项目开发小记 --(三)Android APP 开发(3)使用jni调用c++/c 应用实例浅析](https://blog.csdn.net/m0_69502339/article/details/127995223)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [自己平时做的android相关的总结](https://download.csdn.net/download/mars_cheng/8724303)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值