如何在 Java 应用程序中在 Android 上运行 Lua 脚本?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10471667/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I run Lua scripts on Android in a Java application?
提问by Nick Bolton
I'm developing an Android game in Java which uses Lua scripts. To execute these scripts, I'm using LuaJ with Java's ScriptEngine class. For example...
我正在用 Java 开发一个使用 Lua 脚本的 Android 游戏。为了执行这些脚本,我将 LuaJ 与 Java 的 ScriptEngine 类一起使用。例如...
ScriptEngineManager sem = new ScriptEngineManager();
scriptEngine = sem.getEngineByExtension(".lua");
script = ((Compilable)scriptEngine).compile("some lua here");
However, this is apparently not supported on Android (something to do with android not having a full blown JVM, I read somewhere). Is there a way I can use Lua scripts on Android? Maybe there's a LuaJ alternative? Perhaps there is a way of compiling and executing Lua scripts using LuaJ directly (though I can't see how).
但是,这显然在 Android 上不受支持(与 android 没有完整的 JVM 有关系,我在某处读到过)。有没有办法在 Android 上使用 Lua 脚本?也许有 LuaJ 替代品?也许有一种直接使用 LuaJ 编译和执行 Lua 脚本的方法(虽然我看不出是怎么做的)。
FYI, I see this error when I try to run this code on Android:
仅供参考,当我尝试在 Android 上运行此代码时看到此错误:
05-06 16:12:32.870: E/dalvikvm(17509): Could not find class 'javax.script.ScriptEngineManager', referenced from method unearth.levels.LevelReader.<init>
05-06 16:12:32.870: W/dalvikvm(17509): VFY: unable to resolve new-instance 787 (Ljavax/script/ScriptEngineManager;) in Lunearth/levels/LevelReader;
05-06 16:12:32.870: D/dalvikvm(17509): VFY: replacing opcode 0x22 at 0x0018
05-06 16:12:32.875: E/dalvikvm(17509): Could not find class 'javax.script.Compilable', referenced from method unearth.levels.LevelReader.parseScript
05-06 16:12:32.875: W/dalvikvm(17509): VFY: unable to resolve check-cast 782 (Ljavax/script/Compilable;) in Lunearth/levels/LevelReader;
05-06 16:12:32.875: D/dalvikvm(17509): VFY: replacing opcode 0x1f at 0x0047
05-06 16:12:32.875: W/dalvikvm(17509): VFY: unable to resolve exception class 788 (Ljavax/script/ScriptException;)
05-06 16:12:32.875: W/dalvikvm(17509): VFY: unable to find exception handler at addr 0x51
05-06 16:12:32.875: W/dalvikvm(17509): VFY: rejected Lunearth/levels/LevelReader;.parseScript (Lorg/w3c/dom/Element;Lunearth/levels/Level;)V
05-06 16:12:32.875: W/dalvikvm(17509): VFY: rejecting opcode 0x0d at 0x0051
05-06 16:12:32.875: W/dalvikvm(17509): VFY: rejected Lunearth/levels/LevelReader;.parseScript (Lorg/w3c/dom/Element;Lunearth/levels/Level;)V
05-06 16:12:32.875: W/dalvikvm(17509): Verifier rejected class Lunearth/levels/LevelReader;
05-06 16:12:32.890: W/dalvikvm(17509): threadid=11: thread exiting with uncaught exception (group=0x40c331f8)
05-06 16:12:32.895: E/AndroidRuntime(17509): FATAL EXCEPTION: GLThread 1062
05-06 16:12:32.895: E/AndroidRuntime(17509): java.lang.VerifyError: unearth/levels/LevelReader
05-06 16:12:32.895: E/AndroidRuntime(17509): at unearth.Game.startGame(Game.java:201)
05-06 16:12:32.895: E/AndroidRuntime(17509): at unearth.Game.update(Game.java:713)
05-06 16:12:32.895: E/AndroidRuntime(17509): at unearth.screens.LoadScreen.update(LoadScreen.java:56)
05-06 16:12:32.895: E/AndroidRuntime(17509): at unearth.UnearthListener.render(UnearthListener.java:71)
05-06 16:12:32.895: E/AndroidRuntime(17509): at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(AndroidGraphics.java:423)
05-06 16:12:32.895: E/AndroidRuntime(17509): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1462)
05-06 16:12:32.895: E/AndroidRuntime(17509): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1216)
05-06 16:12:58.600: D/dalvikvm(17509): GC_CONCURRENT freed 334K, 3% free 16196K/16647K, paused 2ms+6ms
Update:
更新:
Maybe this project has some useful code? http://code.google.com/p/android-scripting/
也许这个项目有一些有用的代码?http://code.google.com/p/android-scripting/
采纳答案by Nick Bolton
I found a way of using LuaJ on Android! :-)
我找到了一种在 Android 上使用 LuaJ 的方法!:-)
The key is to use the LuaJ API directly as opposed to through javax.script
. It's a little tricky to figure out as there's no tutorials, so here's a before and after so that others don't have to go through picking through the LuaJ source code and JavaDoc. I really hope this helps someone as it drove me bonkers!
关键是直接使用 LuaJ API,而不是通过javax.script
。由于没有教程,弄清楚这有点棘手,所以这里有一个之前和之后,以便其他人不必通过挑选 LuaJ 源代码和 JavaDoc。我真的希望这对某人有所帮助,因为它让我发疯了!
Note:"secretgame" isn't the actual name of my game ;-)
注意:“secretgame”不是我游戏的实际名称;-)
After:
后:
package secretgame.scripting;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import org.luaj.vm2.LuaClosure;
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Prototype;
import org.luaj.vm2.compiler.LuaC;
import org.luaj.vm2.lib.jse.CoerceJavaToLua;
import org.luaj.vm2.lib.jse.JsePlatform;
import secretgame.SecretGameException;
import secretgame.events.EventArgs;
import secretgame.levels.Level;
public class DirectLuaj implements Lua
{
private final Level level;
private final ScriptTools scriptTools;
private final ScriptEvents scriptEvents;
private int nextId = 0;
private ArrayList<LuaClosure> scripts = new ArrayList<LuaClosure>();
public DirectLuaj(Level level, ScriptTools scriptTools,
ScriptEvents scriptEvents)
{
this.level = level;
this.scriptTools = scriptTools;
this.scriptEvents = scriptEvents;
}
@Override
public int add(String scriptText) throws SecretGameException
{
try {
InputStream input = new ByteArrayInputStream(scriptText.getBytes());
Prototype p = LuaC.compile(input, "script");
LuaValue g = JsePlatform.standardGlobals();
LuaClosure c = new LuaClosure(p, g);
scripts.add(c);
}
catch (IOException e) {
throw new SecretGameException("compile failed", e);
}
return nextId++;
}
@Override
public void run(int id, EventArgs args) throws SecretGameException
{
LuaClosure script = scripts.get(id);
LuaTable bindings = new LuaTable();
bindings.set("java", toLua(scriptTools));
bindings.set("level", toLua(level));
bindings.set("args", toLua(args));
bindings.set("events", toLua(scriptEvents));
script.setfenv(bindings);
script.call();
}
private LuaValue toLua(Object javaValue) {
return javaValue == null? LuaValue.NIL:
javaValue instanceof LuaValue? (LuaValue) javaValue:
CoerceJavaToLua.coerce(javaValue);
}
}
Before:
前:
package secretgame.scripting;
import java.util.ArrayList;
import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import secretgame.SecretGameException;
import secretgame.events.EventArgs;
import secretgame.levels.Level;
// sadly this won't work on Android because there's no such thing
// as javax.script in Dalvik ... dumb Android java :|
public class JavaxScriptingLua implements Lua
{
private ScriptEngine scriptEngine;
private final Level level;
private final ScriptTools scriptTools;
private final ScriptEvents scriptEvents;
private int nextId = 0;
private ArrayList<CompiledScript> scripts = new ArrayList<CompiledScript>();
public JavaxScriptingLua(Level level, ScriptTools scriptTools, ScriptEvents scriptEvents)
{
this.level = level;
this.scriptTools = scriptTools;
this.scriptEvents = scriptEvents;
ScriptEngineManager sem = new ScriptEngineManager();
scriptEngine = sem.getEngineByExtension(".lua");
}
public int add(String scriptText) throws SecretGameException
{
try {
CompiledScript script = ((Compilable)scriptEngine).compile(scriptText);
scripts.add(script);
}
catch (ScriptException e) {
throw new SecretGameException("could not compile lua.", e);
}
return nextId++;
}
public void run(int id, EventArgs args) throws SecretGameException
{
Bindings bindings = scriptEngine.createBindings();
bindings.put("java", scriptTools);
bindings.put("level", level);
bindings.put("args", args);
bindings.put("events", scriptEvents);
try {
scripts.get(id).eval(bindings);
}
catch (ScriptException e) {
throw new SecretGameException("could not run script.", e);
}
}
}
回答by Michal Kottman
Instead of LuaJ you can (also) use LuaJava together with Lua compiled for Android using the NDK. This allows Lua full access to whatever is available from Java. Take a look at this exampleto see how to get started.
除了 LuaJ,您还可以(也)将 LuaJava 与使用 NDK 为 Android 编译的 Lua 一起使用。这允许 Lua 完全访问 Java 中可用的任何内容。看看这个例子,看看如何开始。
Lua 5.1.4 + LuaJava compiled are provided in the libs
directory (a single libluajava.so
file) if you do not want to fiddle with the NDK, but it is relatively easy to set up anyway.
libs
目录下提供了Lua 5.1.4 + LuaJava 编译(单个libluajava.so
文件),如果你不想摆弄NDK,但无论如何设置起来相对容易。
回答by Danke Xie
To use Lua on Android, you can use JNLua + Lua 5.2 (implemented in C). The only Android port with JSR 223 (javax.script) support is here: https://github.com/danke-sra/jnlua-android
要在 Android 上使用 Lua,您可以使用 JNLua + Lua 5.2(用 C 实现)。唯一支持 JSR 223 (javax.script) 的 Android 端口在这里:https: //github.com/danke-sra/jnlua-android
Using this port, you can do what you want:
使用这个端口,你可以做你想做的:
ScriptEngine scriptEngine = new LuaScriptEngineFactory().getEngine();
scriptEngine.eval("lua statements");
ScriptEngine scriptEngine = new LuaScriptEngineFactory().getEngine();
scriptEngine.eval("lua statements");
回答by CommonsWare
However, this is apparently not supported on Android
但是,这显然在 Android 上不受支持
Correct.
正确的。
something to do with android not having a full blown JVM, I read somewhere
与android没有完整的JVM有关,我在某处读过
Correct. If you look at the JavaDocs, you will see that javax.script
does not exist in the Android SDK.
正确的。如果您查看JavaDocs,您会发现javax.script
Android SDK 中不存在该文件。
Maybe I'll give this a try: https://github.com/damonkohler/sl4a
也许我会尝试一下:https: //github.com/damonkohler/sl4a
That is one option. Another is to embed the Lua interpreter in your app via the NDK, as in this sample application.
那是一种选择。另一种方法是通过 NDK 在您的应用程序中嵌入 Lua 解释器,如本示例应用程序中所示。