杰瑞科技汇

cocos2d-x c如何调用Java方法?

  1. 在 C++ 代码中声明和调用 Java 方法
  2. 在 C++ 中获取 Java 的类、方法和字段
  3. 在 Java 中编写被调用的方法
  4. 在 CMakeLists.txt 中链接 JNI 库

下面我们通过一个完整的、可运行的例子来详细讲解,这个例子将实现一个功能:点击 Cocos2d-x 场景中的一个按钮,弹出一个 Android 原生的 Toast 提示。

cocos2d-x c如何调用Java方法?-图1
(图片来源网络,侵删)

准备工作

  1. 确保你的 Cocos2d-x 项目已经正确配置并能运行在 Android 上,如果还没有,请使用 Cocos Creator 或 Cocos2d-x 命令行工具创建一个新项目,并成功构建到 Android 设备或模拟器上。

步骤 1: 在 Java 中编写被调用的方法

我们需要在 Java 代码中创建一个静态方法,这个方法将被 C++ 调用,这个方法的功能就是显示一个 Toast。

  1. 找到你的 Java 源文件,通常位于 proj.android/app/src/main/java/org/cocos2dx/cpp/AppActivity.javacpp 是默认的包名,如果你的项目不同,请相应调整。

  2. 修改 AppActivity.java,添加一个静态方法 showToast

// proj.android/app/src/main/java/org/cocos2dx/cpp/AppActivity.java
package org.cocos2dx.cpp; // 确保包名正确
import org.cocos2dx.lib.Cocos2dxActivity;
import android.os.Bundle;
import android.widget.Toast; // 导入 Toast 类
public class AppActivity extends Cocos2dxActivity {
    // ... (原有的 onCreate 等方法保持不变)
    /**
     * 这是一个静态方法,可以被 C++ 通过 JNI 调用
     * @param context 上下文,用于创建 Toast
     * @param message 要显示的消息
     */
    public static void showToast(String context, String message) {
        // 在 UI 线程上显示 Toast
        Toast.makeText(Cocos2dxActivity.getContext(), message, Toast.LENGTH_SHORT).show();
    }
}

关键点:

cocos2d-x c如何调用Java方法?-图2
(图片来源网络,侵删)
  • public static: 方法必须是 publicstatic 的,这样 C++ 才能通过类名直接调用,而无需创建 Java 对象实例。
  • Toast.makeText(...): 这是 Android 原生显示提示框的代码。
  • Cocos2dxActivity.getContext(): Cocos2d-x 提供了一个静态方法来获取当前 Activity 的上下文,这是最安全的方式。

步骤 2: 在 C++ 中调用 Java 方法

我们将在 C++ 代码中编写逻辑来调用上面定义的 showToast 方法。

  1. 在 C++ 类的头文件或源文件中,包含必要的 JNI 头文件,并添加一个方法来触发调用。

假设我们在 HelloWorldScene.cpp 中实现这个功能。

// HelloWorldScene.cpp
#include "HelloWorldScene.h"
#include "cocos2d.h"
#include "platform/android/jni/JniHelper.h" // 1. 包含 Cocos2d-x 的 JNI 辅助头文件
#include <jni.h> // 2. 标准 JNI 头文件
USING_NS_CC;
Scene* HelloWorld::createScene()
{
    return HelloWorld::create();
}
// 在 .cpp 文件顶部定义 Java 方法的签名
// 这个签名可以通过 javap 命令生成,我们手动写一个简单的
// (Ljava/lang/String;Ljava/lang/String;)V
// 解释: (L...;L...;)V -> 两个 String 参数,返回 void
static const char* className = "org/cocos2dx/cpp/AppActivity"; // 3. Java 类的全限定名 (包名/类名)
static const char* methodName = "showToast";                 // 4. Java 方法名
static const char* methodSignature = "(Ljava/lang/String;Ljava/lang/String;)V"; // 5. Java 方法签名
// ... create() 和 init() 方法保持不变 ...
void HelloWorld::menuCloseCallback(Ref* pSender)
{
    // 这里我们不调用 Director::getInstance()->end(),而是调用 Java 方法
    callJavaToast();
}
void HelloWorld::callJavaToast()
{
    // 6. 获取 JniMethodInfo
    JniMethodInfo methodInfo;
    // 7. 调用 JniHelper 的静态方法获取方法信息
    // 参数: 方法信息对象, Java类名, Java方法名, 方法签名
    if (JniHelper::getStaticMethodInfo(methodInfo,
                                       className,
                                       methodName,
                                       methodSignature))
    {
        // 8. 调用 Java 方法
        // 参数: jobject (this指针, 静态方法传NULL), jstring参数...
        jstring jParam1 = methodInfo.env->NewStringUTF("Cocos2d-x"); // 第一个参数
        jstring jParam2 = methodInfo.env->NewStringUTF("Hello from C++!"); // 第二个参数
        methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, jParam1, jParam2);
        // 9. 释放局部引用
        methodInfo.env->DeleteLocalRef(jParam1);
        methodInfo.env->DeleteLocalRef(jParam2);
        // 10. 释放方法信息
        JniHelper::getEnv()->DeleteLocalRef(methodInfo.classID);
        CCLOG("Successfully called Java showToast method.");
    }
    else
    {
        CCLOG("Failed to get static method info for showToast");
    }
}

代码详解:

  1. #include "platform/android/jni/JniHelper.h": Cocos2d-x 提供的 JNI 工具类,它封装了复杂的 JNI 调用,使代码更简洁。
  2. #include <jni.h>: 标准 JNI 接口定义。
  3. className: 非常重要!必须是 Java 类的全限定名,即 包名/类名,用斜杠 而不是点 。
  4. methodName: 你要调用的 Java 静态方法名。
  5. methodSignature: 最复杂也最容易出错的部分,它描述了方法的参数和返回类型。
    • 开始, 结束。
    • 中间是参数列表,每个参数对应一个类型码。
    • V 表示 void 返回类型。
    • 常见类型码:
      • Z -> boolean
      • B -> byte
      • C -> char
      • S -> short
      • I -> int
      • J -> long
      • F -> float
      • D -> double
      • Ljava/lang/String; -> String
      • L.../...; -> 任意对象 (如 Landroid/graphics/Bitmap;)
    • 我们的 showToast 方法有两个 String 参数,返回 void,所以签名是 (Ljava/lang/String;Ljava/lang/String;)V
  6. JniHelper::getStaticMethodInfo(...): 核心函数,用于查找并加载 Java 的静态方法,如果成功,它会填充 JniMethodInfo 结构体。
  7. methodInfo.env->NewStringUTF(...): C++ 字符串 (const char*) 不能直接传给 Java,需要用 JNI 环境指针 env 将其转换为 jstring 对象。
  8. methodInfo.env->CallStaticVoidMethod(...): 真正执行 Java 方法的地方。
    • methodInfo.classID: Java 类的引用。
    • methodInfo.methodID: Java 方法的引用。
    • 后面是转换后的参数。
  9. DeleteLocalRef(...): 非常重要! 在 JNI 中,通过 NewStringUTF 等方法创建的局部引用,在使用完毕后必须手动释放,否则会导致内存泄漏。
  10. DeleteLocalRef(methodInfo.classID): 同样,getStaticMethodInfo 返回的 classID 也是一个局部引用,需要释放。

步骤 3: 在 CMakeLists.txt 中链接 JNI 库

虽然 JniHelper 帮我们简化了很多,但底层的 JNI 调用仍然需要链接 Android 的 JNI 库。

cocos2d-x c如何调用Java方法?-图3
(图片来源网络,侵删)

打开 proj.android/CMakeLists.txt 文件,在 target_link_libraries 部分添加 logandroid

# ... 其他配置 ...
# Add your application library
add_library(${APP_NAME} SHARED
    ${COCOS2D_X_ANDROID_JNI_DIR}/cocos2dxjni.cpp
分享:
扫描分享到社交APP
上一篇
下一篇