Android NDK开发 JNI 基础

在android 系统开发中 ndk开发是很重要的内容。ndk开发中 jni 是基础。

目录

一.什么是JNI

[二. 如何使用JNI](#二. 如何使用JNI)

[1.Java 代码如何调用 c/c++ 代码](#1.Java 代码如何调用 c/c++ 代码)

[2. c/c++如何调用 java 函数](#2. c/c++如何调用 java 函数)


一. 什么是JNI

JNI------Java Native Interface,它是Java平台的一个特性(并不是Android系统特有的)。其实主要是定义了一些JNI函数,让开发者可以通过调用这些函数实现Java代码调用C/C++的代码,C/C++的代码也可以调用Java的代码,这样就可以发挥各个语言的特点了。

二. 如何使用JNI

一般情况下我们首先是将写好的C/C++代码编译成对应平台的动态库(windows一般是dll文件,linux一般是so文件等),这里我们是针对Android平台,所以只讨论so库。由于JNI编程支持C和C++编程,这里我们的栗子都是使用C++,对于C的版本可能会有些差异,但是主要的内容还是一致的。我们从两方面来介绍JNI, 一是 JAVA代码如何调用 C/C++ 代码。 一是 C/C++ 代码如何调用java代码。

1.Java 代码如何调用 c/c++ 代码

这里我们开发工具使用 android studio, android studio自带单步调试功能。能清晰的跟踪代码调用流程。Java 代码调用 c/c++代码有两种方式,静态注册和 动态注册。

静态注册,当我们在Android studio "new project "选 "native c++", 一路next, 创建出的这个例子 用的是 静态注册。 静态注册的优点是比动态注册方便一点, 缺点也明显, 当native方法比较多时, 写对应的jni c++ 方法会比较繁琐。

java 文件的写法

cpp 复制代码
    static {
        System.loadLibrary("myapplication"); 
    }

    public native String stringFromJNI();

c++ 这边的写法

cpp 复制代码
extern "C" JNIEXPORT jstring JNICALL
Java_com_unionpower_myapplication_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

动态注册 的关键是 jni_onload函数, 当我们使用System.loadLibarary()方法加载so库的时候,Java虚拟机就会找到这个函数并调用该函数,在该函数中做一些初始化的动作。

cpp 复制代码
static JNINativeMethod nativeMethods[] = {
        {"_init", "()Z", (void *) init},
        {"_sendMcuData", "([B)Z", (void*) sendMcuData},
        {"_getMcuData", "(II)[B", (void*) getMcuData},
        {"_deinit", "()Z",(void *) deinit},
};


JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
//    JNIEnv *env = AndroidRuntime::getJNIEnv();// 在android 系统中通过AndroidRuntiem获得JNIEnv
//    AndroidRuntime::registerNativeMethods(env, MCU_SERVER_NAME_FOR_APP, nativeMethods, NELEM(nativeMethods));
//    return JNI_VERSION_1_4;
    JNIEnv *env; //在android studio 中通过vm ->getEnv 得到JNIEnv
    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
        return -1;
    }
    jclass clz = env->FindClass(MCU_SERVER_NAME_FOR_APP);
    env->RegisterNatives(clz, nativeMethods, sizeof(nativeMethods)/sizeof(nativeMethods[0]));
    return JNI_VERSION_1_4;
}
cpp 复制代码
typedef struct {
    const char* name;
    const char* signature;
    void*       fnPtr;
} JNINativeMethod;
2. c/c++如何调用 java 函数

c/c++ 调用 java 的方式 是先得到类的字节码,

cpp 复制代码
jclass clazz = env->GetObjectClass(obj);
gClassInfo.autoImage = (jclass) env->NewGlobalRef(clazz);

获取方法ID,

cpp 复制代码
gClassInfo.callback = env->GetStaticMethodID(clazz, "callbackFromNative", "(I[BI)V");
复制代码
反射的方式调用到 java 里的方法
cpp 复制代码
env->CallStaticVoidMethod(gClassInfo.autoImage, gClassInfo.callback, BUSINESS_MCU_UPDATE, data, BUSINESS_MCU_UPDATE);

java 文件也要有对应的方法

cpp 复制代码
    private static void callbackFromNative(int msg, byte[] data, int value) {}

在android studio中单步调试 JNI 时, 如果遇到 socket 这类错误, 可以 选 build->clean project, 再重新运行即可。

相关推荐
callJJ20 分钟前
Spring Data Redis 两种编程模型详解:同步 vs 响应式
java·spring boot·redis·python·spring
空中海26 分钟前
安卓逆向03. 动态调试、抓包分析与 Frida Hook
android
wbs_scy1 小时前
Linux线程同步与互斥(三):线程同步深度解析之POSIX 信号量与环形队列生产者消费者模型,从原理到源码彻底吃透
java·开发语言
一起搞IT吧2 小时前
相机Camera日志实例分析之二十:相机Camx【照片后置4800/5000/6400万拍照】单帧流程日志详解
android·嵌入式硬件·数码相机·智能手机
jinanwuhuaguo3 小时前
(第三十三篇)五月的文明奠基:OpenClaw 2026.5.2版本的文明级解读
android·java·开发语言·人工智能·github·拓扑学·openclaw
xmjd msup3 小时前
spring security 超详细使用教程(接入springboot、前后端分离)
java·spring boot·spring
952364 小时前
SpringBoot统一功能处理
java·spring boot·后端
Lyyaoo.4 小时前
优惠券秒杀业务分析
java·开发语言
消失的旧时光-19434 小时前
统一并发模型:线程、Reactor、协程本质是一件事(从线程到协程 · 第6篇·终章)
java·python·算法
勿忘初心12214 小时前
Java 国密 SM4 加密工具类实战(Hutool + BouncyCastle)|企业级数据加密 + 兼容 JDK8
java·数据安全·数据加密·后端开发·企业级开发·国密 sm4