أساسيات Gradle
أساسيات Gradle
يُعدّ Gradle أداة البناء الأكثر هيمنةً في عالم Android ومنافسًا جديًا لـ Maven في بيئة JVM. يستبدل XML بلغة برمجة حقيقية — إما Groovy DSL أو Kotlin DSL — مانحًا إياك القوة التعبيرية الكاملة لبيئة نصية مع الحفاظ على النموذج التصريحي الذي تحتاجه لبناء قابل للتنبؤ. يتناول هذا الدرس بنية ملف build.gradle ونموذج المهام ومعمقة Groovy/Kotlin DSL.
لماذا Gradle؟
XML في Maven طويل ومتصلّب. يحتفظ Gradle بالجوانب الجيدة — إدارة الاعتماديات التصريحية ومنظومة الإضافات الغنية والاصطلاحات على التهيئة — ويتخلص من أسوأها:
- بناء تدريجي. يتتبّع Gradle مدخلات ومخرجات كل مهمة. إن لم يتغيّر شيء فتُوسَم المهمة بـ UP-TO-DATE وتُتجاوز. يُعيد Maven تنفيذ المراحل حتى عند غياب أي تغيير.
- ذاكرة تخزين للبناء. تُخزَّن مخرجات المهام وتُعاد استخدامها عبر الأجهزة مما يُقلّص زمن البناء في CI بشكل كبير للمشاريع الكبيرة.
- نصوص مرنة. ملف البناء برنامج حقيقي يمكنك فيه استخدام حلقات وشروط ودوال مساعدة.
- عفريت يُعطي الأداء الأولوية. يعمل عفريت Gradle في الخلفية فتتجنب عمليات البناء اللاحقة تهيئة JVM بالكامل.
build.gradle.kts). يمنحك إكمالًا تلقائيًا في IDE ودعمًا لإعادة الهيكلة والتحقق من الأنواع وقت الترجمة. Groovy DSL (build.gradle) أقدم وشائع جدًا، لذا ستصادف كليهما — يعرض هذا الدرس كلتا الصياغتين جنبًا إلى جنب حيثما اختلفتا.
بنية build.gradle
يتضمّن ملف بناء مشروع Java بسيط أربعة أقسام: الإضافات والمستودعات والاعتماديات وتهيئة المهام (اختياريًا).
Groovy DSL (build.gradle):
Kotlin DSL (build.gradle.kts) — المشروع ذاته:
يلفّ Kotlin DSL كل شيء في استدعاءات دوال (الأقواس إلزامية) ويستخدم سلاسل بعلامات اقتباس مزدوجة ويُحلّ الأنواع وقت الترجمة — تُكتشف أخطاء ملف البناء قبل تشغيله.
تهيئات الاعتماديات
تأتي إضافة Java في Gradle مع عدة تهيئات. أهمها:
implementation— على مسار ترجمة هذا المشروع؛ غير مُسرَّبة للمستهلكين. افضلها دائمًا.api— (من إضافةjava-library) مُسرَّبة للمستهلكين؛ استخدمها فقط للأنواع التي تكشفها واجهتك العامة.compileOnly— متاحة وقت الترجمة فقط (مثل Lombok ومعالجات التعليقات التوضيحية).runtimeOnly— على مسار التنفيذ فقط (مثل برامج تشغيل JDBC).testImplementation— مثلimplementationلكنها مقتصرة على الاختبارات.testRuntimeOnly— تنفيذ فقط للاختبارات (مثل JUnit launcher).
implementation على compile المهجورة. كانت تهيئة compile القديمة تُسرِّب جميع الاعتماديات العابرة للمستهلكين مما ينفّخ مسارات الترجمة. تحتفظ implementation بالاعتماديات الداخلية داخليةً مما يعني ترجمة أسرع وشجرة اعتماديات أنظف.
نموذج المهام في Gradle
كل ما يفعله Gradle هو مهمة. المهمة وحدة عمل ذات مدخلات ومخرجات مُحدَّدة النوع. حين تشغّل ./gradlew build يبني Gradle رسمًا بيانيًا موجَّهًا لا دوري (DAG) لجميع المهام التي تحتاج التنفيذ وينفّذها بترتيب التبعيات.
أبرز المهام المدمجة في إضافة Java:
compileJava— يُجمّعsrc/main/java.processResources— ينسخsrc/main/resourcesإلى مجلد الإخراج.classes— مهمة دورة الحياة: تعتمد علىcompileJava+processResources.test— يُجمّع الاختبارات ويشغّلها.jar— يحزم الفئات المُجمَّعة في ملف JAR.build— يُجمّع المشروع ويختبره (البناء الكامل القياسي).clean— يحذف مجلدbuild/.
تعريف مهام مخصصة
يمكنك تعريف مهامك مباشرةً في ملف البناء. يجعل Groovy DSL هذا موجزًا بشكل خاص:
المكافئ بـ Kotlin DSL:
المهام ذات الأنواع — الأسلوب المفضَّل
للمهام الجدية يوفّر Gradle فئات أساسية ذات أنواع. استخدام مهمة ذات نوع يتيح لـ Gradle تتبّع المدخلات والمخرجات للتنفيذ التدريجي:
لأن from وinto مُعلَن عنهما كمدخلات/مخرجات للمهمة سيتجاوز Gradle هذه المهمة تلقائيًا عند عدم تغيّر مصدر Javadoc ولا الوجهة.
doFirst/doLast لتهيئة مدخلات أو مخرجات المهمة. كود التهيئة الذي يعمل وقت التهيئة ينتمي لكتلة تهيئة المهمة؛ كود الإجراء (العمل الفعلي) ينتمي لـ doLast. خلطهما يُفسد البناء التدريجي وذاكرة التخزين المؤقتة.
مغلّف Gradle (Gradle Wrapper)
يجب أن يُودِع كل مشروع مغلّف Gradle — نص برمجي صغير وملف JAR يُنزّل إصدار Gradle الصحيح تلقائيًا. هذا يضمن أن كل مطوّر وكل خادم CI يستخدم الإصدار ذاته من Gradle:
تُخزَّن تهيئة المغلّف في gradle/wrapper/gradle-wrapper.properties. أودِع هذا الملف ونصوص المغلّف؛ لا تودِع مجلد .gradle/ للتخزين المؤقت.
أوامر سطر الأوامر الأساسية
./gradlew tasks— يُدرج جميع المهام المتاحة مجمَّعةً حسب الفئة../gradlew build— يُجمّع ويختبر ويحزم../gradlew test— يشغّل الاختبارات فقط../gradlew dependencies— يطبع شجرة الاعتماديات الكاملة../gradlew :subproject:build— يبني مشروعًا فرعيًا محددًا../gradlew build --scan— يولّد فحصًا للبناء على scans.gradle.com (لا غنى عنه لتشخيص البناء البطيء).
الخلاصة
يستبدل Gradle XML بـ DSL حقيقي (Groovy أو Kotlin) ويُنمذج كل إجراء كمهمة ذات مدخلات ومخرجات صريحة ويستخدم التنفيذ التدريجي لإعادة بناء ما تغيّر فقط. يضمن المغلّف قابلية إعادة إنتاج البناء في كل بيئة. في الدرس القادم سنتعمّق في إدارة الاعتماديات وكتالوجات الإصدارات وكتابة مهام Gradle مخصصة تتكامل مع بناء متعدد المشاريع.