يُعد المكوّن الإضافي لنظام Gradle المتوافق مع Android (AGP) هو نظام التصميم الرسمي لتطبيقات Android. وهي تشمل دعمًا لجمع العديد من أنواع المصادر المختلفة وربطها معًا بتطبيق يمكنك تشغيله على جهاز Android فعلي أو محاكي.
يحتوي AGP على نقاط امتداد للمكونات الإضافية للتحكم في إدخالات الإنشاء وتوسيع نطاق وظائفه من خلال خطوات جديدة يمكن دمجها مع مهام التصميم القياسية. لم تكن الإصدارات السابقة من AGP تحتوي على واجهات برمجة تطبيقات رسمية منفصلة بوضوح عن عمليات التنفيذ الداخلية. بدءًا من الإصدار 7.0، يحتوي AGP على مجموعة من واجهات برمجة التطبيقات الرسمية والثابتة التي يمكنك الاعتماد عليها.
مراحل نشاط واجهة برمجة تطبيقات AGP
يتّبع AGP دورة حياة ميزة Gradle لتحديد حالة واجهات برمجة التطبيقات الخاصة به:
- داخلي: ليس مخصصًا للاستخدام العام
- الحضانة: متاحة للاستخدام العام ولكنها ليست نهائية، ما يعني أنها قد لا تكون متوافقة مع الأنظمة القديمة في الإصدار النهائي.
- متاح للجميع: متاح للاستخدام المتاح للجميع وهو إصدار ثابت
- متوقّف نهائيًا: لم يعُد متوافقًا، وتم استبداله بواجهات برمجة تطبيقات جديدة.
سياسة الإيقاف النهائي
يتطوّر AGP بالتزامن مع إيقاف واجهات برمجة التطبيقات القديمة واستبدالها بواجهات برمجة تطبيقات جديدة وثابتة ولغة جديدة خاصة بالنطاق (DSL). ويشمل هذا التطوّر إصدارات متعدّدة من AGP، ويمكنك الاطّلاع على المزيد من المعلومات حوله على المخطط الزمني لنقل بيانات AGP API/DSL.
في حال إيقاف واجهات AGP API نهائيًا، بسبب عملية النقل هذه أو غير ذلك، ستظل متاحة في الإصدار الرئيسي الحالي، ولكن ستظهر تحذيرات. ستتم إزالة واجهات برمجة التطبيقات التي تم إيقافها بالكامل من AGP في الإصدار الرئيسي اللاحق. على سبيل المثال، إذا تم إيقاف واجهة برمجة التطبيقات نهائيًا بالإصدار 7.0 من AGP، ستكون متاحة في ذلك الإصدار وستنشئ تحذيرات. لن تكون واجهة برمجة التطبيقات هذه متاحة في الإصدار 8.0 من AGP.
للاطّلاع على أمثلة لواجهات برمجة التطبيقات الجديدة المستخدمة في عمليات تخصيص الإصدارات الشائعة، يمكنك إلقاء نظرة على وصفات مكوّنات إضافية لنظام Gradle المتوافق مع Android. وتُقدِّم أمثلة على تخصيصات الإصدار الشائعة. يمكنك أيضًا العثور على مزيد من التفاصيل حول واجهات برمجة التطبيقات الجديدة في المستندات المرجعية.
أساسيات إنشاء 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
مباشرةً). استخدِم دالة Fla Map() عندما يتعذّر تحديد 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 وإمكانية الوصول إلى نتائج مهامها، أو إنشاء أدوات يمكن قراءتها وتحويلها. يمكنك الاطّلاع على Variant API و"العناصر" و"مهام Google" في هذا المستند للحصول على مزيد من المعلومات.
مراحل إنشاء Gradle
يُعد بناء المشروع بطبيعتها عملية معقدة وتتطلب موارد، وهناك العديد من الميزات مثل تجنب تهيئة المهام، وعمليات الفحص الحديثة، وميزة التخزين المؤقت للتكوين التي تساعد في تقليل الوقت المستغرق في إجراء عمليات حسابية قابلة للتكرار أو غير الضرورية.
لتطبيق بعض من هذه التحسينات، يجب أن تمتثل نصوص Gradle البرمجية والمكوّنات الإضافية لقواعد صارمة خلال كل مرحلة من مراحل تصميم Gradle المميزة، وهي: التهيئة والإعداد والتنفيذ. في هذا الدليل، سنركز على مرحلتي التهيئة والتنفيذ. يمكنك العثور على مزيد من المعلومات حول جميع المراحل في دليل مراحل نشاط إنشاء Gradle.
مرحلة الضبط
أثناء مرحلة الضبط، يتم تقييم النصوص البرمجية للإصدار لجميع المشاريع التي تشكّل جزءًا من الإصدار، ويتم تطبيق المكوّنات الإضافية، وحلّ تبعيات الإصدار. يجب استخدام هذه المرحلة في تكوين الإصدار باستخدام كائنات DSL ولتسجيل المهام ومدخلاتها ببطء.
وبما أنّ مرحلة الضبط يتم تشغيلها دائمًا، بغض النظر عن المهمة المطلوبة لتشغيلها، من المهم بشكل خاص الحفاظ على سرعتها وتقييد أي عمليات حسابية من الاعتماد على مدخلات أخرى غير النصوص البرمجية للإصدار نفسه.
ويعني هذا أنّه يجب عدم تنفيذ برامج خارجية أو القراءة من الشبكة، أو
إجراء عمليات حسابية طويلة يمكن تأجيلها إلى مرحلة التنفيذ على أنّها مثيلات
Task
مناسبة.
مرحلة التنفيذ
في مرحلة التنفيذ، يتم تنفيذ المهام المطلوبة والمهام التابعة لها. على وجه التحديد، يتم تنفيذ طرق الفئات Task
التي تم وضع علامة @TaskAction
عليها. أثناء تنفيذ المهمة، يُسمَح لك بالقراءة من الإدخالات (مثل الملفات) وحلّ مشكلة مقدّمي الخدمة الكسولين من خلال طلب البيانات من Provider<T>.get()
. عند حل مشكلة مقدّمي الخدمات الكسولين، يؤدي ذلك إلى بدء سلسلة من طلبات map()
أو flatMap()
التي تتّبع معلومات تبعية المهام المضمَّنة في مقدّم الخدمة. يتم تشغيل المهام ببطء
لتحقيق القيم المطلوبة.
"واجهة برمجة التطبيقات" و"الأدوات" و"المهام" للنسخة التجريبية
Variant API هي آلية إضافة في المكوّن الإضافي لنظام Gradle المتوافق مع Android تتيح لك معالجة الخيارات المختلفة التي يتم ضبطها عادةً باستخدام DSL في ملفات إعداد الإصدار والتي تؤثر في إصدار Android. تمنحك واجهة برمجة التطبيقات Variant API أيضًا إمكانية الوصول إلى العناصر الوسيطة والنهائية التي تمّ إنشاؤها من خلال الإصدار، مثل ملفات الفئة أو البيان المدمج أو ملفات APK أو AAB.
نقاط تدفق إصدار Android والإضافات
عند التفاعل مع AGP، استخدِم نقاط إضافة تم إنشاؤها خصيصًا بدلاً من تسجيل استدعاءات دورة حياة Gradle المعتادة (مثل afterEvaluate()
) أو إعداد تبعيات Task
واضحة. تُعد المهام التي يتم إنشاؤها بواسطة AGP تفاصيل التنفيذ ولا يتم الكشف عنها كواجهة برمجة تطبيقات عامة. عليك تجنُّب
محاولة الحصول على مثيلات لكائنات Task
أو تخمين أسماء Task
وإضافة استدعاءات أو اعتماديات إلى كائنات Task
هذه مباشرةً
يُكمل AGP الخطوات التالية لإنشاء مثيلات Task
الخاصة به وتنفيذها، ما يؤدي بدوره إلى إنتاج عناصر الإصدار. الخطوات الأساسية لإنشاء عنصر
Variant
تتبعها عمليات استدعاء تتيح لك إجراء تغييرات على عناصر
معينة تم إنشاؤها كجزء من تصميم. تجدر الإشارة إلى أنّ جميع عمليات معاودة الاتصال تحدث خلال مرحلة الإعداد (الموضّحة في هذه الصفحة) ويجب أن تتم بسرعة مع تأجيل أي عمل معقد إلى مثيلات Task
المناسبة أثناء مرحلة التنفيذ بدلاً من ذلك.
- تحليل DSL: يحدث ذلك عند تقييم النصوص البرمجية للإصدار، وعند إنشاء السمات المختلفة لكائنات Android DSL من مجموعة
android
وضبطها. خلال هذه المرحلة، يتم أيضًا تسجيل طلبات معاودة الاتصال من واجهة برمجة التطبيقات Variant API الموضّحة في الأقسام التالية. finalizeDsl()
: عبارة استدعاء تتيح لك تغيير عناصر DSL قبل قفلها لإنشاء المكوّنات (الصيغة). يتم إنشاء كائناتVariantBuilder
استنادًا إلى البيانات الموجودة في كائنات DSL.قفل DSL: تم قفل DSL الآن ولم يعد من الممكن إجراء التغييرات.
beforeVariants()
: يمكن أن تؤثر معاودة الاتصال هذه في المكوّنات التي يتم إنشاؤها وبعض سماتها من خلالVariantBuilder
. ولا يزال يسمح بإجراء تعديلات على تدفق التصميم والأدوات التي يتم إنتاجها.إنشاء الصيغة: أصبحت قائمة المكونات والعناصر التي سيتم إنشاؤها نهائية ولا يمكن تغييرها.
onVariants()
: في معاودة الاتصال هذه، يمكنك الوصول إلى عناصرVariant
التي تم إنشاؤها، ويمكنك ضبط قيم أو موفِّري قيم لقيمProperty
التي تحتوي عليها ليتم احتسابها بطريقة كسول.قفل خيارات المنتج: أصبحت عناصر الصيغ مُقفَلة الآن ولم يعُد من الممكن إجراء التغييرات.
المهام التي تم إنشاؤها: يتم استخدام كائنات
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
النماذج في مستودع Gradle المخصص لوصفات الطعام على GitHub للتعرّف على كيفية إنشاء مكوّن إضافي في مشروعك. في ما يلي مثال على تسجيل عمليات معاودة الاتصال من رمز المكوّن الإضافي:
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
لن يتم حلها
إلا عند تنفيذ مهام AGP، يمكنك إرسالها بأمان إلى
المزوّدين من مهامك المخصَّصة التي ستُجري أي عمليات حوسبة مطلوبة، بما في ذلك القراءة من مدخلات خارجية مثل الملفات أو الشبكة.
// 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() })
}
المساهمة بمصادر تم إنشاؤها في الإصدار
يمكن أن يساهم المكوّن الإضافي في بضعة أنواع من المصادر التي يتم إنشاؤها، مثل:
- رمز التطبيق في دليل
java
- موارد Android في
دليل
res
- موارد Java
في دليل
resources
- مواد عرض Android في
دليل
assets
للحصول على القائمة الكاملة بالمصادر التي يمكنك إضافتها، انتقِل إلى 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()
، وسيضمن AGP أن يتم ربطها بشكل تسلسلي بشكل صحيح حتى يتم تشغيل جميع المهام في الوقت المناسب ويتم إنتاج العناصر وتحديثها بشكل صحيح. هذا يعني أنّه عندما تغيّر إحدى العمليات أي مخرجات من خلال إرفاقها أو استبدالها أو تحويلها، سترى العملية التالية النسخة المعدَّلة من هذه العناصر كمدخلات وهكذا.
نقطة الدخول إلى عمليات التسجيل هي فئة 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
.
لمعرفة المزيد حول تمديد AGP، ننصحك بقراءة الأقسام التالية من دليل نظام تصميم Gradle:
- تطوير المكوّنات الإضافية المخصّصة لنظام Gradle المتوافق
- تنفيذ مكونات Gradle الإضافية
- تطوير أنواع مهام Gradle المخصّصة
- الضبط الكسول
- تجنُّب ضبط المهام