كتابة مكوّنات Gradle الإضافية

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

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

مراحل نشاط واجهة برمجة التطبيقات في "مكوّن Android الإضافي في Gradle"

تتّبع "مكوّن Android الإضافي في Gradle" دورة حياة ميزة Gradle لتحديد حالة واجهات برمجة التطبيقات:

  • داخلي: غير مخصّص للاستخدام العام
  • في مرحلة التجربة: متاحة للاستخدام العام ولكنها ليست نهائية، ما يعني أنّها قد لا تكون متوافقة مع الإصدارات السابقة في الإصدار النهائي
  • الإصدار المتاح للجميع: متاح للاستخدام من قِبل الجميع وثابت
  • متوقّفة نهائيًا: لم يعُد يتم توفيرها، وتم استبدالها بواجهات برمجة تطبيقات جديدة

سياسة الإيقاف النهائي

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

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

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

أساسيات إنشاء Gradle

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

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

مسرد مصطلحات أنواع Gradle الكسولة

توفّر Gradle عددًا من الأنواع التي تعمل "ببطء" أو تساعد في تأجيل العمليات الحسابية المعقّدة أو إنشاء Task إلى مراحل لاحقة من عملية الإنشاء. وتشكّل هذه الأنواع أساس العديد من واجهات برمجة التطبيقات في Gradle وAGP. تتضمّن القائمة التالية أنواع Gradle الرئيسية المعنية بالتنفيذ المؤجّل، وطُرقها الرئيسية.

Provider<T>
توفّر قيمة من النوع T (حيث يشير "T" إلى أي نوع)، ويمكن قراءتها أثناء مرحلة التنفيذ باستخدام get() أو تحويلها إلى Provider<S> جديد (حيث يشير "S" إلى نوع آخر) باستخدام الطرق map() وflatMap() وzip(). يُرجى العِلم أنّه يجب عدم استدعاء get() مطلقًا خلال مرحلة الإعداد.
  • map(): تقبل lambda وتنتج Provider من النوع S،Provider<S>. يأخذ وسيط lambda في الدالة map() القيمة T وينتج القيمة S. لا يتم تنفيذ تعبير lambda على الفور، بل يتم تأجيل تنفيذه إلى حين استدعاء get() على Provider<S> الناتج، ما يجعل السلسلة بأكملها غير نشطة.
  • flatMap(): تقبل أيضًا دالة lambda وتنتج Provider<S>، ولكن الدالة lambda تأخذ القيمة T وتنتج Provider<S> (بدلاً من إنتاج القيمة S مباشرةً). استخدِم flatMap() عندما يتعذّر تحديد S في وقت الإعداد ولا يمكنك الحصول إلا على Provider<S>. من الناحية العملية، إذا استخدمت map() وحصلت على نوع نتيجة Provider<Provider<S>>، يعني ذلك على الأرجح أنّه كان عليك استخدام flatMap() بدلاً من ذلك.
  • zip(): تتيح لك هذه السمة دمج مثيلَين من Provider لإنشاء Provider جديد، بقيمة يتم احتسابها باستخدام دالة تجمع القيم من مثيلَي الإدخال Providers.
Property<T>
تنفّذ Provider<T>، لذا توفّر أيضًا قيمة من النوع T. على عكس Provider<T> التي تكون للقراءة فقط، يمكنك أيضًا ضبط قيمة Property<T>. يمكنك إجراء ذلك بإحدى الطريقتَين التاليتَين:
  • اضبط قيمة من النوع T مباشرةً عند توفّرها، بدون الحاجة إلى عمليات حسابية مؤجّلة.
  • اضبط Provider<T> أخرى كمصدر لقيمة Property<T>. في هذه الحالة، لا يتم إنشاء القيمة T إلا عند استدعاء Property.get().
TaskProvider
تنفيذ Provider<Task> لإنشاء TaskProvider، استخدِم tasks.register() وليس tasks.create()، وذلك لضمان عدم إنشاء مثيل للمهام إلا عند الحاجة إليها. يمكنك استخدام flatMap() للوصول إلى نواتج Task قبل إنشاء Task، وهو ما قد يكون مفيدًا إذا كنت تريد استخدام النواتج كمدخلات إلى مثيلات Task أخرى.

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

تحتوي الجهات المقدّمة للخدمة أيضًا على معلومات حول تبعية المهام. عند إنشاء Provider من خلال تحويل ناتج Task، يصبح Task تابعًا ضمنيًا لـ Provider ويتم إنشاؤه وتشغيله كلما تم تحديد قيمة Provider، مثلاً عندما يتطلبه Task آخر.

في ما يلي مثال على تسجيل مهمتَين، GitVersionTask وManifestProducerTask، مع تأجيل إنشاء مثيلات Task إلى حين الحاجة إليها فعليًا. يتم ضبط قيمة الإدخال ManifestProducerTask على Provider تم الحصول عليها من ناتج GitVersionTask، وبالتالي تعتمد ManifestProducerTask ضمنيًا على GitVersionTask.

// Register a task lazily to get its TaskProvider.
val gitVersionProvider: TaskProvider =
    project.tasks.register("gitVersionProvider", GitVersionTask::class.java) {
        it.gitVersionOutputFile.set(
            File(project.buildDir, "intermediates/gitVersionProvider/output")
        )
    }

...

/**
 * Register another task in the configuration block (also executed lazily,
 * only if the task is required).
 */
val manifestProducer =
    project.tasks.register(variant.name + "ManifestProducer", ManifestProducerTask::class.java) {
        /**
         * Connect this task's input (gitInfoFile) to the output of
         * gitVersionProvider.
         */
        it.gitInfoFile.set(gitVersionProvider.flatMap(GitVersionTask::gitVersionOutputFile))
    }

ولن يتم تنفيذ هاتين المهمّتَين إلا إذا تم طلبهما بشكل صريح. يمكن أن يحدث ذلك كجزء من استدعاء Gradle، مثلاً، إذا شغّلت ./gradlew debugManifestProducer، أو إذا كان ناتج ManifestProducerTask مرتبطًا بمهمة أخرى وأصبحت قيمته مطلوبة.

مع أنّك ستكتب مهامًا مخصّصة تستهلك مدخلات و/أو تنتج مخرجات، لا يوفّر AGP إمكانية الوصول إلى مهامه الخاصة بشكل مباشر. وهي تفاصيل تنفيذية قابلة للتغيير من إصدار إلى آخر. بدلاً من ذلك، يوفّر AGP واجهة برمجة التطبيقات Variant API وإمكانية الوصول إلى ناتج مهامها، أو نتائج عملية الإنشاء، التي يمكنك قراءتها وتحويلها. لمزيد من المعلومات، يُرجى الاطّلاع على واجهة برمجة التطبيقات الخاصة بإنشاء الصيغ والنتائج والمهام في هذا المستند.

مراحل إنشاء Gradle

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

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

مرحلة الإعداد

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

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

مرحلة التنفيذ

في مرحلة التنفيذ، يتم تنفيذ المهام المطلوبة والمهام التابعة لها. على وجه التحديد، يتم تنفيذ طرق الفئة Task التي تحمل العلامة @TaskAction. أثناء تنفيذ المهمة، يُسمح لك بالقراءة من المدخلات (مثل الملفات) وحلّ المشاكل المتعلّقة بموفّري البيانات غير الفورية من خلال استدعاء Provider<T>.get(). يؤدي حلّ المشاكل المتعلّقة بموفّري البيانات غير النشطين بهذه الطريقة إلى بدء سلسلة من طلبات map() أو flatMap() التي تتّبع معلومات تبعية المهام الواردة في موفّر البيانات. يتم تنفيذ المهام بشكل غير مباشر لتوفير القيم المطلوبة.

Variant API والعناصر والمهام

واجهة برمجة التطبيقات Variant هي آلية توسيع في المكوّن الإضافي لنظام Android المتوافق مع Gradle تتيح لك التعامل مع الخيارات المختلفة التي يتم ضبطها عادةً باستخدام لغة DSL في ملفات إعدادات الإصدار التي تؤثر في إصدار Android. تتيح لك Variant API أيضًا الوصول إلى العناصر الوسيطة والنهائية التي يتم إنشاؤها بواسطة الإصدار، مثل ملفات الفئات أو البيان المدمج أو ملفات APK/AAB.

مسار إنشاء Android ونقاط الإضافة

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

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

  1. تحليل DSL: يحدث ذلك عند تقييم نصوص البرامج الإنشائية، وعند إنشاء وضبط الخصائص المختلفة لعناصر Android DSL من الحزمة android. يتم أيضًا تسجيل عمليات معاودة الاتصال الخاصة بواجهة برمجة التطبيقات Variant API الموضّحة في الأقسام التالية خلال هذه المرحلة.
  2. finalizeDsl(): دالة رد الاتصال التي تتيح لك تغيير عناصر DSL قبل أن يتم قفلها لإنشاء المكوّن (الصيغة). يتم إنشاء عناصر VariantBuilder استنادًا إلى البيانات الواردة في عناصر DSL.

  3. قفل DSL: تم الآن قفل DSL ولم يعُد من الممكن إجراء تغييرات.

  4. beforeVariants(): يمكن أن يؤثّر هذا الإجراء على العناصر التي يتم إنشاؤها، وعلى بعض خصائصها، من خلال VariantBuilder. ويظلّ بإمكانك إجراء تعديلات على مسار الإنشاء والنتائج التي يتم إنتاجها.

  5. إنشاء صيغة: تم الآن الانتهاء من قائمة المكوّنات والعناصر التي سيتم إنشاؤها، ولا يمكن تغييرها.

  6. onVariants(): في دالة معاودة الاتصال هذه، يمكنك الوصول إلى عناصر Variant التي تم إنشاؤها، ويمكنك ضبط القيم أو موفّري القيم الخاصة بقيم Property التي تحتوي عليها، ليتم احتسابها بشكل غير مباشر.

  7. قفل خيارات المنتجات: تم الآن قفل عناصر خيارات المنتجات ولم يعُد من الممكن إجراء تغييرات عليها.

  8. المهام التي تم إنشاؤها: يتم استخدام عناصر Variant وقيم Property الخاصة بها لإنشاء مثيلات Task اللازمة لتنفيذ عملية الإنشاء.

تقدّم واجهة برمجة التطبيقات AGP AndroidComponentsExtension تتيح لك تسجيل دوال رد الاتصال الخاصة بـ finalizeDsl() وbeforeVariants() وonVariants(). تتوفّر الإضافة في نصوص البرامج الإنشائية من خلال الحظر androidComponents:

// This is used only for configuring the Android build through DSL.
android { ... }

// The androidComponents block is separate from the DSL.
androidComponents {
   finalizeDsl { extension ->
      ...
   }
}

ومع ذلك، ننصحك بإبقاء نصوص البرامج الإنشائية مخصّصة فقط للإعدادات التعريفية باستخدام DSL الخاص بحزمة android، ونقل أي منطق إلزامي مخصّص إلى buildSrc أو إلى مكوّنات إضافية خارجية. يمكنك أيضًا الاطّلاع على buildSrc الأمثلة في مستودع GitHub الخاص بوصفات Gradle لمعرفة كيفية إنشاء مكوّن إضافي في مشروعك. في ما يلي مثال على تسجيل عمليات الرجوع من رمز المكوّن الإضافي:

abstract class ExamplePlugin: Plugin<Project> {

    override fun apply(project: Project) {
        val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
        androidComponents.finalizeDsl { extension ->
            ...
        }
    }
}

في ما يلي نظرة فاحصة على عمليات معاودة الاتصال المتاحة وأنواع حالات الاستخدام التي يمكن أن تتوافق معها الإضافة في كل عملية:

finalizeDsl(callback: (DslExtensionT) -> Unit)

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

abstract class ExamplePlugin: Plugin<Project> {

    override fun apply(project: Project) {
        val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
        androidComponents.finalizeDsl { extension ->
            extension.buildTypes.create("extra").let {
                it.isJniDebuggable = true
            }
        }
    }
}

beforeVariants()

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

androidComponents {
    beforeVariants { variantBuilder ->
        variantBuilder.minSdk = 23
    }
}

يمكن أن تتضمّن دالة رد الاتصال beforeVariants() بشكل اختياري VariantSelector، ويمكنك الحصول عليها من خلال الطريقة selector() في androidComponentsExtension. يمكنك استخدامها لفلترة المكوّنات المشارِكة في استدعاء دالة الرجوع استنادًا إلى اسمها أو نوع الإصدار أو نوع المنتج.

androidComponents {
    beforeVariants(selector().withName("adfree")) { variantBuilder ->
        variantBuilder.minSdk = 23
    }
}

onVariants()

عند استدعاء onVariants()، تكون جميع العناصر التي سيتم إنشاؤها بواسطة AGP قد تم تحديدها بالفعل، وبالتالي لن تتمكّن من إيقافها. ومع ذلك، يمكنك تعديل بعض القيم المستخدَمة في المهام من خلال ضبطها لسمات Property في عناصر Variant. بما أنّ قيم Property لن يتم تحديدها إلا عند تنفيذ مهام "مكوّن Android الإضافي"، يمكنك ربطها بأمان بموفّري البيانات من مهامك المخصّصة التي ستنفّذ أي عمليات حسابية مطلوبة، بما في ذلك القراءة من المدخلات الخارجية، مثل الملفات أو الشبكة.

// onVariants also supports VariantSelectors:
onVariants(selector().withBuildType("release")) { variant ->
    // Gather the output when we are in single mode (no multi-apk).
    val mainOutput = variant.outputs.single { it.outputType == OutputType.SINGLE }

    // Create version code generating task
    val versionCodeTask = project.tasks.register("computeVersionCodeFor${variant.name}", VersionCodeTask::class.java) {
        it.outputFile.set(project.layout.buildDirectory.file("${variant.name}/versionCode.txt"))
    }
    /**
     * Wire version code from the task output.
     * map() will create a lazy provider that:
     * 1. Runs just before the consumer(s), ensuring that the producer
     * (VersionCodeTask) has run and therefore the file is created.
     * 2. Contains task dependency information so that the consumer(s) run after
     * the producer.
     */
    mainOutput.versionCode.set(versionCodeTask.map { it.outputFile.get().asFile.readText().toInt() })
}

المساهمة في إنشاء مصادر

يمكن أن يساهم المكوّن الإضافي في توفير بعض أنواع المصادر التي يتم إنشاؤها، مثل:

للاطّلاع على القائمة الكاملة بالمصادر التي يمكنك إضافتها، راجِع Sources API.

يوضّح مقتطف الرمز البرمجي هذا كيفية إضافة مجلد مصدر مخصّص باسم ${variant.name} إلى مجموعة مصادر Java باستخدام الدالة addStaticSourceDirectory(). بعد ذلك، تعالج مجموعة أدوات Android هذا المجلد.

onVariants { variant ->
    variant.sources.java?.let { java ->
        java.addStaticSourceDirectory("custom/src/kotlin/${variant.name}")
    }
}

راجِع وصفة addJavaSource للحصول على مزيد من التفاصيل.

يوضّح مقتطف الرمز هذا كيفية إضافة دليل يتضمّن موارد Android تم إنشاؤها من مهمة مخصّصة إلى مجموعة المصادر res. وتتشابه العملية مع أنواع المستندات المصدر الأخرى.

onVariants(selector().withBuildType("release")) { variant ->
    // Step 1. Register the task.
    val resCreationTask =
       project.tasks.register<ResCreatorTask>("create${variant.name}Res")

    // Step 2. Register the task output to the variant-generated source directory.
    variant.sources.res?.addGeneratedSourceDirectory(
       resCreationTask,
       ResCreatorTask::outputDirectory)
    }

...

// Step 3. Define the task.
abstract class ResCreatorTask: DefaultTask() {
   @get:OutputFiles
   abstract val outputDirectory: DirectoryProperty

   @TaskAction
   fun taskAction() {
      // Step 4. Generate your resources.
      ...
   }
}

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

الوصول إلى العناصر وتعديلها

بالإضافة إلى السماح لك بتعديل الخصائص البسيطة في عناصر Variant، يحتوي AGP أيضًا على آلية إضافة تتيح لك قراءة أو تحويل العناصر الوسيطة والنهائية التي يتم إنتاجها أثناء عملية الإنشاء. على سبيل المثال، يمكنك قراءة محتوى ملف AndroidManifest.xml النهائي المدمج في Task مخصّص لتحليله، أو يمكنك استبدال محتواه بالكامل بمحتوى ملف بيان تم إنشاؤه بواسطة Task المخصّص.

يمكنك العثور على قائمة بالعناصر التي يتم دعمها حاليًا في مستندات المرجع الخاصة بفئة Artifact. لكل نوع من أنواع العناصر بعض الخصائص التي من المفيد معرفتها:

عدد القيم الفريدة للسمة

تمثّل العلاقة الأساسية Artifact عدد مثيلات FileSystemLocation، أو عدد الملفات أو الدلائل من نوع العنصر. يمكنك الحصول على معلومات حول عدد العناصر الأساسية لعنصر ما من خلال التحقّق من فئته الرئيسية: ستكون العناصر التي تتضمّن FileSystemLocation واحدًا فقط فئة فرعية من Artifact.Single، بينما ستكون العناصر التي تتضمّن عدة مثيلات من FileSystemLocation فئة فرعية من Artifact.Multiple.

نوع واحد FileSystemLocation

يمكنك التحقّق مما إذا كان Artifact يمثّل ملفات أو أدلّة من خلال النظر إلى نوع FileSystemLocation المحدّد المعلمات، والذي يمكن أن يكون إما RegularFile أو Directory.

العمليات المتوافقة

يمكن لكل فئة Artifact تنفيذ أي من الواجهات التالية للإشارة إلى العمليات التي تتوافق معها:

  • Transformable: يسمح باستخدام Artifact كإدخال إلى Task الذي ينفّذ عمليات تحويل عشوائية عليه ويُخرج نسخة جديدة من Artifact.
  • Appendable: تنطبق هذه السمة فقط على العناصر التي تكون فئات فرعية من Artifact.Multiple. وهذا يعني أنّه يمكن إلحاق Artifact، أي أنّ Task مخصّص يمكنه إنشاء مثيلات جديدة من نوع Artifact هذا، والتي ستتم إضافتها إلى القائمة الحالية.
  • Replaceable: تنطبق هذه السمة فقط على العناصر التي تكون فئات فرعية من Artifact.Single. يمكن استبدال Artifact قابل للاستبدال بمثيل جديد تمامًا، يتم إنتاجه كنتيجة Task.

بالإضافة إلى العمليات الثلاث التي تعدّل العناصر، يتيح كل عنصر عملية get() (أو getAll()) التي تعرض Provider مع النسخة النهائية من العنصر (بعد الانتهاء من جميع العمليات عليه).

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

نقطة الدخول إلى عمليات التسجيل هي الفئة Artifacts. يوضّح مقتطف الرمز البرمجي التالي كيف يمكنك الوصول إلى مثيل من Artifacts من إحدى السمات في العنصر Variant في دالة onVariants().

يمكنك بعد ذلك إدخال TaskProvider المخصّص للحصول على عنصر TaskBasedOperation (1)، واستخدامه لربط المدخلات والمخرجات باستخدام إحدى طرق wiredWith* (2).

تعتمد الطريقة المحدّدة التي عليك اختيارها على عدد العناصر الأساسية وFileSystemLocation النوع الذي تم تنفيذه بواسطة Artifact الذي تريد تحويله.

وأخيرًا، يمكنك تمرير النوع Artifact إلى طريقة تمثّل العملية المحدّدة على العنصر *OperationRequest الذي تحصل عليه في المقابل، على سبيل المثال، toAppendTo() أو toTransform() أو toCreate() (3).

androidComponents.onVariants { variant ->
    val manifestUpdater = // Custom task that will be used for the transform.
            project.tasks.register(variant.name + "ManifestUpdater", ManifestTransformerTask::class.java) {
                it.gitInfoFile.set(gitVersionProvider.flatMap(GitVersionTask::gitVersionOutputFile))
            }
    // (1) Register the TaskProvider w.
    val variant.artifacts.use(manifestUpdater)
         // (2) Connect the input and output files.
        .wiredWithFiles(
            ManifestTransformerTask::mergedManifest,
            ManifestTransformerTask::updatedManifest)
        // (3) Indicate the artifact and operation type.
        .toTransform(SingleArtifact.MERGED_MANIFEST)
}

في هذا المثال، MERGED_MANIFEST هو SingleArtifact، وهو RegularFile. لهذا السبب، علينا استخدام طريقة wiredWithFiles التي تقبل مرجع RegularFileProperty واحدًا للإدخال ومرجع RegularFileProperty واحدًا للإخراج. تتوفّر طرق wiredWith* أخرى في الفئة TaskBasedOperation يمكن استخدامها مع مجموعات أخرى من Artifact عدد العناصر وFileSystemLocation أنواعها.

لمزيد من المعلومات حول توسيع نطاق "المكوّن الإضافي لنظام Gradle المتوافق مع Android"، ننصحك بقراءة الأقسام التالية من دليل نظام الإصدار Gradle: