如何在Android平台上使用JavaScript直接调用Java方法
在Creator打包的Android本机APP中,可以使用反射机制在JavaScript中直接调用Java的静态方法。 它的使用很简单:
varo=jsb.reflection.callstaticmethod (class name,methodName,methodSignature,parameters . )
在callStaticMethod方法中,可以通过传递给Java的类名、方法名、方法签名和参数直接调用Java的静态方法,从而获取Java方法的返回值。 下面介绍的类名和方法的签名可能有点奇怪,但Java的规范就是这样的。
类名
参数中的类名必须是包含Java包路径的完整类名。 例如,我们在名为org.cocos2dx.javascript的包下编写了一个Test类。
package org.cocos2dx.javascript;
公共类测试{
publicstaticvoidhello (字符串msg ) {
system.out.println(msg;
}
公共静态Intsum (inta,int b ) {
返回a b;
}
公共静态防毒(inta ) {
返回a 2;
}
}
那么,此Test类的完整类名必须为org/cocos2dx/javascript/Test。 请注意,这里必须是正斜杠/,不是我们在Java代码中习惯的地方。
方法名称
方法名称很简单。 方法的原始名称。 例如,sum方法的名称为sum。
方法签名
方法签名有点复杂,但最简单的方法签名是(v,表示没有参数且没有返回值的方法。 其他示例:
) I ) v表示参数为一个int,无法返回值
(I ) I表示参数为1个int、返回值为int的方法
(IF ) z表示参数为int和float,返回值为boolean的方法
理解了几个吧? 括号中的符号表示参数类型,括号后的符号表示返回类型。 因为Java允许函数重载,所以有多个方法,即使方法名称相同,参数返回值也不同。 方法签名有助于区分这些同名的方法。
当前Cocos Creator支持以下四种类型的Java签名:
Java类型
签名
资讯科技
I
浮动
f
布尔型
z
史汀
Ljava/lang/String;
参数
参数可以是0个,也可以是多个。 直接使用JS的number、bool、string就可以了。
使用案例
调用上面Test类的静态方法。
调用hello方法
jsb.reflection.callstaticmethod (org/cocos2d x/JavaScript/test )、() hello )、() Ljava/lang/String; (v )、(this is a message from js );
//调用第一个sum方法
varresult=jsb.reflection.callstaticmethod ((org/cocos2d x/JavaScript/test )、() II )、I )、3、7
c .日志(结果); //10
//调用第二个sum方法
varresult=jsb.reflection.callstaticmethod ((org/cocos2d x/JavaScript/test )、() sum )、((I )、3 );
c .日志(结果); //5
在你的控制台上得到正确的输出。 这很简单吧。
注意
还有需要注意的事情。 在Android APP中,Cocos引擎的呈现和JS逻辑在GL线程中进行,但Android本身的UI更新在App的UI线程中进行,因此在JS调用的Java方法中更新UI的操作(如果有)将在UI线程中进行
例如,以下示例调用显示Android警报对话框的Java方法。
//请在我们熟悉的AppActivity类中加入一点东西
publicclassappactivityextendscocos2dx activity
{private static AppActivity app = null;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
app = this;
}
public static void showAlertDialog(final String title,final String message){
// 这里一定要使用 runOnUiThread
app.runOnUiThread(new Runnable() {
@Override
public void run(){
AlertDialog alertDialog = new AlertDialog.Builder(app).create();
alertDialog.setTitle(title);
alertDialog.setMessage(message);
alertDialog.setIcon(R.drawable.icon);
alertDialog.show();
}
});
}
}
然后我们在 JS 中调用:
jsb.reflection.callStaticMethod("org/cocos2dx/javascript/AppActivity", "showAlertDialog", "(Ljava/lang/String;Ljava/lang/String;)V", "title", "hahahahha");
这样调用你就可以看到一个 Android 原生的 Alert 对话框了。
再加点料
现在我们可以从 JS 调用 Java 了,那么能不能反过来?当然可以!
在你的项目中包含 Cocos2dxJavascriptJavaBridge,这个类有一个 evalString 方法可以执行 JS 代码,它位于 frameworksjs-bindingsbindingsmanualplatformandroidjavasrcorgcocos2dxlib 文件夹下。我们将会给刚才的 Alert 对话框增加一个按钮,并在它的响应中执行 JS。和上面的情况相反,这次执行 JS 代码必须在 GL 线程中进行。
一般来说,目前引擎并未承诺多线程下的安全性,所以在开发过程中需要避免 JS 代码在其他线程被调用,以避免各种内存错误。
alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which){
// 一定要在 GL 线程中执行
app.runOnGLThread(new Runnable() {
@Override
public void run(){
Cocos2dxJavascriptJavaBridge.evalString("cc.log("Javascript Java bridge!")");
}
});
}
});
如果要在 C++ 中调用 evalString,我们可以参考下面的方式,确保 evalString 在 JS 引擎所在的线程被执行:
Application::getInstance()->getScheduler()->performFunctionInCocosThread([=](){
se::ScriptEngine::getInstance()->evalString(script.c_str());
});
这样在点击 OK 按钮后,你应该可以在控制台看到正确的输出。evalString 可以执行任何 JS 代码,并且它可以访问到你在 JS 代码中的对象。