الإنتقال إلى المحتوى

قصة Rustroid (وقصتي أيضاً، على ما أعتقد)

إذا لم تكن تعرف بالفعل، Rustroid هو بيئة تطوير متكاملة للغة Rust على نظام أندرويد تعمل محلياً على الجهاز.

كل شيء بدأ مع ماينكرافت

في الماضي، كنت طفلاً في الثانية عشرة من عمري أشاهد مستخدمي يوتيوب وهم يلعبون على سيرفرات ماينكرافت إصدار جافا مع مودات. كانت المودات رائعة ومذهلة، وأردت أن أجربها.
أحد المودات التي أردت تجربتها بشدة كان مود Morph. إنه مود يسمح لك بأن تصبح أي مخلوق تقتله.

لكن لم يكن لدي جهاز كمبيوتر أو حتى ماينكرافت جافا. كل ما كان لدي هو هاتف محمول مع ماينكرافت إصدار Bedrock، والذي لم يكن يحتوي على أي مودات مذهلة. لذلك، قررت أن أحاول إنشاء مود بنفسي لإصدار الهاتف المحمول. لم أكن أعرف ماذا أفعل أو من أين أبدأ. قمت فقط بتنزيل مجموعة من المودات وحاولت فتح ملفاتها لفهم كيف تعمل.

في تلك اللحظة، أدركت أن نظام أندرويد يفتقر إلى أي نوع من أدوات المطورين.

في ذلك الوقت، كانت جميع مودات Bedrock مجرد ملفات JSON. كنت أرغب في محرر JSON، وكل ما استطعت إيجاده هو تطبيق اسمه QuickEdit. لم يكن متطوراً جداً، لكنه كان يحتوي على ميزات مفيدة مثل تلوين الأكواد، التراجع/الإعادة، والبحث/الاستبدال. ومع ذلك، كان يفتقر إلى المدقق اللغوي، والإكمال التلقائي، والتشخيصات، أو أي من الميزات التي تجعل المبرمجين سعداء.

في النهاية، بدأت في نسخ ولصق بعض الأجزاء من هنا وهناك، وأنشأت أكثر مود Morph تطوراً لإصدار Bedrock في ذلك الوقت، باستخدام هاتفي المحمول فقط.

وبعد ذلك حذفت المود وانتقلت إلى أمور أخرى، ولكن هذا ليس مربط الفرس في هذه المقالة. 😃

الانتقال من ماينكرافت

بعد ما أسميه نجاحاً كبيراً، أردت أن أنتقل وأفعل أشياء أخرى. أردت أن أفعل المزيد.

بدأت في تجربة لغة جافا لأنني أردت أن أعرف كيف أصنع لعبة يمكنها منافسة ماينكرافت (والتي، بالمناسبة، كانت فكرة سخيفة)، مرة أخرى كل ذلك من هاتفي الأندرويد. بدأت في مشاهدة سلسلة تعليمية جيدة جداً من RyiSnow حول إنشاء لعبة مغامرات ثنائية الأبعاد من الأعلى رابط قائمة التشغيل.

شرحت السلسلة التعليمية كيفية إنشاء لعبة ثنائية الأبعاد باستخدام رسوميات Java swing/awt. وكما تعلم، فإن نظام أندرويد مبني على لغة جافا، لذا يجب أن يعمل كل شيء، أليس كذلك؟

حسناً، لا. اتضح أن أندرويد لا يتضمن جافا الكاملة. بل يتضمن أجزاء منها فقط، ولا يتم تضمين Java swing/awt. ولكن لدى أندرويد بديل. تتكون تطبيقات أندرويد من Activity، وهو نقطة الدخول للتطبيق.

و View الذي هو بمثابة البديل لـ JComponent، والـView تحتوي على دالة onDraw(Canvas) المسؤولة عن رسم الأشياء على الشاشة. وهي مشابهة جداً لدالة JComponent.paintComponent(Graphics) في جافا. لذلك، بدأت في متابعة السلسلة التعليمية، ولكنني استبدلت أي شيء متعلق بـ Swing بالبديل الخاص بأندرويد.

البداية الصغيرة

أردت إنشاء بيئة تطوير متكاملة لجافا باستخدام CodeAssist. أعرف، فكرة أصيلة جداً. ولكنك دائماً تريد تكرار الأدوات التي تستخدمها. حاولت استخدام CodeAssist لإنشائها، وأود أن أقول إنني وصلت إلى مكان ما. أصبحت على دراية بـ Android SDK وكيف يعمل توليد APK، ومترجم جافا، وأشياء أخرى.

ولكن مرة أخرى، هذا ليس ما تدور حوله هذه المقالة.

البداية الحقيقية

أخيراً حصلت على جهاز كمبيوتر. جربت Rust لأرى سبب كل هذه الضجة حولها، ونعم، لقد أحببت نظامها البيئي نوعاً ما. كما تعلمون، كل شيء في مكان واحد: المترجم، مدير الحزم، جناح الاختبار، التوثيق - كلها واحدة ونفس الشيء (تسمى cargo).

قمت بتثبيت Android Studio، وأنشأت مشروعاً جديداً، ورميت حرفياً كل شيء آخر كنت قد أنشأته. سميت المشروع Rustroid.

قد تسأل لماذا أنشأت بيئة تطوير متكاملة لRust وليس لجافا. حسناً، كان هناك ثلاثة أسباب (أو ربما أكثر، لا أعرف، هههه).

  1. اكتشفت أن Rust هي اللغة الأكثر إعجاباً.
  2. كان هناك بيئة تطوير متكاملة جيدة جداً لنظام أندرويد كان العمل جارياً عليها، تسمى AndroidIDE. (AndroidIDE أيضاً لم يعد يتم صيانته الآن. 😕)
  3. لقد أحببت اللغة.

عندما كنت أنشئ المشروع، قمت بضبط اللغة على جافا وكنت سأصنع التطبيق باستخدام نهج مبني على العروض (views)، كما اعتدت على هاتفي. لكنني أردت تجربة كوتلين مع Jetpack Compose لأن كوتلين و Jetpack Compose كانا الخيارات الافتراضية الموصى بها في Android Studio للمشاريع الجديدة. ويا للهول، لقد وقعت في حب كوتلين و Jetpack Compose. لم أعد إلى جافا بعد ذلك.

كيف يعمل Rustroid؟

لفهم كيف يعمل Rustroid، عليك أولاً أن تفهم كيف يعمل أندرويد. أندرويد هو نظام تشغيل مبني على لينكس، مما يعني أنه يشارك نفس الأجزاء الداخلية لتوزيعة لينكس كاملة الميزات. وأندرويد يدعم جافا، والتي بدورها تدعم Process والقدرة على تشغيل الـBinaries. لذا يجب أن يكون من الممكن تشغيل Rust على أندرويد. كنت فقط بحاجة إلى الحصول على إصدار Rust الذي تم تجميعه لـ aarch64-linux (الـArchitecture الخاص ب هاتفي) وتشغيله على أندرويد، ويجب أن يعمل، أليس كذلك؟

حسناً، لا. اتضح أن هناك اختلافاً جوهرياً بين الـBinaries الخاصة بتوزيعات لينكس العادية والـBinaries الخاصة بأندرويد. الـBinaries الخاصة بلينكس مرتبطة بـ gnu's libc، بينما أندرويد مرتبط بـ bionic's libc.

التنفيذ

اكتشفت أن هناك مجموعة من الأشخاص يقومون بتحويل كل حزمة لينكس تقريباً إلى أندرويد. كيف؟ حسناً، يقومون بتجميعها باستخدام Android NDK، الذي يربطها بـ bionic's libc. هؤلاء الأشخاص هم من يقفون وراء Termux (محاكي طرفية لنظام أندرويد). لذلك، قمت بنسخ Rust المجمعة مع تبعياتها، وقمت بترقيع بعض أجزائها، وتادا، إنها تعمل.

ملاحظة

عندما ذكرت الأشخاص وراء Termux، كنت أشير إلى مشروع Termux-Packages. الحزم التي يقومون بتجميعها مرخصة بنفس ترخيص الحزمة الأصلية، لذا على سبيل المثال، فإن حزمة Rust الخاصة بهم مرخصة إما بموجب ترخيص Apache 2.0 أو ترخيص MIT.
يمكنك أيضًا العثور على جميع معلومات التراخيص في شاشة "حول" في تطبيقي.

الآن، ما الذي تحتاجه بيئة التطوير المتكاملة (IDE)؟

  1. محرر أكواد قوي (مع LSP)
  2. محاكي طرفية (terminal)
  3. مستكشف ملفات وواجهة جيدة

الجزء الثالث كان الأسهل ولم يكن صعباً جداً، أود أن أقول.

محرر الأكواد

أردت تنفيذ محرر الأكواد على الأقل بالميزات التالية:

  • مخزن نصوص (Text Buffer) سريع وفعال من حيث الذاكرة.
  • مدير تراجع وإعادة (undo and redo).
  • تلوين الأكواد باستخدام TextMate.
  • تكامل مع LSP.

مخزن النصوص (The Text Buffer)

في البداية، كتبته باستخدام مصفوفة من الأسطر، لكن الأداء لم يكن جيداً، وكانت له عدة عيوب. ولكن بعد ذلك، لفتت نظري هذه المقالة من VS Code: إعادة تطبيق مخزن نصوص VS Code. إنها مقالة رائعة، أوصي بأن تلقي نظرة عليها. من مقالة VS Code:

النموذج العقلي للمحرر هو نموذج قائم على الأسطر. يقرأ المطورون ويكتبون الكود البرمجي سطراً بسطر، وتوفر المترجمات تشخيصات قائمة على السطر/العمود، وتتضمن تتبعات المكدس أرقام الأسطر، وتعمل محركات الترميز سطراً بسطر، وما إلى ذلك. على الرغم من بساطته، لم يتغير تطبيق مخزن النصوص الذي يدعم VS Code كثيراً منذ اليوم الأول الذي بدأنا فيه مشروع Monaco. استخدمنا مصفوفة من الأسطر.

ومع ذلك، استمررنا في تلقي تقارير تفيد بأن فتح ملفات معينة يتسبب في تعطلات بسبب نفاد الذاكرة (Out-Of-Memory) في VS Code. على سبيل المثال، فشل مستخدم في فتح ملف بحجم 35 ميجابايت. كان السبب الجذري هو أن الملف يحتوي على عدد كبير جداً من الأسطر - 13.7 مليون سطر. كنا ننشئ كائن ModelLine لكل سطر، وكل كائن كان يستخدم حوالي 40-60 بايت، لذلك استخدمت مصفوفة الأسطر حوالي 600 ميجابايت من الذاكرة لتخزين المستند. وهذا يعادل تقريباً 20 ضعف حجم الملف الأصلي!

مشكلة أخرى في تمثيل مصفوفة الأسطر كانت سرعة فتح الملف. لبناء مصفوفة الأسطر، كان علينا تقسيم المحتوى حسب فواصل الأسطر، بحيث نحصل على كائن سلسلة نصية (string) لكل سطر. التقسيم بحد ذاته يضر بالأداء، كما سترى في الاختبارات المعيارية لاحقاً.

أعلم أن هذا لا ينبغي أن يكون مشكلة لتطبيقي، حيث لن يفتح أحد مثل هذه الملفات الكبيرة على هاتفه الذكي، أليس كذلك؟ حسناً، نعم! لكنني قمت بتنفيذ مخزن شجرة القطع (piece tree buffer) على أي حال. 😉

استغرق الأمر بضعة أيام، لكنه كان يعمل، وقمت بتحويل اختبارات مخزن شجرة القطع الخاص بـ VS Code إلى كوتلين. وجميعها اجتازت الاختبار.

بالمناسبة، أنا لا أكتب اختبارات لبرمجي. إما أن أسر... أعني، أنسخها، أو أترك الكود بدون اختبارات.


مدير التراجع والإعادة (The Undo & Redo Manager)

حسناً، لم يكن هذا صعباً. فقط قم بإنشاء قائمة من فئة Action التي تحتوي على طريقة undo و redo، وقم بإنشاء متغير فهرس. قم بإدراج/حذف النص بناءً على ما إذا كنا نقوم بالتراجع أو الإعادة. عند التراجع، قم بتقليل الفهرس، وعند الإعادة، قم بزيادة الفهرس. وهذا كل شيء.


تلوين الأكواد (The Syntax Highlighting)

حسناً، قمت فقط بتحويل تطبيق TextMate الخاص بـ VS Code إلى كوتلين واستخدمته. بالمناسبة، تحويل كود مايكروسوفت ليس بهذه السهولة؛ مجرد قولي إنني قمت بتحويله لا يعني أنه سهل. أعتقد أنهم يحاولون جعل الكود أكثر تعقيداً مما هو مطلوب عن قصد. لذا، نعم.


LSP (الجزء الأساسي من بيئة التطوير المتكاملة)

الـLSP تعني بروتوكول خادم اللغة.
وهو بروتوكول يسمح للعميل (الـClient) بالتواصل مع الخادم (الـServer) للحصول علي معلومات حول كل ما يتعلق باللغة.

أول شيء يجب فعله هو قراءة مواصفات LSP.

ملخص البروتوكول هو أن بيئة التطوير (العميل) وخادم اللغة يتواصلان من خلال std in & out أو TCP، أو مقابس Unix، أو أي شيء آخر، وهو مبني على JSON-RPC.

يتكون البروتوكول الأساسي من رأس وجزء محتوى (يشبه HTTP). يتم فصل الرأس وجزء المحتوى بـ \r\n.
يحتوي جزء الرأس على Content-Length، الذي يحدد طول المحتوى. هذا ضروري لمعرفة متى تنتهي الرسالة.
يستخدم جزء المحتوى JSON-RPC لوصف الطلبات والاستجابات والإشعارات.

بفضل فئات كوتلين sealed classes و kotlinx.serialization، لم يكن تنفيذ LSP صعباً جداً. وهذا كل شيء: يرسل العميل والخادم مجموعة من الطلبات/الاستجابات لبعضهما البعض، وتادا، كل شيء يعمل!


الطرفية (The Terminal)

أخذت جزء محاكاة الطرفية من Jackpal's Android Terminal Emulator، وقمت بتحويله إلى كوتلين، وقمت بتحويله إلى كود Jetpack Compose بدلاً من كود خاص بأندرويد، وقمت بإصلاح بعض الأخطاء - كما تعلمون، أشياء من هذا القبيل.

أشياء أخرى

كما تعلمون، هناك أشياء أخرى يجب أخذها في الاعتبار: يحتاج محرر الأكواد إلى قياس النص وتقديم النص، والتعامل مع التمرير، وتحديث موضع المؤشر، والتأكد من أن المؤشر ليس في منتصف زوج بديل (surrogate pair).

ملاحظة

جافا لا تستخدم UTF-8 بل تستخدم UTF-16، لذا بعض الأحرف (مثل الرموز التعبيرية) تحتوي على نقطتين ترميزيتين بدلاً من واحدة.

إنشاء إطارات منبثقة للتحويم (hover)، ومساعدة التوقيع (signature help)، والإكمال (completion)، والتشخيصات (diagnostics)، والانتقال إلى التعريف (go-to-definition)، والتصريح (declaration)، والتنفيذ (implementation)، وما إلى ذلك.
تنفيذ محلل الـSnippets الأكواد (لأن LSP قد يرسل الـSnippets)
تنفيذ خوارزمية فرز غامضة لفرز عناصر الإكمال (لأنها لا يتم فرزها بشكل افتراضي)
وبالطبع، مولد APK، الذي يقوم بتجميع الكود الخاص بك في مكتبة مشتركة (shared library) ثم يضغطها، ويرتبها، ويوقعها، والعديد من الأشياء الأخرى التي يجب أخذها في الاعتبار.

نشر التطبيق

في البداية، أردت أن أجعله مفتوح المصدر وأنشره على جوجل بلاي حتى أتمكن من الحصول على مساهمين من جميع أنحاء العالم، وفي نفس الوقت، أجعله متاحاً لجميع مستخدمي أندرويد تقريباً.

في الواقع، في وقت مبكر، قمت بالفعل بنشر الكود المصدري على GitLab لمدة 3 أيام تقريباً. ولكن بعد ذلك قمت بحذفه.

لماذا ليس مفتوح المصدر

كما ترون، لم يعد يتم صيانة CodeAssist و AndroidIDE. أعتقد أن هذا يرجع إلى نقص التمويل، مما يزيل تماماً الدافع لمواصلة تطويرهما. بالتأكيد، هناك تبرعات تأتي بين الحين والآخر، ولكن هذا لا يكفي لجعل شخص ما يواصل العمل على مشروع، خاصة إذا لم يكن لديه وظيفة ولا مصدر دخل آخر (مثلي). ربما، فقط ربما، في المستقبل، سأعيد النظر في جعله مفتوح المصدر لإفادة المجتمع وحتى نفسي.

التوزيع مغلق المصدر

الآن هناك أربعة خيارات لتوزيع التطبيق.

  1. توزيعه مجاناً بدون إعلانات.
  2. توزيعه مجاناً مع إعلانات.
  3. توزيعه مجاناً مع ميزات محدودة وتقديم عمليات شراء داخل التطبيق لفتح إمكاناته الكاملة.
  4. توزيعه عن طريق شراء لمرة واحدة.

لا يمكنني اختيار رقم واحد، لأن ذلك سيجعلني مفلساً 😃.
بجدية، إذا كنت ستجعله مجانياً، فاجعله مفتوح المصدر فقط.

ولا يمكنني اختيار رقم اثنين أيضاً. لا أحب فكرة الإعلانات؛ إنها مزعجة حقاً، وأنا فقط لا أحبها.

الآن الأمر كله يتعلق بالخيارين الثالث والرابع. الخيار الثالث ليس سيئاً جداً. لكنني لا أحبه كثيراً؛ أفضل توزيع التطبيق بإمكاناته الكاملة، لأي شخص يمكنه الحصول عليه.

لذلك لم يتبق سوى الخيار الرابع: جعله مدفوعاً. ونعم، هذا ما فعلته، لكنني لا أعتقد أنه باهظ الثمن، مع ذلك. (وأخطط للحفاظ على ذلك). هذا لأن التطبيق يستهدف أولئك الذين ليس لديهم أجهزة كمبيوتر، لذلك لا أعتقد أنه من العدل أن أجعله باهظ الثمن.

التطبيق معروض حالياً للبيع مقابل 4.50 دولار أمريكي فقط، لكن سعره العادي هو 7.00 دولار أمريكي.

ملاحظة

الخصم يبدأ يوم 6 أغسطس

إذا كنت في بلد لا يدعم مشتريات جوجل بلاي (مثل سوريا)، أو لم يكن لديك ما يكفي من المال، تواصل معي وسأحاول أن أعطيه لك مجاناً، إن شاء الله.

النهاية

أعلم أنني لم أقل الكثير؛ أنا كسول جداً للكتابة. يا رجل، أنا حقاً أكره الكتابة.

إنشاء بيئة التطوير المتكاملة هذه سمح لي بتعلم الكثير، وأعني الكثير. أنا كسول جداً لكتابة ما تعلمته، لكنني أعني ذلك.
هذه المقالة ليست سوى موجز لكيفية عمل Rustroid، واستغرق ترميز التطبيق أكثر من عام. كان يمكن أن يستغرق وقتاً أقل، لكنني كنت أتعلم أشياء جديدة فقط.

الآن أنا في السنة الأخيرة من المدرسة الثانوية (عمري 17 عاماً، بالمناسبة). آمل أن أجد وقتاً لمواصلة العمل على التطبيق هذا العام (أقصد بهذا العام، عام 2026 😉).

بالمناسبة، قمت بتحويل بيئة التطوير المتكاملة إلى Compose Multiplatform حتى أتمكن من تشغيلها على جهاز الكمبيوتر الخاص بي دون الحاجة إلى توصيل هاتف أندرويد (لجعل عملية تطويرها أسهل.). أيضاً، أخطط لإنشاء بيئة تطوير متكاملة لكل لغة موجودة (إن شاء الله) بما أنني قمت بتنفيذ أساس بيئة التطوير، لذا ترقبوا!

يمكنك تنزيل التطبيق من جوجل بلاي، عبر هذا الرابط.

أطيب التحيات،
MohammedKHC

أوه، صحيح، هذا ليس بريداً إلكترونياً. تجاهل الجزء الأخير. ههه.

آخر تحديث:

صنع بواسطة MohammedKHC.