برنامههای Android معمولاً بااستفاده از سیستم ساخت Gradle ساخته میشوند. قبلاز اینکه به جزئیات نحوه پیکربندی ساخت بپردازیم، مفاهیم پشت ساخت را بررسی میکنیم تا بتوانید سیستم را بهطور کلی ببینید.
ساخت چیست؟
سیستم ساخت کد منبع شما را به برنامه اجرایی تبدیل میکند. ساختها اغلب شامل ابزارهای متعددی برای تجزیهوتحلیل، کامپایل، پیوند، و بستهبندی برنامه یا کتابخانه شما هستند. Gradle از رویکردی وظیفهمحور برای سازماندهی و اجرای این فرمانها استفاده میکند.
تکالیف فرمانهایی را دربرمیگیرند که ورودیهایشان را به خروجی ترجمه میکنند. افزایهها تکالیف و پیکربندی آنها را تعریف میکنند. اعمال کردن افزونه در ساخت شما، تکالیف آن را ثبت میکند و آنها را بااستفاده از ورودیها و خروجیهایشان به هم متصل میکند. برای مثال، اعمال افزایه Android Gradle (AGP)
به فایل ساخت شما، همه تکالیف لازم برای ساخت APK یا
کتابخانه Android را ثبت خواهد کرد. افزایه java-library به شما امکان میدهد یک jar از کد منبع جاوا بسازید. افزایههای مشابهی برای Kotlin و زبانهای دیگر وجود دارد، اما افزایههای دیگر
برای گسترش افزایهها درنظر گرفته شدهاند. برای مثال، افزونه protobuf برای افزودن
پشتیبانی protobuf به افزونههای موجود مانند AGP یا java-library درنظر گرفته شده است.
Gradle قرارداد را بر پیکربندی ترجیح میدهد، بنابراین افزایهها با مقادیر پیشفرض خوب ارائه میشوند، اما میتوانید ساخت را ازطریق زبان مختص دامنه (DSL) اعلانی بیشتر پیکربندی کنید. DSL بهگونهای طراحی شده است که بتوانید آنچه را که میخواهید بسازید مشخص کنید، نه نحوه ساخت آن را. منطق موجود در افزونهها «چگونگی» را مدیریت میکند. این پیکربندی در چندین فایل ساخت در پروژه (و زیرپروژههای) شما مشخص شده است.
ورودیهای تکلیف میتواند فایلها و دایرکتوریها و همچنین اطلاعات دیگری باشد که بهصورت انواع Java (عدد صحیح، رشته، یا کلاسهای سفارشی) کدگذاری شدهاند. بروندادها فقط میتوانند دایرکتوری یا فایل باشند چون باید روی دیسک نوشته شوند. با سیمکشی خروجی یک تکلیف به ورودی تکلیف دیگر، تکالیف به هم پیوند داده میشوند تا یکی قبلاز دیگری اجرا شود.
درحالیکه Gradle از نوشتن کد دلخواه و اعلام وظیفه در فایلهای ساخت شما پشتیبانی میکند، این امر میتواند درک ساخت شما را برای ابزارها و نگهداری آن را برای شما دشوارتر کند. برای مثال، میتوانید برای کد داخل افزایهها آزمایش بنویسید اما نه در فایلهای ساخت. درعوض، باید منطق ساخت و اعلانهای تکلیف را به افزایهها (که شما یا شخص دیگری تعریف میکنید) محدود کنید و نحوه استفاده از آن منطق را در فایلهای ساخت خود اعلام کنید.
وقتی Gradle build اجرا میشود چه اتفاقی میافتد؟
ساختهای Gradle در سه فاز اجرا میشوند. هریک از این فازها بخشهای مختلفی از کد را که در فایلهای ساخت خود تعریف میکنید، اجرا میکنند.
- مقداردهی اولیه تعیین میکند کدام پروژهها و زیرپروژهها در ساخت گنجانده شوند و مسیرهای کلاس حاوی فایلهای ساخت و افزایههای اعمالشده را راهاندازی میکند. این مرحله بر فایل تنظیماتی تمرکز دارد که در آن پروژههایی را که باید ساخته شوند و مکانهایی را که افزایهها و کتابخانهها باید از آنها واکشی شوند اعلام میکنید.
- پیکربندی تکالیف را برای هر پروژه ثبت میکند و فایل ساخت را برای اعمال مشخصات ساخت کاربر اجرا میکند. مهم است بدانید که کد پیکربندی شما به دادهها یا فایلهای تولیدشده درطول اجرا دسترسی نخواهد داشت.
- اجرا «ساخت» واقعی برنامه شما را انجام میدهد. خروجی پیکربندی، یک گراف جهتدار غیرمدور (DAG) از تکالیف است که نشاندهنده تمام مراحل ساخت موردنیاز است که توسط کاربر درخواست شدهاند (تکالیف ارائهشده در خط فرمان یا بهعنوان پیشفرض در فایلهای ساخت). این نمودار نشاندهنده رابطه بین تکالیف است، چه بهطور صریح در تعریف تکلیف بیان شده باشد، چه براساس ورودیها و خروجیهای آن باشد. اگر تکلیفی ورودیای داشته باشد که خروجی تکلیف دیگری است، باید بعداز آن تکلیف دیگر اجرا شود. این مرحله تکالیف قدیمی را به ترتیبی که در نمودار تعریف شده است اجرا میکند؛ اگر ورودیهای تکلیف از آخرین اجرای آن تغییر نکرده باشد، Gradle آن را رد میکند.
برای اطلاعات بیشتر، چرخه حیات ساخت Gradle را ببینید.
زبانهای خاص دامنه پیکربندی
Gradle از زبان مختص دامنه (DSL) برای پیکربندی ساختها استفاده میکند. این رویکرد اعلانی بهجای نوشتن دستورالعملهای گامبهگام (امری)، بر مشخص کردن دادههای شما تمرکز دارد. میتوانید فایلهای ساخت را بااستفاده از Kotlin یا Groovy بنویسید، اما اکیداً توصیه میکنیم از Kotlin استفاده کنید.
زبانهای خاص دامنه تلاش میکنند تا مشارکت در پروژه را برای همه، ازجمله کارشناسان دامنه و برنامهنویسان، آسانتر کنند و زبان کوچکی را تعریف میکنند که دادهها را بهشیوهای طبیعیتر نشان میدهد. افزونههای Gradle میتوانند DSL را گسترش دهند تا دادههای موردنیاز برای تکالیفشان را پیکربندی کنند.
برای مثال، پیکربندی بخش Android ساخت شما ممکن است بهصورت زیر باشد:
کاتلین
android { namespace = "com.example.app" compileSdk { version = release(36) { minorApiLevel = 1 } } // ... defaultConfig { applicationId = "com.example.app" minSdk { version = release(23) } targetSdk { version = release(36) } // ... } }
شیک
android { namespace = 'com.example.app' compileSdk { version = release(36) { minorApiLevel = 1 } } // ... defaultConfig { applicationId = 'com.example.app' minSdk { version = release(23) } targetSdk { version = release(36) } // ... } }
در پشت صحنه، کد DSL شبیه به این است:
fun Project.android(configure: ApplicationExtension.() -> Unit) {
...
}
interface ApplicationExtension {
var namespace: String?
fun compileSdk(configure: CompileSdkSpec.() -> Unit) {
...
}
val defaultConfig: DefaultConfig
fun defaultConfig(configure: DefaultConfig.() -> Unit) {
...
}
}
هر بلوک در DSL با تابعی نشان داده میشود که یک لامبدا برای پیکربندی آن و یک ویژگی با همان نام برای دسترسی به آن میگیرد. این کار باعث میشود کد موجود در فایلهای ساخت شما بیشتر شبیه به مشخصات داده باشد.
وابستگیهای خارجی
سیستم ساخت Maven یک سیستم مشخصات، ذخیرهسازی، و مدیریت وابستگی معرفی کرد. کتابخانهها در مخازن (سرورها یا دایرکتوریها) ذخیره میشوند و فرادادههایی ازجمله نسخه آنها و وابستگیهایشان به کتابخانههای دیگر را دربرمیگیرند. شما مشخص میکنید که کدام مخازن جستجو شوند، از کدام نسخههای وابستگیها میخواهید استفاده کنید، و سیستم ساخت آنها را درطول ساخت بارگیری میکند.
مصنوعات Maven با نام گروه (شرکت، توسعهدهنده، و غیره)، نام مصنوع (نام کتابخانه)، و نسخه آن مصنوع شناسایی میشوند. این معمولاً بهصورت group:artifact:version نشان داده میشود.
این رویکرد مدیریت ساخت را بهطور قابلتوجهی بهبود میبخشد. اغلب میشنوید که به این مخزنها «مخزنهای Maven» میگویند، اما همه اینها به نحوه بستهبندی و انتشار مصنوعات مربوط میشود. این مخازن و فرادادهها در چندین سیستم ساخت مجدداً استفاده شدهاند، ازجمله Gradle (و Gradle میتواند در این مخازن منتشر کند). مخازن عمومی امکان همرسانی را برای استفاده همه فراهم میکنند، و مخازن شرکتی وابستگیهای داخلی را در داخل شرکت نگه میدارند.
همچنین میتوانید پروژهتان را به زیرپروژههای مدولار تقسیم کنید (که در «استودیو Android» با نام «مدول» نیز شناخته میشود) و از آنها بهعنوان وابستگی نیز استفاده کنید. هر زیرپروژه بروندادهایی (مانند jar) تولید میکند که میتواند توسط زیرپروژهها یا پروژه سطح بالای شما مصرف شود. این کار میتواند زمان ساخت را با جداسازی بخشهایی که نیاز به بازسازی دارند بهبود بخشد، و همچنین مسئولیتها را در برنامه بهتر تفکیک کند.
در بخش افزودن وابستگیهای ساخت، با جزئیات بیشتری به نحوه مشخص کردن وابستگیها خواهیم پرداخت.
ساختن گونههای دیگر
وقتی برنامه Android ایجاد میکنید، معمولاً میخواهید چندین نسخه بسازید. انواع مختلف حاوی کدهای متفاوت هستند یا با گزینههای مختلفی ساخته شدهاند، و از انواع ساخت و نسخههای ویژه محصول تشکیل شدهاند.
انواع ساخت گزینههای ساخت اعلامشده را تغییر میدهند. بهطور پیشفرض، AGP انواع ساخت «انتشار» و «اشکالزدایی» را راهاندازی میکند، اما میتوانید آنها را تنظیم کنید و موارد بیشتری اضافه کنید (شاید برای آمادهسازی یا آزمایش داخلی).
ساخت اشکالزدایی برنامه شما را کوچک یا مبهم نمیکند، ساخت آن را تسریع میکند، و همه نمادها را همانطور که هستند حفظ میکند. همچنین برنامه را بهعنوان «قابلاشکالزدایی» علامتگذاری میکند، آن را با کلید اشکالزدایی عمومی امضا میکند، و دسترسی به فایلهای برنامه نصبشده در دستگاه را فعال میکند. این کار امکان کاوش دادههای ذخیرهشده در فایلها و پایگاههای داده را درحین اجرای برنامه فراهم میکند.
ساخت نسخه پخش برنامه را بهینهسازی میکند، آن را با کلید انتشار شما امضا میکند، و از فایلهای برنامه نصبشده محافظت میکند.
بااستفاده از نسخههای ویژه محصول، میتوانید منبع گنجاندهشده و انواع وابستگی را برای برنامه تغییر دهید. برای مثال، ممکن است بخواهید طعمهای «نمونه» و «کامل» یا شاید طعمهای «رایگان» و «پولی» برای برنامهتان ایجاد کنید. منبع مشترکتان را در دایرکتوری مجموعه منبع «اصلی» مینویسید و منبع را در مجموعه منبعی که نام آن از روی نوع گرفته شده است لغو میکنید یا اضافه میکنید.
AGP برای هر ترکیب از نوع ساخت و نسخه ویژه محصول، تنوع ایجاد میکند. اگر
انواع را تعریف نکنید، متغیرها براساس نوع ساخت نامگذاری میشوند. اگر هر دو را تعریف کنید، نام متغیر <flavor><Buildtype> خواهد بود. برای مثال، با انواع ساخت release و debug، و طعمهای demo و full، AGP این گونهها را ایجاد خواهد کرد:
demoReleasedemoDebugfullReleasefullDebug
مراحل بعدی
اکنون که با مفاهیم ساخت آشنا شدید، به ساختار ساخت Android در پروژهتان نگاهی بیندازید.