概述 在 Cocos Creator 游戏开发中,经常需要与 Android 原生平台进行交互,例如调用支付 SDK、分享功能、获取设备信息等。Cocos Creator 通过 JSB(JavaScript Binding)技术提供了 JavaScript 与 Java 之间的互相调用能力。本文将详细介绍如何在 Cocos Creator 中调用 Android 原生代码。
JSB 反射机制简介 Cocos Creator 使用 jsb.reflection 模块实现 JavaScript 与 Java 的通信。该模块提供了 callStaticMethod 方法,可以调用 Java 类中的静态方法。
callStaticMethod 方法签名 1 jsb.reflection .callStaticMethod (className, methodName, methodSignature, ...args)
参数说明:
className:Java 类的完整路径(使用斜杠代替点号)
methodName:要调用的静态方法名称
methodSignature:方法签名,描述参数类型和返回值类型
...args:可变参数,传递给 Java 方法的实参
基础调用示例 JavaScript 端代码 1 2 3 4 5 6 7 8 9 if (jsb) { let result = jsb.reflection .callStaticMethod ( "org/cocos2dx/javascript/AppActivity" , "pay" , "(Ljava/lang/String;)Ljava/lang/String;" , "1" ); cc.log (result); }
Java 端代码 在 AppActivity.java 中添加静态方法:
1 2 3 4 5 6 7 8 9 package org.cocos2dx.javascript;public class AppActivity extends Cocos2dxActivity { public static String pay (String index) { return "success" ; } }
方法签名详解 方法签名使用 JNI(Java Native Interface)格式,用于描述方法的参数类型和返回值类型。
基本类型对应表
JNI 类型
Java 类型
I
int
F
float
Z
boolean
J
long
D
double
B
byte
C
char
S
short
V
void
引用类型表示法
字符串:Ljava/lang/String;
数组:[I(int 数组)、[Ljava/lang/String;(String 数组)
复杂方法签名示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 "()V" "(Ljava/lang/String;)I" "(ILjava/lang/String;)Ljava/lang/String;" jsb.reflection .callStaticMethod ( "org/cocos2dx/javascript/AppActivity" , "shareContent" , "(Ljava/lang/String;Ljava/lang/String;I)V" , "标题" , "内容" , 1 );
完整实战示例 1. 支付功能封装 Java 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class AppActivity extends Cocos2dxActivity { public static String startPay (String productId, String orderId) { try { PaySDK.getInstance().pay(productId, orderId, new PayCallback () { @Override public void onSuccess () { Cocos2dxJavascriptJavaBridge.evalString( "cc.director.emit('pay_success')" ); } @Override public void onFail (int code, String msg) { Cocos2dxJavascriptJavaBridge.evalString( "cc.director.emit('pay_fail', {code:" + code + ", msg:'" + msg + "'})" ); } }); return "processing" ; } catch (Exception e) { return "error: " + e.getMessage(); } } }
JavaScript 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class PaymentHelper { static init ( ) { cc.director .on ('pay_success' , this .onPaySuccess , this ); cc.director .on ('pay_fail' , this .onPayFail , this ); } static startPay (productId, orderId ) { if (!jsb) { cc.warn ("非原生平台,跳过支付" ); return ; } let result = jsb.reflection .callStaticMethod ( "org/cocos2dx/javascript/AppActivity" , "startPay" , "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" , productId, orderId ); cc.log ("支付调用结果:" , result); } static onPaySuccess ( ) { cc.log ("支付成功!" ); } static onPayFail (data ) { cc.error ("支付失败:" , data.code , data.msg ); } } module .exports = PaymentHelper ;
2. 获取设备信息 Java 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 public static String getDeviceInfo () { JSONObject info = new JSONObject (); try { info.put("deviceModel" , Build.MODEL); info.put("systemVersion" , Build.VERSION.RELEASE); info.put("sdkVersion" , Build.VERSION.SDK_INT); info.put("packageName" , getPackageName()); info.put("versionName" , getVersionName()); } catch (JSONException e) { e.printStackTrace(); } return info.toString(); }
JavaScript 代码:
1 2 3 4 5 6 7 8 9 10 11 getDeviceInfo ( ) { if (!jsb) return null ; let infoStr = jsb.reflection .callStaticMethod ( "org/cocos2dx/javascript/AppActivity" , "getDeviceInfo" , "()Ljava/lang/String;" ); return JSON .parse (infoStr); }
Java 调用 JavaScript 除了 JS 调用 Java,有时也需要从 Java 层回调 JavaScript。
使用 Cocos2dxJavascriptJavaBridge 1 2 3 4 5 6 7 8 9 10 11 import org.cocos2dx.lib.Cocos2dxJavascriptJavaBridge;runOnGLThread(new Runnable () { @Override public void run () { Cocos2dxJavascriptJavaBridge.evalString( "window.onAndroidCallback && window.onAndroidCallback('参数')" ); } });
调用带参数的 JS 函数 1 2 3 4 5 6 7 8 9 10 11 public void notifyGameEvent (String event, String data) { final String jsCode = String.format( "cc.director.emit('%s', '%s')" , event, data ); runOnGLThread(() -> { Cocos2dxJavascriptJavaBridge.evalString(jsCode); }); }
常见问题与解决方案 1. 类找不到错误 问题现象: java.lang.ClassNotFoundException
解决方案:
检查类路径是否正确(使用斜杠 / 而非点号 .)
确保类在 src 目录下
检查包名声明是否与路径一致
2. 方法签名错误 问题现象: java.lang.NoSuchMethodError
解决方案:
确认方法签名格式正确
检查参数类型是否匹配
确保方法是 public static 修饰
3. 在非 Android 平台报错 问题现象: 在浏览器或桌面端运行时出现 jsb is not defined
解决方案:
1 2 3 4 5 if (jsb && jsb.reflection ) { } else { cc.log ("当前平台不支持原生调用" ); }
4. 主线程问题 某些 Android 操作需要在主线程执行:
1 2 3 4 5 6 runOnUiThread(new Runnable () { @Override public void run () { } });
最佳实践 1. 封装原生接口 建议将原生调用封装成独立的模块:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 export default class NativeHelper { static isNative ( ) { return jsb && jsb.reflection ; } static callAndroid (className, method, signature, ...args ) { if (!this .isNative ()) { cc.warn ("当前不是原生平台" ); return null ; } try { return jsb.reflection .callStaticMethod ( className, method, signature, ...args ); } catch (e) { cc.error ("原生调用失败:" , e); return null ; } } }
2. 回调处理机制 使用事件系统处理异步回调:
1 2 3 4 5 6 7 8 9 10 11 export const NativeEvents = { PAY_SUCCESS : 'native_pay_success' , PAY_FAIL : 'native_pay_fail' , SHARE_COMPLETE : 'native_share_complete' };
3. 调试技巧 在 Java 端添加日志便于调试:
1 2 3 4 5 6 7 import android.util.Log;public static String testMethod (String param) { Log.d("CocosCreator" , "收到参数: " + param); return "result" ; }
使用 adb logcat -s CocosCreator:D 查看日志。
总结 通过 jsb.reflection.callStaticMethod,Cocos Creator 可以方便地与 Android 原生平台进行通信。关键点包括:
正确使用方法签名 :理解 JNI 类型标识符的含义
做好平台判断 :确保只在原生平台执行相关代码
封装调用接口 :将原生调用封装成易用的模块
处理异步回调 :使用事件机制处理 Java 到 JS 的通信
掌握这些技术,可以大大扩展 Cocos Creator 游戏的功能边界,实现更丰富的原生平台能力集成。