
我认为许多android开发中心的读者都听说过Java允许您通过
ClassLoader在
运行时修改已经安装的应用程序的dex。 使用此功能,您可以在运行时加载已编译的代码并使用它。 但是Google对待此类欺诈行为要轻描淡写,不要太忠诚,并禁止被此类应用程序捕获的欺诈行为。
但是,还有其他方法可以在移动设备上下载和执行脚本。 有关猫下的详细信息!
因此,尽管我们无法在运行时更新dex应用程序,但可以使用完全用Java编写的脚本语言的解释器。 因此,从版本6开始,Oracle在JVM中包含了jhascript引擎Rhino。 这要归功于JSR-223规范的实现,该规范声明了对Java脚本语言的支持。
当前,有几种内置的引擎可用于流行的编程语言,例如:Lua(Luaj),Python(Jython),Ruby(Jruby)和Java脚本(Rhino,...)。 它们中的每一个都允许您执行脚本和访问用Java编写的函数。
为了说明这种可能性,我建议实施开发“环境”。 我将在文章结尾处留下一个到资源的链接。 为了不弄乱示例,我将重点介绍Lua,尽管没有什么可以阻止您同时连接所有引擎并在它们之间进行切换。 撰写本文时,JLua的当前版本可在mvnrepository:
org.luaj:luaj-jse:3.0.1中获得 。
每个自重的开发环境都应具有一个用于输入脚本的字段,一个用于显示结果的字段以及一个使您完成自己的构想的按钮。
自尊的开发环境的用户界面:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <EditText android:id="@+id/scriptInput" android:layout_width="0dp" android:layout_height="0dp" android:gravity="top|start" android:hint="@string/write_script" android:inputType="textMultiLine" android:padding="4dp" android:textColor="#000000" app:layout_constraintBottom_toTopOf="@id/scriptOutput" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/scriptOutput" android:layout_width="0dp" android:layout_height="0dp" android:hint="@string/script_output" android:padding="4dp" android:textColor="#000000" app:layout_constraintBottom_toTopOf="@id/executeButton" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/scriptInput" /> <Button android:id="@+id/executeButton" android:layout_width="0dp" android:layout_height="48dp" android:text="@string/run_script" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
为了执行Lua脚本,我们需要获取将在其中执行脚本的全局环境
-Globals 。 Luaj允许您自定义它,例如,通过设置变量或向Java类添加活页夹。 对于我们来说,这里的一个重要机会是设置消息输出流,因为默认情况下使用
java.lang.System.out ,
java.lang.System.err ,这在您需要在TextView中显示执行结果时不是很方便。 要更改此设置,您需要重新定义值
Globals#STDOUT和
Globals#STDERR 。
因此,现在我们只需要将吱吱声加载到环境中并执行即可。
这是我的示例中的样子:
private fun runLua(script: String) { val charset = StandardCharsets.UTF_8 val globals = JsePlatform.standardGlobals() val outStream = ByteArrayOutputStream() val outPrintStream = PrintStream(outStream, true, charset.name()) globals.STDOUT = outPrintStream globals.STDERR = outPrintStream try { globals.load(script).call() scriptOutput.setTextColor(Color.BLACK) scriptOutput.text = String(outStream.toByteArray(), charset) } catch (e: LuaError) { scriptOutput.setTextColor(Color.RED) scriptOutput.text = e.message } finally { outPrintStream.close() } }
现在,让我们尝试使用上述Java类绑定来扩展可用功能集,以显示
Toast 。 使用
CoerceJavaToLua使其变得容易:
globals.set("bubble", CoerceJavaToLua.coerce(Bubble(this))) ... private class Bubble(private val context: Context) {
我得到的结果是这样的:

因此,通过一个小示例,我们考虑了在移动应用程序内部运行脚本的可能性。 好奇的读者可以猜测,可以从资产,应用程序资源或服务器中下载脚本。 什么是有用的,例如在游戏中。 幸运的是,luaj与最流行的游戏Java框架之一-Libgdx兼容。 通常,这里的范围仅受开发人员的想象力限制。
→
样品来源→
鲁阿吉→
Jython→
茹比→
犀牛 (
android包装器 )