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

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

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

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

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

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

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

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

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

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

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

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

إعداد DSL

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

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

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

Kotlin

android {
    namespace = "com.example.app"
    compileSdk = 34
    // ...

    defaultConfig {
        applicationId = "com.example.app"
        minSdk = 34
        // ...
    }
}

رائع

android {
    namespace 'com.example.myapplication'
    compileSdk 34
    // ...

    defaultConfig {
        applicationId "com.example.myapplication"
        minSdk 24
        // ...
    }
}

في الخلفية، يشبه رمز DSL ما يلي:

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

interface ApplicationExtension {
    var compileSdk: Int
    var namespace: String?

    val defaultConfig: DefaultConfig

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

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

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

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

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

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

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

سنوضّح بالتفصيل كيفية تحديد التبعيات في إضافة تبعيات الإنشاء .

إنشاء الصيغ

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

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

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

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

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

تُنشئ أداة AGP خيارات لكل مجموعة من نوع الإصدار ونكهة المنتج. إذا لم تحدِّد النُسخ المخصّصة، سيتم تسمية الأسعار المتغيرة باسم أنواع الإصدارات. إذا حددت كليهما، سيكون اسم الصيغة <flavor><Buildtype>. على سبيل المثال، باستخدام نوعَي الإصدارrelease وdebug والنكهتَينdemo وfull، سينشئ AGP الصيغ التالية:

  • demoRelease
  • demoDebug
  • fullRelease
  • fullDebug

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

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