
Je pense que de nombreux lecteurs du hub de développement Android ont entendu dire que Java vous permet de modifier le dex d'une application déjà installée en
runtime via
ClassLoader . En utilisant cela, vous pouvez charger du code compilé en runtime et l'utiliser. Mais Google traite ces fraudes, pour le dire avec douceur, pas trop loyalement et interdit ceux qui sont pris dans une telle application.
Cependant, il existe d'autres façons de télécharger et d'exécuter des scripts sur un appareil mobile. Pour plus de détails sous le chat!
Ainsi, bien que nous ne puissions pas mettre à jour les applications dex en runtime, nous pouvons utiliser des interprètes de langages de script entièrement écrits en Java. Ainsi, Oracle, à partir de la version 6, inclut le moteur jhascript Rhino dans la JVM. Cela s'est produit grâce à l'implémentation de la spécification JSR-223, qui déclare la prise en charge des langages de programmation de script en Java.
Actuellement, il existe plusieurs moteurs intégrés pour des langages de programmation populaires tels que: Lua (Luaj), Python (Jython), Ruby (Jruby) et java-script (Rhino, ...). Chacun d'eux vous permet à la fois d'exécuter des scripts et d'accéder à des fonctions écrites en Java.
Pour démontrer les possibilités, je propose de mettre en place un «environnement» de développement. Je vais laisser un lien vers les sources à la fin de l'article. Afin de ne pas encombrer l'exemple, je me concentrerai sur Lua, bien que rien ne vous empêche de connecter tous les moteurs en même temps et de basculer entre eux. La version actuelle de JLua au moment de la rédaction est disponible dans mvnrepository:
org.luaj: luaj-jse: 3.0.1 .
Chaque environnement de développement qui se respecte devrait avoir un champ pour entrer un script, un champ pour afficher le résultat et un bouton qui vous permet de compléter votre idée.
UI d'un environnement de développement qui se respecte:
<?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>
Pour exécuter le script Lua, nous devons obtenir l'environnement global dans lequel il sera exécuté -
Globals . Luaj vous permet de le personnaliser, par exemple, en définissant des variables ou en ajoutant des classeurs aux classes Java. Une opportunité importante pour nous ici sera de définir des flux de sortie de messages, car
java.lang.System.out ,
java.lang.System.err est utilisé par défaut, ce qui n'est pas très pratique lorsque vous devez afficher le résultat de l'exécution dans TextView. Pour changer cela, vous devez redéfinir les valeurs
Globals # STDOUT et
Globals # STDERR .
Ainsi, il ne nous reste plus qu'à charger notre craquement dans l'environnement et à l'exécuter.
Voici à quoi cela ressemble dans mon exemple:
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() } }
Essayons maintenant d'étendre l'ensemble des fonctions disponibles avec la possibilité d'afficher
Toast en utilisant la liaison ci-dessus des classes Java. Rendez-le facile en utilisant
CoerceJavaToLua :
globals.set("bubble", CoerceJavaToLua.coerce(Bubble(this))) ... private class Bubble(private val context: Context) {
Le résultat que j'ai obtenu est le suivant:

Ainsi, avec un petit exemple, nous avons considéré la possibilité d'exécuter des scripts à l'intérieur d'une application mobile. Un lecteur curieux peut deviner que les scripts peuvent être téléchargés à partir des ressources, des ressources d'application ou du serveur. Ce qui peut être utile, par exemple, dans les jeux. Heureusement, luaj est compatible avec l'un des frameworks de jeu Java les plus populaires - Libgdx. En général, la portée ici n'est limitée que par l'imagination du développeur.
→
Exemples de sources→
Luaj→
Jython→
Jruby→
Rhino (
wrapper android )