Lua 发送一个带有特定参数的请求给 Java,Java 在一个独立的线程中执行这个请求,执行完毕后(可选)再将结果返回给 Lua。

下面我将分步详细讲解如何实现,并提供一个完整的示例。
核心概念:JsbBridge
JsbBridge 提供了两个主要的方法:
callStaticMethod: 这是最常用的方法,用于调用 Java 的静态方法。reflectionCall: 用于通过反射调用 Java 的实例方法或构造函数,相对复杂,一般较少使用。
我们主要讲解 callStaticMethod。
第一步:在 Cocos Creator (Lua) 中调用 Java
在 Lua 脚本中,使用 JsbBridge.callStaticMethod 来发起调用。

callStaticMethod 的方法签名
JsbBridge.callStaticMethod(className, methodName, paramType, parameters, callback)
className(string): Java 类的全限定名,格式为包名.类名。methodName(string): 要调用的 Java 静态方法名。paramType(string or table): 参数类型描述,如果只有一个参数,可以是字符串(如"I"代表 int);如果有多个参数,则需要是一个类型字符串数组(如{"I", "Ljava/lang/String;"})。parameters(any or table): 要传递给 Java 方法的参数,如果只有一个参数,可以直接传入;如果有多个参数,需要按顺序放入一个表中。callback(function, 可选): 回调函数,当 Java 方法执行完毕后,如果需要返回结果给 Lua,会通过这个回调函数返回,这个回调在主线程中执行。
Java 参数类型与 Lua 的对应关系
| Java 类型 | JNI 类型描述符 | Lua 类型 | 备注 |
|---|---|---|---|
| int, Integer | I | number | |
| float, Float | F | number | |
| double, Double | D | number | |
| boolean, Boolean | Z | boolean | Lua 中用 true/false |
| String | Ljava/lang/String; |
string | |
| byte, Byte | B | number | |
| char, Character | C | string | 传入单个字符的字符串 |
| int[] | [I |
table | {1, 2, 3} |
| String[] | [Ljava/lang/String; |
table | {"a", "b", "c"} |
第二步:在 Android (Java) 中接收调用
在 Java 端,你需要创建一个类,并使用 @Jni 和 @Jsi 注解来告诉引擎哪些方法可以被 Lua 调用,这些注解通常位于 cocos-service 库中。
添加依赖
确保你的 app/build.gradle 文件中包含了 cocos-service 依赖,对于较新版本的 Cocos Creator,这通常是自动配置的。
// app/build.gradle
dependencies {
// ... 其他依赖
implementation project(':cocos-service') // 确保这行存在
}
创建 Java 类并添加注解
创建一个 Java 类,com.yourpackage.MyJavaBridge。
package com.yourpackage;
import com.cocos.service.bridge.Jni;
import com.cocos.service.bridge.Jsi;
public class MyJavaBridge {
// 被 @Jsi 注解标记的静态方法可以被 Lua 调用
// 参数和返回值类型必须与 JNI 兼容
@Jsi
public static String showToast(String message, int duration) {
// 注意:这个方法运行在**后台线程**,不能直接操作 UI!
// 如果要更新 UI,需要使用 Handler 切换到主线程。
Log.d("MyJavaBridge", "Received message from Lua: " + message + ", Duration: " + duration);
// 使用 Handler 切换到主线程显示 Toast
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast.makeText(CocosHelper.getActivity(), message, duration).show();
}
});
// 返回一个字符串给 Lua
return "Message '" + message + "' is being shown.";
}
@Jsi
public static int addNumbers(int a, int b) {
Log.d("MyJavaBridge", "Adding " + a + " and " + b);
return a + b;
}
}
代码解释
package com.yourpackage;: 包名必须与你在 Lua 中传入的className中的包名一致。@Jsi: 这个注解是关键,它告诉 Cocos Service 引擎,这个静态方法可以被 Lua 调用。- 线程问题:非常重要!
@Jsi标记的方法运行在后台线程(非 UI 线程),任何 UI 操作(如显示 Toast、更新 View)都必须通过Handler切换到主线程执行,上面的showToast示例就展示了正确的做法。 CocosHelper.getActivity(): 这是一个 Cocos Creator 提供的工具类,可以方便地获取到当前 Activity 的实例。
第三步:完整示例
场景描述
在 Cocos Creator 场景中,有一个按钮,点击按钮后,Lua 会调用 Java 的 showToast 方法,显示一个 Toast;然后调用 addNumbers 方法,并将结果打印到控制台。
Java 端代码
按照第二步,创建 MyJavaBridge.java 文件,内容如下:
// MyJavaBridge.java
package com.yourpackage;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import com.cocos.service.bridge.Jsi;
import com.cocos.service.CocosHelper;
public class MyJavaBridge {
private static final String TAG = "MyJavaBridge";
@Jsi
public static String showToast(String message, int duration) {
Log.d(TAG, "Java showToast called with: " + message);
// 切换到主线程显示 Toast
new Handler(Looper.getMainLooper()).post(() -> {
Toast.makeText(CocosHelper.getActivity(), message, duration).show();
});
return "Java: Toast for '" + message + "' has been queued.";
}
@Jsi
public static int addNumbers(int a, int b) {
Log.d(TAG, "Java addNumbers called with: " + a + ", " + b);
return a + b;
}
}
Lua 端代码
在 Cocos Creator 中创建一个 Lua 脚本,MainScene.lua,并把它挂载到场景的节点上。
-- MainScene.lua
local MainScene = class("MainScene", function()
return cc.Scene:create()
end)
function MainScene:ctor()
-- 加载 CCB 文件或创建 UI 节点
-- 假设我们有一个按钮,它的 name 是 "myButton"
local node = cc.CSLoader:createNode("MainScene.csb")
self:addChild(node)
local button = node:getChildByName("myButton")
button:addClickEventListener(function()
self:onButtonClick()
end)
end
function MainScene:onButtonClick()
print("Button clicked! Calling Java...")
-- --- 示例 1: 调用 showToast 方法 ---
-- className: "com.yourpackage.MyJavaBridge"
-- methodName: "showToast"
-- paramType: 一个字符串数组,描述两个参数的类型
-- "Ljava/lang/String;" -> String
-- "I" -> int
-- parameters: 参数表,顺序必须与 paramType 一致
-- callback: 回调函数,用于接收 Java 返回的结果
local callback1 = function(result)
-- 这个回调在 Lua 的主线程中执行
print("Lua: Callback from showToast received result:", result)
end
local className1 = "com.yourpackage.MyJavaBridge"
local methodName1 = "showToast"
local paramType1 = {"Ljava/lang/String;", "I"}
local parameters1 = {"Hello from Lua!", Toast.LENGTH_LONG} -- Toast.LENGTH_LONG 是一个常量
-- 发起调用
JsbBridge.callStaticMethod(className1, methodName1, paramType1, parameters1, callback1)
-- --- 示例 2: 调用 addNumbers 方法 ---
local callback2 = function(result)
print("Lua: Callback from addNumbers received result:", result, "(type: ", type(result), ")")
end
local className2 = "com.yourpackage.MyJavaBridge"
local methodName2 = "addNumbers"
local paramType2 = {"I", "I"}
local parameters2 = {10, 20}
JsbBridge.callStaticMethod(className2, methodName2, paramType2, parameters2, callback2)
end
return MainScene
注意事项
- 包名一致性:Java 类的包名
com.yourpackage必须与 Lua 中className的部分完全一致。 - 方法名一致性:Lua 传入的
methodName必须与 Java 方法名完全一致。 - 参数类型和顺序:
paramType和parameters的类型和顺序必须严格对应,否则会调用失败。 - 异步性:
callStaticMethod是异步的,Java 方法执行后,结果通过callback返回,不要期望调用后立即能拿到返回值。 - 错误处理:如果调用失败(例如类名、方法名错误),
callback不会被调用,你可以通过引擎的日志来排查问题,在 Android Studio 的 Logcat 中,过滤标签cocos或JsbBridge通常能看到相关的错误信息。 - 混淆:在发布 Android 版本时,如果启用了代码混淆,必须保留被
@Jsi注解标记的类和方法,否则它们会被混淆掉,导致 Lua 无法找到,在proguard-rules.pro文件中添加如下规则:# Keep Cocos Service JNI classes -keep class com.cocos.service.** { *; } # Keep your own bridge class and methods -keep class com.yourpackage.MyJavaBridge { *; }
调试技巧
- Logcat: 这是你最好的朋友,在 Android Studio 中,打开 Logcat,选择你的 App,然后使用过滤器
cocos或JsbBridge,你会在日志中看到引擎发送的请求、参数以及可能的错误信息。 - Lua 打印: 在 Lua 回调函数中大量使用
print()来打印收到的结果和中间状态,确认 Lua 端的逻辑是否正确。 - 逐步排查:
- 先确保 Java 类和方法名、注解都正确。
- 再确保 Lua 传入的
className和methodName拼写无误。 - 然后检查
paramType和parameters的类型和顺序是否一一对应。 - 最后检查 Java 方法内部的逻辑,特别是线程切换是否正确。
通过以上步骤,你就可以在 Cocos Creator 的 Lua 项目中成功调用 Java 代码了。
