DEX (Dalvik Executable) هو تنسيق بايت كود يتم ترجمة الكود المصدري لتطبيقات Android بلغة Java وKotlin إليه. يتم تنفيذ ملفات DEX بواسطة الآلة الافتراضية Dalvik (حتى Android 4.4) أو Android Runtime (ART، بدءاً من Android 5.0). وفقاً لـ Android Open Source Project، 2026، يوفر تنسيق DEX في المتوسط 30% تمثيلاً أكثر ضغطاً للكود مقارنة ببايت كود JVM القياسي.
أهم النقاط
DEX (Dalvik Executable) هو تنسيق بايت كود مصمم خصيصاً للأجهزة المحمولة التي تعمل بنظام Android. على عكس بايت كود Java القياسي (ملفات .class)، تم تحسين DEX للموارد المحدودة: ذاكرة أقل، حجم أصغر، وتحميل أسرع للفئات.
يتم ترجمة الكود المصدري بلغة Java أو Kotlin بواسطة javac/kotlinc إلى ملفات .class القياسية (بايت كود Java). ثم تقوم أداة d8 (أو dx سابقاً) بتحويل .class إلى ملف DEX واحد أو أكثر. هذا التحويل ليس مجرد إعادة تغليف — بل يقوم d8 بتحسينات: دمج مجموعات الثوابت، إعادة كتابة التعليمات إلى بنية السجلات، وإزالة البيانات المكررة.
يستخدم DEX بنية قائمة على السجلات (بعكس JVM القائمة على المكدس). كل طريقة لها عدد ثابت من السجلات (حتى 65536). تعليمات DEX أقصر — في المتوسط 2 بايت مقابل 1–4 بايت في JVM. هذا ينتج كوداً أكثر ضغطاً: يتقلص التطبيق النموذجي من 10–15 ميجابايت من .class إلى 4–6 ميجابايت من .dex.
ملف DEX له بنية ثنائية محددة بدقة. يبدأ كل ملف برأس ويحتوي على عدة أقسام تشير إلى بعضها البعض من خلال الإزاحات.
| القسم | الغرض |
|---|---|
| header | الرأس: magic، المجموع الاختباري، التوقيع، أحجام وإزاحات الأقسام |
| string_ids | جدول السلاسل: أسماء الفئات، الطرق، الحقول |
| type_ids | الأنواع: مراجع لمعرفات سلسلة الأنواع |
| proto_ids | نماذج الطرق: نوع الإرجاع والمعاملات |
| field_ids | حقول الفئات: الفئة، النوع، الاسم |
| method_ids | الطرق: الفئة، النموذج، الاسم |
| class_defs | تعريفات الفئات: العلامات، الفئة الأم، الواجهات، إزاحات البيانات |
| data | البيانات الفعلية: كود الطرق، التعليقات التوضيحية، معلومات التصحيح |
الرقم السحري لـ DEX هو `dex\n035\0` (الإصدار 035). إصدارات أخرى: 036، 037، 038 (لـ Android 8.0+). الرأس بحجم 0x70 بايت ويحتوي على المجموع الاختباري SHA-1 وإزاحات جميع الأقسام. التحقق من صحة الرأس هو الخطوة الأولى عند تحميل DEX بواسطة الآلة الافتراضية.
string_ids، type_ids، proto_ids، field_ids، method_ids — هي جداول مفهرسة. بدلاً من تخزين الأسماء الكاملة في كود الطريقة، يتم استخدام فهرس 4 بايت. هذا تحسين رئيسي: إذا تم ذكر فئة 100 مرة، يتم تخزين اسمها مرة واحدة في string_ids. dex2oat يحسن هذه الجداول بشكل إضافي أثناء ترجمة ART.
عملية تحويل الكود المصدري إلى DEX تتكون من عدة مراحل. سلسلة الأدوات الحديثة تستخدم المترجم D8، الذي حل محل DX في 2018 مع Android Gradle Plugin 3.2.
javac (لـ Java) أو kotlinc (لـ Kotlin) يترجمان الكود المصدري إلى ملفات .class. كل فئة هي ملف .class منفصل في بايت كود Java. في هذه المرحلة، يتم التحقق من الأنواع، إنشاء طرق bridge، وتضمين الثوابت.
D8 يأخذ جميع ملفات .class ويحولها إلى بايت كود DEX. يقوم D8 بعدة تحسينات: يزيل وسائط الطرق غير المستخدمة، يدمج مجموعات الثوابت من ملفات .class المختلفة في مجموعة واحدة عالمية لـ DEX، ويحول تعليمات مكدس JVM إلى تعليمات سجلات Dalvik.
// كود مصدر Kotlin
data class User(
val name: String,
val email: String
)
fun greet(user: User): String {
return "Hello, ${user.name}!"
}
بعد ترجمة D8، يتحول هذا الكود إلى تعليمات DEX مضغوطة: const-string لتحميل السلاسل، iget-object للوصول إلى حقل الكائن، invoke-virtual لاستدعاء StringBuilder.append.
D8 أسرع من DX بمقدار 2–3 مرات، وينتج DEX أكثر ضغطاً (أصغر بنسبة 5–10%)، ويحسن بشكل أفضل التركيبات الخاصة بـ Kotlin (الدوال المضمنة، lambdas). تم إعلان DX قديماً في 2018 وتمت إزالته من Android Gradle Plugin 8.0.
تنفيذ كود DEX في Android مر بمرحلتين: الآلة الافتراضية Dalvik الأصلية (Android 2.2–4.4) وAndroid Runtime ART (Android 5.0+). الفرق في نهج الترجمة جوهري.
Dalvik استخدمت الترجمة في الوقت المناسب (JIT): يتم تفسير بايت كود DEX، ويتم ترجمة الطرق التي يتم استدعاؤها بشكل متكرر إلى كود أصلي أثناء التشغيل. الإيجابيات — تثبيت سريع. السلبيات — بدء أبطأ واستهلاك مستمر لوحدة المعالجة المركزية لـ JIT.
ART (Android Runtime) يقوم بترجمة DEX إلى كود أصلي أثناء تثبيت التطبيق عبر dex2oat. هذا نهج Ahead-Of-Time (AOT): التثبيت أطول، لكن البدء أسرع واستهلاك الطاقة أقل. منذ Android 7.0، يستخدم ART نهجاً هجيناً — AOT + JIT + Profile Guided Optimization.
أداة dex2oat تعمل عند تثبيت أو تحديث التطبيق. تقوم بترجمة DEX إلى ملف ELF مع كود أصلي لبنية الجهاز. النتيجة — ملفات .oat و .art في دليل /data/dalvik-cache/. Google تحسن dex2oat باستمرار: على Android 14 تمت إضافة تحسينات للأجهزة القابلة للطي.
حد 65536 طريقة لكل ملف DEX هو إرث من بنية Dalvik. حقل method_ids في رأس DEX يشغل 4 بايت، مما يعطي حداً أقصى 2^16 = 65536 مرجعاً فريداً. التطبيقات الحديثة مع Google Play Services وFirebase وSDKs أخرى تتجاوز هذا الحد بسهولة.
Multidex هي آلية لتقسيم الكود عبر عدة ملفات DEX. يحتوي classes.dex الرئيسي على نقاط الدخول (فئة Application، النشاط الرئيسي)، والباقي هي classes2.dex وclasses3.dex وهكذا. عند بدء التشغيل، يتم تحميل الفئات من ملفات DEX الإضافية عبر DexClassLoader.
// build.gradle.kts — تفعيل multidex
android {
defaultConfig {
multiDexEnabled = true
}
}
// فئة Application مع دعم multidex
class MyApp : Application() {
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
MultiDex.install(this)
}
}
تحميل ملفات DEX الإضافية أثناء بدء تشغيل التطبيق يمكن أن يسبب ANR (Application Not Responding) على الأجهزة التي تعمل بنظام Android أقل من 5.0. التوصية — استخدام multidex فقط عند الضرورة وتقليل التبعيات لتجنب تجاوز الحد.
تحسين DEX هو خطوة قياسية في بناء تطبيق Android للإصدار. أدوات R8 وProGuard تقلل حجم DEX، وتعتم الكود، وتزيل الفئات غير المستخدمة.
R8 هو خليفة ProGuard، المدمج في Android Gradle Plugin منذ 2019. يقوم R8 بالتصغير والتعتيم والتحسين في تمريرة واحدة، بينما كان ProGuard يتطلب مرحلتين: ProGuard → D8. ProGuard لا يزال مدعوماً، لكن Google توصي باستخدام R8 للمشاريع الجديدة.
يزيل R8 الفئات والطرق والحقول غير المستخدمة، ويعيد تسميتها بأسماء قصيرة (a، b، c)، ويضمّن الدوال المضمنة ويزيل الكود الميت. النتيجة — يتقلص DEX بنسبة 20–40% دون فقدان الوظائف.
يتم تحديد تكوين R8 في ملف proguard-rules.pro. يمكن للمطور تحديد الفئات التي لا يمكن إعادة تسميتها (على سبيل المثال، للتفكير التأملي أو تسلسل Gson). Firebase وSDKs أخرى توفر قواعدها الخاصة في تبعياتها.
DEX يمكن فك ترجمته مرة أخرى إلى كود Java. هذه مسألة أمان رئيسية لتطبيقات Android: بدون التعتيم، يتم استعادة الكود إلى مستوى قريب من الأصل.
JADX هو أكثر أدوات فك ترجمة DEX إلى Java شيوعاً. يستعيد أسماء الفئات والطرق والحقول ومعظم المنطق. apktool يفك ترجمة DEX إلى كود smali (مجمّع Dalvik) — تمثيل منخفض المستوى قريب من التعليمات الأصلية. Bytecode Viewer يجمع عدة أدوات فك ترجمة في واجهة واحدة.
التعتيم باستخدام R8/ProGuard هو خط الدفاع الأول: تصبح أسماء الفئات والطرق غير قابلة للقراءة. DexGuard أداة تجارية بطرق إضافية: تشفير السلاسل، التحقق من السلامة، مضاد للتلاعب. تعتيم تدفق التحكم (O-LLVM) يغير بنية الكود مع الحفاظ على وظائفه، مما يجعل التحليل أكثر صعوبة.
الأسئلة الشائعة
DEX يستخدم بنية قائمة على السجلات بدلاً من JVM القائمة على المكدس، وله تنسيق أكثر ضغطاً (أصغر بنسبة 30%)، ويدمج جميع ملفات .class في ملف واحد بمجموعة ثوابت موحدة، ويستخدم فهارس 16 بت بدلاً من 8 بت.
Smali هو مجمّع لبايت كود DEX. كل تعليمة DEX لها تمثيل نصي بتنسيق smali. أداة baksmali تحول DEX إلى smali (فك التجميع)، وsmali يجمع smali مرة أخرى إلى DEX.
مهمة Gradle countMethods أو إضافة dex-method-counts تظهر عدد الطرق في كل ملف DEX. أمر adb shell مع dumpsys يعرض أيضاً إحصائيات DEX المحملة للتطبيقات المثبتة.
نعم، على الأجهزة التي تعمل بنظام Android قبل 8.0، تعدد ملفات DEX يبطئ بدء تشغيل التطبيق لأن كل ملف إضافي يتم تحميله بشكل منفصل. على ART مع Android 8.0+، الفرق ضئيل بفضل ترجمة dex2oat إلى ملف .oat واحد.
نعم، هناك مشاريع مثل dexplorer وتطبيقات JVM المتوافقة مع Android يمكنها تنفيذ بايت كود DEX خارج Android. ومع ذلك، معظم ملفات DEX تستخدم Android API، مما يجعلها غير مناسبة للتشغيل على JVM قياسي.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.