پلاگین Android Gradle (AGP) سیستم ساخت رسمی برنامه های اندروید است. این شامل پشتیبانی از کامپایل انواع مختلف منابع و پیوند آنها با یکدیگر در یک برنامه است که می توانید آن را در یک دستگاه اندروید فیزیکی یا شبیه ساز اجرا کنید.
AGP حاوی نقاط توسعه برای پلاگین ها برای کنترل ورودی های ساخت و گسترش عملکرد آن از طریق مراحل جدید است که می تواند با وظایف ساخت استاندارد ادغام شود. نسخههای قبلی AGP دارای APIهای رسمی جدا از پیادهسازی داخلی نبودند. با شروع نسخه 7.0، AGP مجموعهای از APIهای رسمی و پایدار دارد که میتوانید به آنها اعتماد کنید.
چرخه عمر AGP API
AGP از چرخه عمر ویژگی Gradle پیروی می کند تا وضعیت API های خود را مشخص کند:
- داخلی : برای استفاده عمومی در نظر گرفته نشده است
- جوجه کشی : برای استفاده عمومی در دسترس است اما نهایی نیست، به این معنی که ممکن است در نسخه نهایی سازگار با عقب نباشند
- عمومی : برای استفاده عمومی و پایدار موجود است
- منسوخ شده : دیگر پشتیبانی نمی شود و با API های جدید جایگزین شده است
سیاست استهلاک
AGP با از بین رفتن APIهای قدیمی و جایگزینی آنها با APIهای جدید و پایدار و یک زبان خاص دامنه جدید (DSL) در حال تکامل است. این تکامل چندین نسخه AGP را در بر می گیرد و می توانید در جدول زمانی مهاجرت AGP API/DSL درباره آن اطلاعات بیشتری کسب کنید.
هنگامی که APIهای AGP منسوخ می شوند، برای این انتقال یا موارد دیگر، در نسخه اصلی فعلی همچنان در دسترس خواهند بود اما هشدارهایی را ایجاد می کنند. APIهای منسوخ شده به طور کامل از AGP در نسخه اصلی بعدی حذف خواهند شد. به عنوان مثال، اگر یک API در AGP 7.0 منسوخ شده باشد، در آن نسخه در دسترس خواهد بود و اخطار ایجاد می کند. آن API دیگر در AGP 8.0 در دسترس نخواهد بود.
برای دیدن نمونههایی از APIهای جدید مورد استفاده در سفارشیسازیهای ساخت رایج، به دستور العملهای پلاگین Android Gradle نگاهی بیندازید. آنها نمونه هایی از سفارشی سازی های رایج ساخت را ارائه می دهند. همچنین میتوانید جزئیات بیشتری درباره APIهای جدید در اسناد مرجع ما بیابید.
اصول ساخت Gradle
این راهنما کل سیستم ساخت Gradle را پوشش نمی دهد. با این حال، حداقل مجموعه مفاهیم ضروری را برای کمک به شما در ادغام با API های ما پوشش می دهد و برای مطالعه بیشتر به اسناد اصلی Gradle پیوند می دهد.
ما دانش اولیه در مورد نحوه عملکرد Gradle، از جمله نحوه پیکربندی پروژهها، ویرایش فایلهای ساخت، اعمال افزونهها و اجرای وظایف را فرض میکنیم. برای آشنایی با اصول اولیه Gradle در رابطه با AGP، توصیه می کنیم Configure your build را مرور کنید. برای آشنایی با چارچوب کلی برای سفارشیسازی پلاگینهای Gradle، به توسعه پلاگینهای سفارشی Gradle مراجعه کنید.
واژه نامه انواع تنبل Gradle
Gradle انواع مختلفی را ارائه می دهد که "تنبل" رفتار می کنند یا به تعویق محاسبات سنگین یا ایجاد Task
به مراحل بعدی ساخت کمک می کنند. این انواع در هسته بسیاری از APIهای Gradle و AGP قرار دارند. لیست زیر شامل انواع اصلی Gradle است که در اجرای تنبل دخیل هستند و روش های کلیدی آنها.
-
Provider<T>
- مقداری از نوع
T
را ارائه می دهد (که در آن "T" به معنای هر نوع است)، که می تواند در طول مرحله اجرا با استفاده ازget()
خوانده شود یا با استفاده ازmap()
به یکProvider<S>
(که در آن "S" به معنای نوع دیگری است) تبدیل شود. متدهایmap()
،flatMap()
وzip()
. توجه داشته باشید کهget()
هرگز نباید در مرحله پیکربندی فراخوانی شود.-
map()
: یک لامبدا را می پذیرد و یکProvider
از نوعS
،Provider<S>
تولید می کند. آرگومان لامبدا برایmap()
مقدارT
را می گیرد و مقدارS
تولید می کند. لامبدا بلافاصله اجرا نمی شود. در عوض، اجرای آن به لحظه ای موکول می شودget()
درProvider<S>
فراخوانی می شود و کل زنجیره را تنبل می کند. -
flatMap()
: همچنین لامبدا را می پذیرد وProvider<S>
را تولید می کند، اما lambda مقدارT
را می گیرد وProvider<S>
را تولید می کند (به جای اینکه مقدارS
مستقیماً تولید کند). زمانی که S را نمی توان در زمان پیکربندی تعیین کرد و می توانید فقطProvider<S>
دریافت کنید، از flatMap () استفاده کنید. در عمل، اگر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
- Implements
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، Artifacts و Tasks را در این سند ببینید.
مراحل ساخت گرید
ساختن یک پروژه ذاتاً فرآیندی پیچیده و نیازمند منابع است و ویژگیهای مختلفی مانند اجتناب از پیکربندی کار، بررسیهای بهروز، و ویژگی ذخیرهسازی پیکربندی وجود دارد که به به حداقل رساندن زمان صرف شده برای محاسبات تکرارپذیر یا غیر ضروری کمک میکند.
برای اعمال برخی از این بهینهسازیها، اسکریپتها و افزونههای Gradle باید در طول هر یک از مراحل ساخت Gradle متمایز از قوانین سختگیرانه پیروی کنند: مقداردهی اولیه، پیکربندی و اجرا. در این راهنما، ما بر روی مراحل پیکربندی و اجرا تمرکز خواهیم کرد. شما می توانید اطلاعات بیشتری در مورد تمام مراحل در راهنمای چرخه عمر ساخت Gradle بیابید.
مرحله پیکربندی
در مرحله پیکربندی، اسکریپتهای ساخت برای همه پروژههایی که بخشی از ساخت هستند، ارزیابی میشوند، افزونهها اعمال میشوند و وابستگیهای ساخت برطرف میشوند. این مرحله باید برای پیکربندی بیلد با استفاده از اشیاء DSL و برای ثبت وظایف و ورودی های آنها به صورت تنبل استفاده شود.
از آنجایی که فاز پیکربندی همیشه اجرا میشود، صرف نظر از اینکه کدام وظیفه اجرا میشود، بسیار مهم است که آن را ناب نگه دارید و محاسبات را به ورودیهایی غیر از خود اسکریپتهای ساخت محدود کنید. یعنی نباید برنامه های خارجی را اجرا کنید یا از شبکه بخوانید یا محاسبات طولانی را انجام دهید که می توانند به عنوان نمونه های Task
مناسب به مرحله اجرا موکول شوند.
مرحله اجرا
در مرحله اجرا، وظایف درخواستی و وظایف وابسته به آنها اجرا می شود. به طور خاص، متد(های) کلاس Task
که با @TaskAction
مشخص شده اند اجرا می شوند. در طول اجرای کار، به شما اجازه داده می شود که از ورودی ها (مانند فایل ها) بخوانید و با فراخوانی Provider<T>.get()
ارائه دهندگان تنبل را حل کنید. حل کردن ارائهدهندههای تنبل به این روش، دنبالهای از فراخوانیهای map()
یا flatMap()
را آغاز میکند که اطلاعات وابستگی وظیفه موجود در ارائهدهنده را دنبال میکنند. وظایف با تنبلی اجرا می شوند تا ارزش های مورد نیاز تحقق یابد.
نوع API، مصنوعات و وظایف
Variant API یک مکانیسم برنامه افزودنی در افزونه Android Gradle است که به شما امکان می دهد گزینه های مختلف را که معمولاً با استفاده از DSL در فایل های پیکربندی ساخت تنظیم می شوند، دستکاری کنید و بر ساخت اندروید تأثیر بگذارند. Variant API همچنین به شما امکان دسترسی به مصنوعات میانی و نهایی را می دهد که توسط بیلد ایجاد می شوند، مانند فایل های کلاس، مانیفست ادغام شده یا فایل های APK/AAB.
نقاط جریان ساخت و توسعه اندروید
هنگام تعامل با AGP، به جای ثبت تماسهای معمولی چرخه عمر Gradle (مانند afterEvaluate()
) یا تنظیم وابستگیهای صریح Task
، از نقاط توسعه ویژه ساخته شده استفاده کنید. وظایف ایجاد شده توسط AGP جزییات پیاده سازی در نظر گرفته می شوند و به عنوان یک API عمومی در معرض نمایش قرار نمی گیرند. شما باید از تلاش برای دریافت نمونه هایی از اشیاء Task
یا حدس زدن نام Task
و افزودن تماس یا وابستگی مستقیم به آن اشیاء Task
اجتناب کنید.
AGP مراحل زیر را برای ایجاد و اجرای Task
Instance های خود تکمیل می کند که به نوبه خود مصنوعات ساخت را تولید می کند. مراحل اصلی درگیر در ایجاد شیء Variant
با فراخوانی دنبال میشوند که به شما امکان میدهند در برخی از اشیاء ایجاد شده به عنوان بخشی از یک ساخت تغییرات ایجاد کنید. توجه به این نکته مهم است که همه فراخوانها در مرحله پیکربندی (توضیح داده شده در این صفحه) اتفاق میافتند و باید سریع اجرا شوند و به جای آن، هر کار پیچیده را به نمونههای Task
مناسب در مرحله اجرا موکول میکند.
- تجزیه DSL : این زمانی است که اسکریپت های ساخت ارزیابی می شوند، و زمانی که ویژگی های مختلف اشیاء DSL Android از بلوک
android
ایجاد و تنظیم می شوند. تماسهای Variant API که در بخشهای زیر توضیح داده شدهاند نیز در این مرحله ثبت میشوند. finalizeDsl()
: Callback که به شما امکان می دهد اشیاء DSL را قبل از قفل شدن برای ایجاد کامپوننت (نوع) تغییر دهید. اشیاءVariantBuilder
بر اساس داده های موجود در اشیاء DSL ایجاد می شوند.قفل DSL : اکنون DSL قفل شده است و تغییرات دیگر امکان پذیر نیست.
beforeVariants()
: این callback می تواند از طریقVariantBuilder
بر روی کامپوننت ها و برخی از ویژگی های آنها تأثیر بگذارد. همچنان اجازه می دهد تا تغییراتی در جریان ساخت و مصنوعات تولید شده ایجاد شود.ایجاد نوع : لیست اجزا و مصنوعاتی که ایجاد خواهند شد اکنون نهایی شده است و قابل تغییر نیست.
onVariants()
: در این callback، شما به اشیاءVariant
ایجاد شده دسترسی پیدا میکنید و میتوانید مقادیر یا ارائهدهندههایی را برای مقادیرProperty
که حاوی آنها هستند تنظیم کنید تا به صورت تنبلی محاسبه شوند.قفل متغیر : اکنون اشیاء مختلف قفل شده اند و تغییرات دیگر امکان پذیر نیست.
Tasks ایجاد شده : اشیاء
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 بلوک اندروید نگه دارید و هر منطق ضروری سفارشی را به buildSrc
یا افزونههای خارجی منتقل کنید . همچنین میتوانید نگاهی به نمونههای buildSrc
در مخزن Gradle recipes 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)
در این callback شما می توانید به اشیاء 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
نباید پس از اتمام اجرای callback 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
- منابع اندروید در دایرکتوری
res
- منابع جاوا در فهرست
resources
- دارایی های اندروید در فهرست
assets
برای فهرست کامل منابعی که میتوانید اضافه کنید، به منابع API مراجعه کنید.
این قطعه کد نشان می دهد که چگونه می توان یک پوشه منبع سفارشی به نام ${variant.name}
با استفاده از تابع addStaticSourceDirectory()
به مجموعه منبع جاوا اضافه کرد. سپس زنجیره ابزار اندروید این پوشه را پردازش می کند.
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 را ببینید.
دستیابی و اصلاح مصنوعات
AGP علاوه بر اینکه به شما امکان میدهد ویژگیهای ساده روی اشیاء Variant
را تغییر دهید، یک مکانیسم توسعه نیز دارد که به شما امکان میدهد مصنوعات میانی و نهایی تولید شده در طول ساخت را بخوانید یا تبدیل کنید. برای مثال، میتوانید محتوای فایل AndroidManifest.xml
نهایی و ادغامشده را در یک Task
سفارشی بخوانید تا آن را تجزیه و تحلیل کنید، یا میتوانید محتوای آن را به طور کامل با فایل مانیفست تولید شده توسط Task
سفارشی خود جایگزین کنید.
میتوانید فهرست مصنوعهایی را که در حال حاضر پشتیبانی میشوند در مستندات مرجع کلاس Artifact
پیدا کنید. هر نوع مصنوع دارای خواص خاصی است که دانستن آنها مفید است:
کاردینالیته
کاردینالیته یک Artifact
تعداد نمونه های FileSystemLocation
یا تعداد فایل ها یا دایرکتوری های نوع مصنوع را نشان می دهد. میتوانید با بررسی کلاس اصلی یک مصنوع اطلاعاتی در مورد اصلی بودن آن به دست آورید: مصنوعات با یک FileSystemLocation
یک زیر کلاس از Artifact.Single
خواهند بود. مصنوعات با چندین نمونه FileSystemLocation
یک زیر کلاس از Artifact.Multiple
خواهند بود.
نوع FileSystemLocation
میتوانید با نگاه کردن به نوع FileSystemLocation
که میتواند یک RegularFile
یا یک Directory
باشد، بررسی کنید که آیا Artifact
فایلها یا دایرکتوریها را نشان میدهد.
عملیات پشتیبانی شده
هر کلاس Artifact
میتواند هر یک از اینترفیسهای زیر را برای نشان دادن عملیاتی که پشتیبانی میکند پیادهسازی کند:
-
Transformable
: به یکArtifact
اجازه می دهد تا به عنوان ورودی برای یکTask
استفاده شود که تغییرات دلخواه را روی آن انجام می دهد و نسخه جدیدی ازArtifact
را خروجی می دهد. -
Appendable
: فقط برای مصنوعاتی اعمال می شود که زیر کلاسArtifact.Multiple
هستند. به این معنی کهArtifact
می تواند به آن اضافه شود، یعنی یکTask
سفارشی می تواند نمونه های جدیدی از این نوعArtifact
ایجاد کند که به لیست موجود اضافه می شود. -
Replaceable
: فقط برای مصنوعاتی اعمال می شود که زیر کلاس هایArtifact.Single
هستند. یکArtifact
قابل تعویض را می توان با یک نمونه کاملاً جدید جایگزین کرد که به عنوان خروجی یکTask
تولید می شود.
علاوه بر سه عملیات اصلاح کننده مصنوع، هر مصنوع از یک عملیات get()
(یا getAll()
) پشتیبانی می کند که یک Provider
با نسخه نهایی مصنوع برمی گرداند (پس از اتمام تمام عملیات روی آن).
پلاگینهای متعدد میتوانند هر تعداد عملیات روی آرتیفکتها را از طریق callback 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
cardinality و FileSystemLocation
کار میکند.
برای کسب اطلاعات بیشتر در مورد گسترش AGP، توصیه می کنیم بخش های زیر را از کتابچه راهنمای سیستم ساخت Gradle بخوانید:
- توسعه پلاگین های Gradle سفارشی
- پیاده سازی پلاگین های Gradle
- توسعه انواع وظایف Gradle سفارشی
- پیکربندی تنبل
- اجتناب از پیکربندی وظیفه