
أعتقد أن العديد من قراء مركز تطوير android قد سمعوا أن Java تسمح لك بتعديل التنفيذ المباشر للتطبيق المثبت بالفعل في
وقت التشغيل عبر
ClassLoader . باستخدام هذا ، يمكنك تحميل التعليمات البرمجية المترجمة في وقت التشغيل واستخدامها. لكن جوجل تتعامل مع مثل هذه الاحتيالات ، بعبارة ملطفة ، وليس بإخلاص شديد ، وتحظر على أولئك الذين وقعوا في مثل هذا الطلب.
ومع ذلك ، هناك طرق بديلة لتنزيل وتنفيذ البرامج النصية على جهاز محمول. لمزيد من التفاصيل تحت القط!
لذلك ، على الرغم من أننا لا نستطيع تحديث تطبيقات dex في وقت التشغيل ، إلا أنه يمكننا استخدام مترجمين بلغات البرمجة النصية المكتوبة بالكامل في Java. لذا فإن Oracle ، بدءًا من الإصدار 6 ، يتضمن محرك jhascript Rhino في JVM. حدث هذا بفضل تطبيق مواصفات JSR-223 ، والتي تعلن عن دعم Java بلغات البرمجة النصية.
يوجد حاليًا العديد من المحركات المدمجة في لغات البرمجة الشائعة مثل: Lua (Luaj) و Python (Jython) و Ruby (Jruby) و java-script (Rhino، ...). كل واحد منهم يسمح لك بتنفيذ البرامج النصية والوصول إلى وظائف مكتوبة بلغة جافا.
كدليل على الاحتمالات ، أقترح تنفيذ "بيئة" التنمية. سأترك رابطًا إلى المصادر في نهاية المقال. لكي لا أفسد المثال ، سأركز على 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() } }
الآن دعونا نحاول توسيع مجموعة الوظائف المتاحة مع إمكانية إظهار
Toast باستخدام الربط أعلاه لفئات Java. اجعل الأمر سهلاً باستخدام
CoerceJavaToLua :
globals.set("bubble", CoerceJavaToLua.coerce(Bubble(this))) ... private class Bubble(private val context: Context) {
النتيجة التي حصلت عليها هي:

وبالتالي ، مع مثال صغير ، درسنا إمكانية تشغيل البرامج النصية داخل تطبيق الهاتف المحمول. يمكن للقارئ الفضائي تخمين إمكانية تنزيل البرامج النصية من الأصول أو موارد التطبيق أو من الخادم. ما يمكن أن يكون مفيدا ، على سبيل المثال ، في الألعاب. لحسن الحظ ، فإن luaj متوافق مع أحد أكثر أطر عمل java للألعاب شيوعًا - Libgdx. بشكل عام ، يقتصر النطاق هنا فقط من خيال المطور.
→
مصادر العينة→
لواج→
جايثون→
Jruby→
الكركدن (
غلاف أندرويد )