المكوّن الإضافي لنظام 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
المناسبة خلال مرحلة التنفيذ بدلاً من ذلك.
- تحليل 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
الأمثلة في مستودع 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() })
}
المساهمة في إنشاء مصادر
يمكن أن يساهم المكوّن الإضافي في توفير بعض أنواع المصادر التي يتم إنشاؤها، مثل:
- رمز التطبيق في الدليل
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()
، وسيضمن "مكوّن 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:
- تطوير مكوّنات Gradle الإضافية المخصّصة
- تنفيذ المكوّنات الإضافية لنظام Gradle
- تطوير أنواع مهام Gradle المخصّصة
- الإعدادات الكسولة
- تجنُّب إعداد المهام