---
title: "Unity跨语言编程精华：CSharp与Java、Native代码的链式调用实践"
author: "Perrin Yong"
author_profile: https://www.pystone.net/profile/
published_by: "Perrin Yong"
canonical: https://www.pystone.net/notes/unity-csharp-java-native-interop/
type: note
content_role: unspecified
visibility: public
id_stability: rename-stable
source_path: "10-计算机、信息技术与工程/02-编程语言与运行时/Unity跨语言编程精华：CSharp与Java、Native代码的链式调用实践.md"
content_hash: c960a11a682b4510f7e59b4076516aa60f114040a4b7ecd8e7b67de74897d2d5
knowledge_version: 224c990773de.5fa8af6e39fa
site_commit: 224c990773de166d23a886306577dd90379529ce
notes_commit: 5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a
---
本文深入剖析Unity中C#与Java/Native代码互调技术，详解JNI动态绑定、AndroidStudio插件工程配置及P/Invoke内存管理机制，提供链式调用实战案例（C#→Java→C++→Java）。涵盖JNIEnv线程绑定策略、JVM内存模型对跨语言调用的影响，帮助你打通Unity-Android原生层开发之路。

# Unity跨语言编程精华：CSharp与Java、Native代码的链式调用实践
* **JNI (Java Native Interface)** 是一种编程框架，使得 Java 代码可以与使用其他编程语言（例如 C、C++、汇编语言）编写的应用程序和库进行交互。

## Unity C#调用Java代码

#### 1. Java 代码
```java
package com.prin.myplugin;

import android.util.Log;

public class TestJavaClass {
    public static String myJavaMethod(String message) {
        Log.d("MyJavaClass", message);
        return "Response from Java: " + message;
    }

    public static int multiply(int a, int b) {
        return a * b;
    }
}

```

可以直接将Java代码放置在Unity工程的Android目录中： `Assets/Plugins/Android/`  。
也可以在Android Studio中将Java代码打成Jar/aar包后，再拷贝到 `Assets/Plugins/Android/` 中。

#### 2. Unity C# 代码
在 Unity 项目中创建一个新的 C# 脚本文件（例如 `TestCallJava.cs`），并编写如下代码：
```cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestCallJava : MonoBehaviour
{
    public void CallJava()
    {
        // 获取 UnityPlayer 类
        AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        // 获取当前活动
        AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
        // 调用自定义 Java 类的方法
        AndroidJavaClass myJavaClass = new AndroidJavaClass("com.prin.myplugin.TestJavaClass");

        // 调用 Java 静态方法并获取返回值
        string response = myJavaClass.CallStatic<string>("myJavaMethod", "Hello from Unity!");
        Debug.Log(response);

        // 调用 Java 静态方法 Multiply
        int res = myJavaClass.CallStatic<int>("Multiply", 3, 4);
        Debug.Log("Multiply result: " + res);
    }
}

```


## Unity C#调用Native代码
- **P/Invoke 声明**：在 C# 中使用 `[DllImport("library-name")]` 属性来声明外部的 C 函数，`library-name` 是不带前缀 `lib` 和后缀 `.so` 的库名。
- 参数传递: `Marshal` 通常用于处理非托管代码中的复杂数据类型，比如字符串、结构体、指针等，而基本数据类型的传递可以通过 P/Invoke 直接完成。
- **内存管理**：由于 Native 代码返回的字符串在堆上分配，需要在 C# 中调用相应的释放函数来释放内存，防止内存泄漏。


Native代码：
```cpp
#include <cstring>
#include <string>

extern "C" {
    const char* stringFromNative(const char* input) {
        std::string response = "Response from Native: ";
        response += input;
        char* result = new char[response.size() + 1];
        std::strcpy(result, response.c_str());
        return result;
    }

    void freeNativeString(const char* str) {
        delete[] str;
    }

    int add(int a, int b) {
        return a + b;
    }
}

```

CMAKE配置：
```cmake
cmake_minimum_required(VERSION 3.4.1)

add_library(experimental-native-lib SHARED experimental-native-lib.cpp)

find_library(log-lib log)

target_link_libraries(experimental-native-lib ${log-lib})

```

Android Studio中构建so代码后,放入Unity工程的 `Assets/Plugins/Android/` 目录下。

C#代码:
```cs
using System;
using System.Runtime.InteropServices;
using UnityEngine;

public class TestCallNative : MonoBehaviour
{
    // 使用 P/Invoke 声明 C++ 函数
    [DllImport("experimental-native-lib")]
    private static extern IntPtr stringFromNative(string input);

    [DllImport("experimental-native-lib")]
    private static extern void freeNativeString(IntPtr str);

    [DllImport("experimental-native-lib")]
    private static extern int add(int a, int b);

    public void CallNative()
    {
        Debug.Log("Call native----------------------------------------");

        IntPtr responsePtr = stringFromNative("Hello from Unity!");
        string response = Marshal.PtrToStringAnsi(responsePtr);
        Debug.Log(response);

        // 释放返回的指针
        freeNativeString(responsePtr);

        int c = add(3, 4);
        Debug.Log("native 3+4: " + c);
    }
}

```


## Java与Native代码互相调用
## 知识储备
### JVM 的底层实现

#### 1. 线程和调度

JVM 在启动时会创建多个线程，包括主线程、垃圾收集线程、编译线程等。每个 Java 线程都对应一个操作系统级别的线程。操作系统负责线程的创建、调度和销毁。

- **Java 线程**：在 Java 程序中，每个通过 `new Thread()` 创建的线程都是一个独立的线程，它们共享相同的内存空间。
- **操作系统线程**：Java 线程被映射为操作系统线程。操作系统负责管理这些线程，包括调度、上下文切换和优先级管理。
-
#### 2. 内存管理
JVM 的内存区域主要包括：
- **堆 (Heap)**：用于存储对象实例。垃圾收集器负责回收不再使用的对象。
- **栈 (Stack)**：每个线程都有自己的栈空间，用于存储局部变量和方法调用信息。
- **方法区 (Method Area)**：存储类信息、常量、静态变量等。
- **本地方法栈 (Native Method Stack)**：用于支持本地方法执行。
#### 3. JNI 的底层机制
JNI 是 Java 调用本地代码的接口，允许 Java 程序与本地应用程序和库进行交互。JNI 使得 Java 程序可以调用用 C/C++ 编写的代码，反之亦然。

### JNIEnv 和 JavaVM 的底层机制

#### 1. JNIEnv 的本质

`JNIEnv` 是一个指向函数表的指针，这些函数表定义了 JNI 提供的所有功能。`JNIEnv` 是线程私有的，每个线程都有一个独立的 `JNIEnv` 实例。

```java
struct JNIEnv {
    const struct JNINativeInterface* functions;
};

struct JNINativeInterface {
    // 定义了所有的 JNI 函数
    jint (*GetVersion)(JNIEnv *env);
    jclass (*FindClass)(JNIEnv *env, const char *name);
    jmethodID (*GetMethodID)(JNIEnv *env, jclass clazz, const char *name, const char *sig);
    // 其他函数省略
};

```
#### 2. JavaVM 的本质

`JavaVM` 是 JVM 实例的一个抽象表示，通常只有一个全局的 `JavaVM` 指针。`JavaVM` 提供了一些全局操作，比如创建和销毁 JVM，附加和分离线程等。

```java
struct JavaVM {
    const struct JNIInvokeInterface* functions;
};

struct JNIInvokeInterface {
    jint (*DestroyJavaVM)(JavaVM *vm);
    jint (*AttachCurrentThread)(JavaVM *vm, JNIEnv **p_env, void *thr_args);
    jint (*DetachCurrentThread)(JavaVM *vm);
    // 其他函数省略
};

```

#### 线程的附加和分离
Java 线程是由 JVM 管理的线程，用于并发执行任务。每个 Java 线程都有一个关联的 `JNIEnv` 指针，这是线程与 JVM 交互的接口。
Native 线程是由操作系统管理的线程，它们通常用来执行与平台相关的任务。Native 线程可以通过 JNI 与 JVM 进行交互。
`JNIEnv` 是一个指针，指向 JVM 提供的一组函数表，用于 Native 代码与 JVM 交互。每个 Java 线程都有一个关联的 `JNIEnv`，但 Native 线程默认情况下没有 `JNIEnv`。
当一个 Native 线程需要与 JVM 交互时，它需要首先附加到 JVM 上，以获得一个 `JNIEnv`。
当一个 Native 线程附加到 JVM 时，JVM 会为该线程分配一个新的 `JNIEnv` 结构，并将其存储在线程局部存储 (Thread Local Storage, TLS) 中。`AttachCurrentThread` 会执行以下操作：
- 分配一个新的 `JNIEnv` 实例，并初始化其函数表。
- 将 `JNIEnv` 指针存储在当前线程的 TLS 中。
- 将线程注册到 JVM 的线程管理系统中。

```cpp
JNIEnv* env;
int getEnvStat = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (getEnvStat == JNI_EDETACHED) {
    if (gJvm->AttachCurrentThread(&env, NULL) != 0) {
        // 处理附加失败
    }
    needDetach = true;
}

```

## Java代码调用Native代码

当 Java 调用 Native 方法时，JVM 会执行以下步骤：
- 查找并加载包含 Native 方法实现的共享库。
- 获取方法的本地函数指针。
- 创建一个 Native 帧并推送到当前线程的调用栈。
- 切换到 Native 模式，执行本地函数。
- 当本地函数返回时，切换回 Java 模式，并弹出 Native 帧。


1. 创建一个 Native C++ 库并定义一个带返回值的方法。
```cpp
// native-lib.cpp
#include <jni.h>
#include <string>

extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_unityplugin_NativeLib_stringFromJNI(JNIEnv *env, jobject /* this */, jstring input) {
    const char *inputStr = env->GetStringUTFChars(input, 0); // JNI 提供的函数，用于将 `jstring` 类型的 `input` 转换为 C 风格的字符串 (`const char*`)。

    std::string hello = "Response from C++: ";
    hello += inputStr;
    env->ReleaseStringUTFChars(input, inputStr); //释放之前通过 `GetStringUTFChars` 获取的内存, 是必要的,防止内存泄漏.

    return env->NewStringUTF(hello.c_str());
}

```

- `env->GetStringUTFChars`  JNI 提供的函数，将 `jstring` 类型的 `input` 转换为 C 风格的字符串 (`const char*`)。
- `ReleaseStringUTFChars` 释放之前通过 `GetStringUTFChars` 获取的内存, 防止内存泄漏.
* `hello.c_str()` 返回 C++ 字符串对象 `hello` 的底层 C 风格字符串指针。
* `env->NewStringUTF` 将 C 风格的字符串 (`const char*`) 转换为 `jstring`，以便返回给 Java 层。

> **UTF (Unicode Transformation Format)** 是一种字符编码形式，用于将 Unicode 字符转换为字节序列。**常见的 UTF 编码格式**：UTF-8, UTF-16等. JNI 提供了函数将 `jstring`（Java 字符串）转换为 UTF-8 编码的 C 字符串，并且允许将 C 字符串转换为 `jstring`。

3. 在 Java 代码中调用 Native 方法并处理返回值。
```java
// MainActivity.java
package com.example.unityplugin;

import android.os.Bundle;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    static {
        System.loadLibrary("native-lib");
    }

    public native String stringFromJNI(String input);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        TextView tv = findViewById(R.id.sample_text);
        String response = stringFromJNI("Hello from Java!");
        tv.setText(response);
    }
}

```

`extern "C"`
- **含义**：用来告诉编译器按 C 语言的函数命名规则（而不是 C++ 的命名规则）来生成符号。
- **目的**：防止 C++ 编译器对函数名进行名称改编（name mangling），使其能够与 Java 的 JNI 调用正确匹配。由于 JNI 是以 C 的方式调用方法，所以需要使用 `extern "C"`。

 JNIEXPORT`
- **含义**：一个宏，通常在 `jni.h` 中定义，用来修饰 JNI 函数，表示该函数会被导出，使 Java 虚拟机 (JVM) 能够访问到此函数。
- **目的**：使函数可以被 JVM 调用。根据具体的平台，`JNIEXPORT` 会展开为相应的导出修饰符，例如在 Windows 上它可能展开为 `__declspec(dllexport)`。

`JNICALL`
- **含义**：一个宏，通常在 `jni.h` 中定义，用来修饰 JNI 函数，表示该函数使用的调用约定 (calling convention)。
- **目的**：保证函数使用正确的调用约定，使 JVM 能够正确地调用此函数。在 Windows 上，这通常展开为 `__stdcall`。

`jstring`
- **含义**：这是 JNI 提供的一个类型，用于表示 Java 中的 `String` 类型。
- **目的**：用来表示从 Java 传递过来的字符串，或者返回一个 Java 字符串给 Java 层。

`JNIEnv *env`
- **含义**：JNI 环境指针，指向一个指针数组，包含了许多 JNI 函数指针。
- **目的**：通过这个指针可以调用 JNI 提供的各种函数，例如将 C++ 字符串转换为 Java 字符串等。

`jobject /* this */`
- **含义**：代表 Java 对象的引用。在非静态方法中，这个参数是必需的，指向调用这个 JNI 函数的 Java 对象。
- **目的**：在 C++ 代码中可以通过这个引用访问调用该方法的 Java 对象。对于静态方法，则为 `jclass`，表示类的引用。

`Java_com_example_unityplugin_NativeLib_callJavaMethod`
- **含义**：这是 JNI 函数的名称，按照 JNI 的命名规范，由 `Java_` 前缀、包名、类名和方法名组成。
- **目的**：通过这种命名方式，JVM 能够根据 Java 代码中的 `NativeLib.callJavaMethod` 方法正确地找到对应的 JNI 实现。


## Native代码调用Java代码

当 Native 代码调用 Java 方法时，执行以下步骤：
- 使用 `JNIEnv` 查找 Java 类和方法 ID。
- 准备方法调用参数并调用相应的 JNI 函数。
- JNI 函数会创建一个 Java 帧并推送到当前线程的调用栈。
- JVM 解释或编译执行该 Java 方法。
- 当 Java 方法返回时，JNI 函数会弹出 Java 帧，并返回结果给 Native 代码。

### 基础
1. 在 Java 类中定义一个带返回值的静态方法。
```java
// MyJavaClass.java
package com.example.unityplugin;

import android.util.Log;

public class MyJavaClass {
    public static String myJavaMethod(String message) {
        Log.d("MyJavaClass", message);
        return "Response from Java: " + message;
    }
}

```

2. 在 Native C++ 代码中调用 Java 方法并处理返回值。
```cpp
// native-lib.cpp
#include <jni.h>
#include <string>

extern "C"
JNIEXPORT jstring JNICALL
Java_com_example_unityplugin_NativeLib_callJavaMethod(JNIEnv *env, jobject /* this */, jstring input) {
    jclass javaClass = env->FindClass("com/example/unityplugin/MyJavaClass");
    jmethodID methodID = env->GetStaticMethodID(javaClass, "myJavaMethod", "(Ljava/lang/String;)Ljava/lang/String;");
    jstring response = (jstring) env->CallStaticObjectMethod(javaClass, methodID, input);
    return response;
}

```

### 进阶-以JavaVM为中介

Java调用Native层时,Native层将JavaVM指针存储下来.
```cpp
static JavaVM* gJvm = NULL;
static jobject gNativeCrashHandler = NULL;

void initializeNativeCrashHandler(JNIEnv* env, jobject obj) {
    LOGI("NativeCrashWatcher->initializeNativeCrashHandler");
    env->GetJavaVM(&gJvm);
    gNativeCrashHandler = env->NewGlobalRef(obj);

    installSignalHandlers();
}
```


Native层需要回调Java代码时,通过JavaVM

```cpp
void handleSignal(int signal, siginfo_t* info, void* context) {
    LOGI("NativeCrashWatcher->handleSignal Caught signal %d", signal);

    JNIEnv* env;
    int getEnvStat = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6);
    bool needDetach = false;

    if (getEnvStat == JNI_EDETACHED) {
        if (gJvm->AttachCurrentThread(&env, NULL) != 0) {
            LOGE("Failed to attach current thread");
            return;
        }        needDetach = true;
    } else if (getEnvStat == JNI_OK) {
        needDetach = true;
//        LOGD("Thread already attached");
    } else {
        LOGE("Failed to get the environment: %d", getEnvStat);
        return;
    }
    jclass handlerClass = env->GetObjectClass(gNativeCrashHandler);
    if (handlerClass == NULL) {
        LOGE("Failed to get handler class");
        gJvm->DetachCurrentThread();
        return;
    }
    jmethodID methodID = env->GetStaticMethodID(handlerClass, "reportException", "(Ljava/lang/String;)V");
    if (methodID == NULL) {
        LOGE("Failed to get method ID for reportException");
        gJvm->DetachCurrentThread();
        return;
    }//    LOGD("NativeCrashWatcher->handleSignal Got method id");

    char message[256];
    snprintf(message, sizeof(message), "Caught signal %d", signal);
//    LOGD("NativeCrashWatcher->handleSignal generate msg: %s", message);

    jstring exceptionMessage = env->NewStringUTF(message);
    if (exceptionMessage == NULL) {
        LOGE("Failed to create new string");
        gJvm->DetachCurrentThread();
        return;
    }
    env->CallStaticVoidMethod(handlerClass, methodID, exceptionMessage);
//    LOGD("NativeCrashWatcher->handleSignal Called java reportException");

    if (env->ExceptionCheck()) {
        env->ExceptionDescribe();
        env->ExceptionClear();
        //LOG输出Java层异常信息
        LOGE("Exception occurred while calling Java method");

    }
    env->DeleteLocalRef(exceptionMessage);
//    LOGD("NativeCrashWatcher->handleSignal Deleted local ref");
    if (needDetach) {
        LOGD("Detaching thread...");
        gJvm->DetachCurrentThread();
        LOGD("NativeCrashWatcher->handleSignal Detached current thread");
    }}
```


## Android Studio工程配置

在 Android Studio 中创建用于 Unity 插件的工程

#### 1. 创建新的 Android Studio 工程

- **选择 "No Activity" 模板**，点击 `Next`。
- Language: 选择 `Java`。
- Minimum API level: 选择适合您的项目的最低 API 级别，建议使用 `API 16: Android 4.1 (Jelly Bean)` 或更高版本。

#### 2. 配置工程结构

##### 创建 Java 代码结构
- **创建 Java 包**：在 `src/main/java` 目录下，右键选择 `New > Package`，输入包名，例如 `com.prin.myplugin`。
- **创建 Java 类**：在新创建的包中，右键选择 `New > Java Class`，输入类名 `TestJavaClass`，然后编写 Java 代码。

```java
package com.prin.myplugin;

import android.util.Log;

public class TestJavaClass {
    public static String myJavaMethod(String message) {
        Log.d("MyJavaClass", message);
        return "Response from Java: " + message;
    }

    public static int Multiply(int a, int b) {
        return a * b;
    }
}
```


##### 创建 Native 代码结构

- **创建 C++ 目录**：在 `src/main` 目录下，右键选择 `New > Directory`，输入目录名 `cpp`。
- **创建 C++ 文件**：在 `cpp` 目录下，右键选择 `New > C++ Source File`，输入文件名 `native-lib`。

编写示例 C++ 代码：
```cpp
#include <jni.h>

extern "C" JNIEXPORT jint JNICALL
Java_com_prin_myplugin_TestJavaClass_multiply(JNIEnv *env, jclass clazz, jint a, jint b) {
    return a * b;
}

```

配置 CMake 构建脚本
在 `cpp` 目录下，右键选择 `New > File`，输入文件名 `CMakeLists.txt`，并编写以下内容：
```cmake
cmake_minimum_required(VERSION 3.4.1)

add_library( native-lib SHARED native-lib.cpp )

find_library( log-lib log )

target_link_libraries( native-lib ${log-lib} )

```


#### 3. 配置 build.gradle 文件

在 `app/build.gradle` 文件中
* 配置 CMake 和 JNI 支持。
```cpp
android {
    ...
    defaultConfig {
        ...
        externalNativeBuild {
            cmake {
                cppFlags "-std=c++11"
            }
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
        }
    }
}

```

添加依赖以生成 Jar 包：
```groovy
task createJar {
    doFirst {
        logger.lifecycle("Starting to create Jar file...")
    }

    doLast {
        def classesDir = file("$buildDir/intermediates/javac/debug/classes")
        def jarDir = file("$buildDir/libs")
        def jarFilePath = "$jarDir/ExperimentalJavaLib.jar"

        if (!classesDir.exists()) {
            logger.lifecycle("Classes directory does not exist: $classesDir")

            return
        }

        if (!jarDir.exists()) {
            jarDir.mkdirs()
        }

        ant.jar(destfile: jarFilePath, basedir: classesDir) {
            exclude(name: "**/R.class")
            exclude(name: '**/R$*.class')
            exclude(name: "**/BuildConfig.class")
            exclude(name: "**/Manifest.class")
        }

        def jarFile = file(jarFilePath)
        if (jarFile.exists()) {
            logger.lifecycle("Jar file created successfully: ${jarFile.absolutePath}")
        } else {
            logger.lifecycle("Jar file creation failed.")
        }
    }
}

```

确保 `createJar` 任务在 `assembleDebug` 或其他具体的 assemble 任务完成之后执行。
```cpp
afterEvaluate {
    tasks.getByName("assembleDebug").finalizedBy(createJar)
}
```

#### 4. 编译项目

* 点击 `Build > Make Project`
* 构建完成后，生成的 Jar 包位于 `app/build/libs/MyPlugin.jar`，SO 库位于 `app/build/intermediates/cmake/debug/obj/<架构>/libnative-lib.so`。

#### 5. 将生成的文件集成到 Unity 中

- 将 `MyPlugin.jar` 复制到 `Assets/Plugins/Android/` 目录。
- 将 `libnative-lib.so` 复制到 `Assets/Plugins/Android/libs/<架构>/` 目录。
- 在 Unity 中调用 Java 和 Native 方法


## 案例：CS->Java->Native->Java

- 在Unity中，通过C#代码调用Java方法`CallNativeMethod`。
- Java方法`CallNativeMethod`调用Native方法`stringFromJNI`。
- Native方法`stringFromJNI`调用Java方法`myJavaMethod`。
- Java方法`myJavaMethod`返回结果给Native方法`stringFromJNI`。
- Native方法`stringFromJNI`处理返回结果并返回给Java方法`CallNativeMethod`。
- Java方法`CallNativeMethod`返回最终结果给C#代码。

1. C#代码
```cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestCallJavaCallNativeCallJava : MonoBehaviour
{
    public void CallJavaCallNativeCallJava()
    {
        Debug.Log("CallJavaCallNativeCallJava----------------------------------------");

        // 获取 UnityPlayer 类
        AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");

        // 获取当前活动
        AndroidJavaObject activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");

        // 调用自定义 Java 类的方法
        AndroidJavaClass myJavaClass = new AndroidJavaClass("com.experimental.javalib.TestJavaCallNativeClass");

        // 调用 Java 静态方法并获取返回值
        string response = myJavaClass.CallStatic<string>("CallNativeMethod", "Hello from Unity!");
        Debug.Log(response);
    }
}

```


2. Java代码
```java
package com.experimental.javalib;

public class TestJavaCallNativeClass {
    static {
        System.loadLibrary("experimental-native-lib");
    }

    // 声明本地方法
    public static native String stringFromJNI(String input);

    // 调用本地方法
    public static String CallNativeMethod(String input) {
        String responseFromNative = stringFromJNI(input);
        return "Response from Java(CallNativeMethod): " + responseFromNative;
    }
}

```

3. Native代码
```cpp
#include <jni.h>
#include <string>

jstring callJavaMethod(JNIEnv *env, jclass clazz, jstring input) {
    // 获取 Java 类
    jclass javaClass = env->FindClass("com/experimental/javalib/TestJavaClass2");

    // 获取 Java 静态方法ID
    jmethodID methodID = env->GetStaticMethodID(javaClass, "myJavaMethod", "(Ljava/lang/String;)Ljava/lang/String;");

    // 调用 Java 静态方法并获取返回值
    jstring response = (jstring) env->CallStaticObjectMethod(javaClass, methodID, input);

    return response;
}

extern "C"
JNIEXPORT jstring JNICALL
Java_com_experimental_javalib_TestJavaCallNativeClass_stringFromJNI(JNIEnv *env, jclass clazz, jstring input) {
    // 调用 Java 方法
    jstring javaMethodRes = callJavaMethod(env, clazz, input);

    // 将 Java 返回的字符串转换为 C++ 字符串并拼接
    const char *tmpStr = env->GetStringUTFChars(javaMethodRes, 0);
    std::string hello = "Response from C++(stringFromJNI): ";
    hello += tmpStr;
    env->ReleaseStringUTFChars(javaMethodRes, tmpStr);

    // 返回拼接后的字符串
    return env->NewStringUTF(hello.c_str());
}

```

4. Java代码
```java
package com.experimental.javalib;

import android.util.Log;

public class TestJavaClass2 {
    // 被Native代码调用的Java静态方法
    public static String myJavaMethod(String message) {
        Log.d("MyJavaClass", message);
        return "Response from Java(myJavaMethod): " + message;
    }
}

```

![assets/image-20240607183651124.png](/media/76861ec96789743d969f.png)
