Android应用程序内部脚本的和谐



我认为许多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.outjava.lang.System.err ,这在您需要在TextView中显示执行结果时不是很方便。 要更改此设置,您需要重新定义值Globals#STDOUTGlobals#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) { // called from lua fun show(message: String) { Toast.makeText(context, message, Toast.LENGTH_SHORT).show() } } 

我得到的结果是这样的:



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

样品来源
鲁阿吉
Jython
茹比
犀牛android包装器

Source: https://habr.com/ru/post/zh-CN452236/


All Articles