نظرة عامة على إنشاء Gradle

يتم عادةً إنشاء تطبيقات Android باستخدام نظام التصميم Gradle. قبل أن نتعمق في تفاصيل كيفية تكوين البنية، سنستكشف المفاهيم الكامنة وراء البنية حتى تتمكن من رؤية النظام ككل.

ما هو الإصدار؟

يحوّل نظام الإصدار الرمز المصدر إلى تطبيق قابل للتنفيذ. غالبًا ما تتضمن عمليات الإنشاء أدوات متعددة لتحليل تطبيقك أو مكتبتك وتجميعها وربطها وحزمها. يستخدم Gradle نهجًا قائمًا على المهام لتنظيم هذه الأوامر وتشغيلها.

المهام هي أوامر تترجم المدخلات إلى مخرجات. تحدّد المكوّنات الإضافية المهام وإعداداتها. يؤدي تطبيق مكوّن إضافي على عملية الإنشاء إلى تسجيل مهامها وربطها معًا باستخدام مدخلاتها ومخرجاتها. على سبيل المثال، سيؤدي تطبيق المكوّن الإضافي لنظام Gradle المتوافق مع Android (AGP) على ملف الإصدار إلى تسجيل جميع المهام اللازمة لإنشاء حزمة APK أو مكتبة Android. يتيح لك المكوّن الإضافي java-library إنشاء ملف jar من رمز المصدر Java. تتوفّر مكوّنات إضافية مماثلة للغة Kotlin ولغات أخرى، ولكنّ المكوّنات الإضافية الأخرى تهدف إلى توسيع نطاق المكوّنات الإضافية. على سبيل المثال، يهدف المكوّن الإضافي protobuf إلى إضافة دعم protobuf إلى المكوّنات الإضافية الحالية مثل AGP أو java-library.

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

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

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

ماذا يحدث عند تشغيل إصدار Gradle؟

يتم تشغيل إصدارات Gradle على ثلاث مراحل. تنفّذ كل مرحلة من هذه المراحل أجزاء مختلفة من الرمز البرمجي الذي تحدّده في ملفات الإصدار.

  • تحدّد مرحلة الإعداد المشاريع والمشاريع الفرعية التي يتم تضمينها في عملية الإنشاء، وتُعدّ مسارات الفئات التي تحتوي على ملفات الإنشاء والمكوّنات الإضافية المطبَّقة. تركّز هذه المرحلة على ملف الإعدادات الذي تحدّد فيه المشاريع التي تريد إنشاءها والمواقع التي تريد جلب المكوّنات الإضافية والمكتبات منها.
  • تسجّل الإعدادات المهام لكل مشروع، وتنفّذ ملف الإصدار لتطبيق مواصفات الإصدار الخاصة بالمستخدم. من المهم أن تفهم أنّ رمز الإعدادات لن يتمكّن من الوصول إلى البيانات أو الملفات التي يتم إنشاؤها أثناء التنفيذ.
  • التنفيذ: يتم فيه "إنشاء" تطبيقك فعليًا. ناتج عملية الضبط هو رسم بياني موجّه لا دوري (DAG) للمهام، يمثّل جميع خطوات عملية الإنشاء المطلوبة التي طلبها المستخدم (المهام المقدَّمة في سطر الأوامر أو كإعدادات تلقائية في ملفات الإنشاء). يمثّل هذا الرسم البياني العلاقة بين المهام، سواء كانت صريحة في تعريف المهمة أو استنادًا إلى مدخلاتها ومخرجاتها. إذا كانت إحدى المهام تتضمّن مدخلات تمثّل مخرجات مهمة أخرى، يجب تشغيلها بعد المهمة الأخرى. تنفّذ هذه المرحلة المهام القديمة بالترتيب المحدّد في الرسم البياني. وإذا لم تتغيّر مدخلات مهمة معيّنة منذ آخر تنفيذ لها، سيتخطّاها Gradle.

لمزيد من المعلومات، يُرجى الاطّلاع على دورة حياة الإصدار في Gradle.

لغات DSL للإعدادات

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

تحاول لغات DSL تسهيل الأمر على الجميع، خبراء المجال والمبرمجين، للمساهمة في مشروع ما، وتحديد لغة صغيرة تمثل البيانات بطريقة أكثر طبيعية. يمكن لمكوّنات Gradle الإضافية توسيع لغة DSL لضبط البيانات التي تحتاجها لمهامها.

على سبيل المثال، قد يبدو إعداد جزء Android من الإصدار على النحو التالي:

Kotlin

android {
    namespace = "com.example.app"
    compileSdk {
        version = release(36) {
            minorApiLevel = 1
        }
    }
    // ...

    defaultConfig {
        applicationId = "com.example.app"
        minSdk {
            version = release(23)
        }
        targetSdk {
            version = release(36)
        }
        // ...
    }
}

أنيق

android {
    namespace = 'com.example.app'
    compileSdk {
        version = release(36) {
            minorApiLevel = 1
        }
    }
    // ...

    defaultConfig {
        applicationId = 'com.example.app'
        minSdk {
            version = release(23)
        }
        targetSdk {
            version = release(36)
        }
        // ...
    }
}

وراء الكواليس، يشبه رمز DSL ما يلي:

fun Project.android(configure: ApplicationExtension.() -> Unit) {
    ...
}

interface ApplicationExtension {
    var namespace: String?

    fun compileSdk(configure: CompileSdkSpec.() -> Unit) {
        ...
    }

    val defaultConfig: DefaultConfig

    fun defaultConfig(configure: DefaultConfig.() -> Unit) {
        ...
    }
}

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

المهام التابعة الخارجية

قدّم نظام تصميم Maven مواصفات الاعتمادية ونظام التخزين والإدارة. يتم تخزين المكتبات في مستودعات (خوادم أو أدلة)، مع بيانات وصفية تشمل إصدارها والتبعيات على المكتبات الأخرى. يمكنك تحديد المستودعات التي تريد البحث فيها، وإصدارات التبعيات التي تريد استخدامها، ويقوم نظام الإنشاء بتنزيلها أثناء عملية الإنشاء.

يتم تحديد عناصر Maven حسب اسم المجموعة (الشركة أو المطوّر أو غير ذلك) واسم العنصر (اسم المكتبة) وإصدار ذلك العنصر. ويتم تمثيل ذلك عادةً بالرمز group:artifact:version.

يؤدي هذا النهج إلى تحسين إدارة الإصدارات بشكل كبير. غالبًا ما يُطلق على هذه المستودعات اسم "مستودعات Maven"، ولكن الأمر كله يتعلق بطريقة حزم العناصر ونشرها. وقد تمت إعادة استخدام هذه المستودعات والبيانات الوصفية في عدة أنظمة تصميم، بما في ذلك Gradle (ويمكن لـ Gradle النشر في هذه المستودعات). تسمح المستودعات العامة بالمشاركة ليستخدمها الجميع، وتحتفظ مستودعات الشركة بالتبعيات الداخلية داخل الشركة.

يمكنك أيضًا تقسيم مشروعك إلى مشاريع فرعية (تُعرف أيضًا باسم "الوحدات" في "استوديو Android")، والتي يمكن استخدامها أيضًا كتبعيات. ينتج عن كل مشروع فرعي مخرجات (مثل ملفات jar) يمكن استخدامها من خلال المشاريع الفرعية أو مشروعك ذي المستوى الأعلى. يمكن أن يؤدي ذلك إلى تحسين وقت الإنشاء من خلال عزل الأجزاء التي تحتاج إلى إعادة الإنشاء، بالإضافة إلى فصل المسؤوليات بشكل أفضل في التطبيق.

سنشرح بالتفصيل كيفية تحديد الاعتماديات في مقالة إضافة اعتماديات الإصدار.

تنويعات التصميم

عند إنشاء تطبيق Android، ستحتاج عادةً إلى إنشاء صِيَغ متعددة. تحتوي الصيغ على رموز برمجية مختلفة أو يتم إنشاؤها باستخدام خيارات مختلفة، وتتألف من أنواع الإصدارات وصيغ المنتجات.

تختلف أنواع الإصدارات حسب خيارات الإصدار المحدّدة. يُعدّ المكوّن الإضافي AGP تلقائيًا نوعَي الإصدار "release" (إصدار) و "debug" (تصحيح الأخطاء)، ولكن يمكنك تعديلهما وإضافة المزيد (ربما لأغراض الاختبار الداخلي أو التجريبي).

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

تعمل بنية الإصدار على تحسين التطبيق وتوقيعه باستخدام مفتاح الإصدار وحماية ملفات التطبيق المثبَّتة.

باستخدام صيغ المنتج، يمكنك تغيير المصدر المضمَّن وصيغ التبعية للتطبيق. على سبيل المثال، قد ترغب في إنشاء إصدارات "تجريبية" و "كاملة" لتطبيقك، أو ربما إصدارات "مجانية" و "مدفوعة". يمكنك كتابة المصدر المشترك في دليل مجموعة رموز المصدر "الرئيسي"، وإلغاء المصدر أو إضافته في مجموعة رموز المصدر التي تحمل اسم الإصدار.

ينشئ "مكوّن Android الإضافي لنظام Gradle" صيغًا لكل مجموعة من أنواع الإصدارات وصيغ المنتجات. إذا لم تحدّد الصيغ، تتم تسمية التنويعات وفقًا لأنواع الإصدارات. إذا حدّدت كليهما، تتم تسمية الصيغة <flavor><Buildtype>. على سبيل المثال، مع أنواع الإصدارات release وdebug، والنكهات demo وfull، سينشئ AGP الصيغ التالية:

  • demoRelease
  • demoDebug
  • fullRelease
  • fullDebug

الخطوات التالية

بعد الاطّلاع على مفاهيم التصميم، يمكنك إلقاء نظرة على بنية إصدار Android في مشروعك.