نمای کلی ساخت Gradle, نمای کلی ساخت Gradle

برنامه های اندروید معمولاً با استفاده از سیستم ساخت Gradle ساخته می شوند. قبل از اینکه به جزئیات نحوه پیکربندی بیلد خود بپردازیم، مفاهیم پشت ساخت را بررسی خواهیم کرد تا بتوانید سیستم را به عنوان یک کل ببینید.

بیلد چیست؟

یک سیستم ساخت، کد منبع شما را به یک برنامه اجرایی تبدیل می کند. بیلدها اغلب شامل چندین ابزار برای تجزیه و تحلیل، کامپایل، پیوند دادن و بسته بندی برنامه یا کتابخانه شما هستند. Gradle از یک رویکرد مبتنی بر وظیفه برای سازماندهی و اجرای این دستورات استفاده می کند.

وظایف دستوراتی را محصور می کنند که ورودی های آنها را به خروجی تبدیل می کند. پلاگین ها وظایف و پیکربندی آنها را تعریف می کنند. اعمال یک افزونه برای ساخت، وظایف آن را ثبت می‌کند و با استفاده از ورودی‌ها و خروجی‌های آن‌ها را به یکدیگر متصل می‌کند. به عنوان مثال، اعمال پلاگین Android Gradle (AGP) در فایل ساخت شما، تمام کارهای لازم برای ساخت APK یا Android را ثبت می‌کند. کتابخانه. افزونه java-library به شما امکان می دهد یک jar از کد منبع جاوا بسازید. افزونه‌های مشابهی برای Kotlin و سایر زبان‌ها وجود دارد، اما پلاگین‌های دیگر برای گسترش افزونه‌ها طراحی شده‌اند. به عنوان مثال، پلاگین protobuf برای افزودن پشتیبانی protobuf به پلاگین های موجود مانند AGP یا java-library است.

Gradle قرارداد را بر پیکربندی ترجیح می‌دهد، بنابراین افزونه‌ها با مقادیر پیش‌فرض خوب خارج از جعبه ارائه می‌شوند، اما می‌توانید ساختار را از طریق یک زبان خاص دامنه (DSL) پیکربندی کنید. DSL طوری طراحی شده است که می توانید مشخص کنید چه چیزی بسازید، نه اینکه چگونه آن را بسازید. منطق موجود در افزونه ها "چگونه" را مدیریت می کند. این پیکربندی در چندین فایل ساخت در پروژه شما (و پروژه های فرعی) مشخص شده است.

ورودی های وظیفه می توانند فایل ها و دایرکتوری ها و همچنین اطلاعات دیگری باشند که به صورت انواع جاوا (اعداد صحیح، رشته ها یا کلاس های سفارشی) کدگذاری شده اند. خروجی ها فقط می توانند دایرکتوری یا فایل باشند زیرا باید روی دیسک نوشته شوند. سیم‌کشی یک خروجی کار به ورودی وظیفه دیگر، وظایف را به یکدیگر پیوند می‌دهد تا یکی قبل از دیگری اجرا شود.

در حالی که Gradle از نوشتن کد دلخواه و اعلان‌های وظایف در فایل‌های ساخت شما پشتیبانی می‌کند، این می‌تواند درک ساخت و نگهداری از ابزار را دشوارتر کند. به عنوان مثال، شما می توانید برای کد در داخل افزونه ها تست بنویسید اما در فایل های ساخت. در عوض، شما باید منطق ساخت و اعلان وظایف را به افزونه ها (که شما یا شخص دیگری تعریف می کنید) محدود کنید و نحوه استفاده از آن منطق را در فایل های ساخت خود اعلام کنید.

وقتی یک ساخت Gradle اجرا می شود چه اتفاقی می افتد؟

بیلدهای Gradle در سه فاز اجرا می شوند. هر یک از این فازها قسمت های مختلفی از کد را که در فایل های ساخت خود تعریف می کنید، اجرا می کند.

  • مقداردهی اولیه تعیین می‌کند که کدام پروژه‌ها و پروژه‌های فرعی در بیلد گنجانده شده‌اند، و مسیرهای کلاسی حاوی فایل‌های ساخت و افزونه‌های کاربردی شما را تنظیم می‌کند. این مرحله بر روی یک فایل تنظیمات تمرکز می‌کند که در آن پروژه‌ها را برای ساخت و مکان‌هایی که از آن افزونه‌ها و کتابخانه‌ها واکشی می‌شوند، اعلام می‌کنید.
  • Configuration وظایف هر پروژه را ثبت می کند و فایل ساخت را برای اعمال مشخصات ساخت کاربر اجرا می کند. درک این نکته مهم است که کد پیکربندی شما به داده ها یا فایل های تولید شده در حین اجرا دسترسی نخواهد داشت.
  • Execution "ساخت" واقعی برنامه شما را انجام می دهد. خروجی پیکربندی یک گراف غیر چرخه مستقیم (DAG) از وظایف است که نشان دهنده تمام مراحل ساخت مورد نیاز است که توسط کاربر درخواست شده است (وظایف ارائه شده در خط فرمان یا به عنوان پیش فرض در فایل های ساخت). این نمودار نشان‌دهنده رابطه بین وظایف است، یا به وضوح در اعلان یک کار، یا بر اساس ورودی‌ها و خروجی‌های آن. اگر وظیفه ای ورودی داشته باشد که خروجی کار دیگری است، باید بعد از کار دیگر اجرا شود. این مرحله وظایف قدیمی را به ترتیب تعریف شده در نمودار اجرا می کند. اگر ورودی های یک کار از آخرین اجرای آن تغییر نکرده باشد، Gradle آن را رد می کند.

برای اطلاعات بیشتر به چرخه عمر Gradle Build مراجعه کنید.

DSL های پیکربندی

Gradle از یک زبان اختصاصی دامنه (DSL) برای پیکربندی بیلدها استفاده می کند. این رویکرد اعلامی به جای نوشتن دستورالعمل های گام به گام (ضروری) بر تعیین داده های شما متمرکز است.

DSLها تلاش می کنند تا برای همه، متخصصان حوزه و برنامه نویسان، مشارکت در یک پروژه را آسان تر کنند و زبان کوچکی را تعریف کنند که داده ها را به روشی طبیعی تر نشان دهد. پلاگین های Gradle می توانند DSL را برای پیکربندی داده های مورد نیاز برای وظایف خود گسترش دهند.

به عنوان مثال، پیکربندی بخش Android از بیلد شما ممکن است به صورت زیر باشد:

کاتلین

android {
    namespace = "com.example.app"
    compileSdk = 34
    // ...

    defaultConfig {
        applicationId = "com.example.app"
        minSdk = 34
        // ...
    }
}

شیار

android {
    namespace 'com.example.myapplication'
    compileSdk 34
    // ...

    defaultConfig {
        applicationId "com.example.myapplication"
        minSdk 24
        // ...
    }
}

در پشت صحنه، کد DSL شبیه به موارد زیر است:

fun Project.android(configure: ApplicationExtension.() -> Unit) {
    ...
}

interface ApplicationExtension {
    var compileSdk: Int
    var namespace: String?

    val defaultConfig: DefaultConfig

    fun defaultConfig(configure: DefaultConfig.() -> Unit) {
        ...
    }
}

هر بلوک در DSL با یک تابع نشان داده می شود که برای پیکربندی آن از یک لامبدا و برای دسترسی به آن یک ویژگی با همان نام استفاده می کند. این باعث می شود کد موجود در فایل های ساخت شما بیشتر شبیه مشخصات داده باشد.

وابستگی های خارجی

سیستم ساخت Maven یک مشخصات وابستگی ، ذخیره سازی و سیستم مدیریت را معرفی کرد. کتابخانه ها در مخازن (سرورها یا دایرکتوری ها) با ابرداده شامل نسخه و وابستگی آنها به کتابخانه های دیگر ذخیره می شوند. شما مشخص می‌کنید که کدام مخازن جستجو شوند، نسخه‌هایی از وابستگی‌هایی که می‌خواهید استفاده کنید، و سیستم ساخت آنها را در طول ساخت دانلود می‌کند.

Maven Artifacts با نام گروه (شرکت، توسعه دهنده و غیره)، نام مصنوع (نام کتابخانه) و نسخه آن مصنوع شناسایی می شوند. این معمولاً به صورت group:artifact:version نشان داده می شود.

این رویکرد به طور قابل توجهی مدیریت ساخت را بهبود می بخشد. شما اغلب چنین مخازنی به نام "مخزن های Maven" را می شنوید، اما همه چیز در مورد نحوه بسته بندی و انتشار آثار است. این مخازن و ابرداده ها در چندین سیستم ساخت، از جمله Gradle مجددا استفاده شده اند (و Gradle می تواند در این مخازن منتشر کند). مخازن عمومی امکان اشتراک گذاری را برای همه فراهم می کند و مخازن شرکت ها وابستگی های داخلی را در خود نگه می دارند.

همچنین می توانید پروژه خود را به زیر پروژه ها (که در اندروید استودیو به عنوان "ماژول" نیز شناخته می شود) مدولار کنید ، که می توانند به عنوان وابستگی نیز استفاده شوند. هر زیر پروژه خروجی هایی (مانند شیشه ها) تولید می کند که می تواند توسط پروژه های فرعی یا پروژه سطح بالای شما مصرف شود. این می تواند زمان ساخت را با جداسازی قطعاتی که نیاز به بازسازی دارند، و همچنین مسئولیت های جداگانه بهتر در برنامه بهبود بخشد.

ما به جزئیات بیشتری در مورد نحوه تعیین وابستگی ها در Add Build Dependencies خواهیم پرداخت.

انواع ساخت

هنگامی که یک برنامه Android ایجاد می کنید، معمولاً می خواهید چندین نوع بسازید. انواع شامل کدهای مختلف یا با گزینه های مختلف ساخته شده اند و از انواع ساخت و طعم محصول تشکیل شده اند.

انواع ساخت، گزینه های ساخت اعلام شده متفاوت است. به‌طور پیش‌فرض، AGP انواع ساخت «release» و «debug» را تنظیم می‌کند، اما می‌توانید آنها را تنظیم کنید و موارد بیشتری را اضافه کنید (شاید برای مرحله‌بندی یا آزمایش داخلی).

ساخت اشکال زدایی برنامه شما را کوچک یا مبهم نمی کند، سرعت ساخت آن را افزایش می دهد و همه نمادها را همانطور که هست حفظ می کند. همچنین برنامه را به عنوان "اشکال زدایی" علامت گذاری می کند، آن را با یک کلید اشکال زدایی عمومی امضا می کند و امکان دسترسی به فایل های برنامه نصب شده روی دستگاه را فراهم می کند. این امکان کاوش داده های ذخیره شده در فایل ها و پایگاه های داده را در حین اجرای برنامه فراهم می کند.

نسخه انتشار برنامه را بهینه می کند، آن را با کلید انتشار امضا می کند و از فایل های برنامه نصب شده محافظت می کند.

با استفاده از طعم های محصول ، می توانید انواع منبع و وابستگی موجود در برنامه را تغییر دهید. برای مثال، ممکن است بخواهید طعم‌های «دمو» و «کامل» را برای برنامه‌تان ایجاد کنید، یا شاید طعم‌های «رایگان» و «پرداخت‌شده». شما منبع مشترک خود را در یک فهرست مجموعه منبع "اصلی" می نویسید، و منبع را در مجموعه منبعی که نام آن طعم است، لغو یا اضافه می کنید.

AGP انواع مختلفی را برای هر ترکیبی از نوع ساخت و طعم محصول ایجاد می کند. اگر طعم‌ها را تعریف نکنید، انواع نام‌گذاری شده بر اساس انواع ساخت‌ها هستند. اگر هر دو را تعریف کنید، نوع آن <flavor><Buildtype> نامیده می شود. به عنوان مثال، با انواع ساخت نسخه ها و debug release ، و طعم های demo و full ، AGP انواع مختلفی را ایجاد می کند:

  • demoRelease
  • demoDebug
  • fullRelease
  • fullDebug

مراحل بعدی

اکنون که مفاهیم ساخت را دیدید، به ساختار ساخت اندروید در پروژه خود نگاهی بیندازید.

،

برنامه های اندروید معمولاً با استفاده از سیستم ساخت Gradle ساخته می شوند. قبل از اینکه به جزئیات نحوه پیکربندی بیلد خود بپردازیم، مفاهیم پشت ساخت را بررسی خواهیم کرد تا بتوانید سیستم را به عنوان یک کل ببینید.

بیلد چیست؟

یک سیستم ساخت، کد منبع شما را به یک برنامه اجرایی تبدیل می کند. بیلدها اغلب شامل چندین ابزار برای تجزیه و تحلیل، کامپایل، پیوند دادن و بسته بندی برنامه یا کتابخانه شما هستند. Gradle از یک رویکرد مبتنی بر وظیفه برای سازماندهی و اجرای این دستورات استفاده می کند.

وظایف دستوراتی را محصور می کنند که ورودی های آنها را به خروجی تبدیل می کند. پلاگین ها وظایف و پیکربندی آنها را تعریف می کنند. اعمال یک افزونه برای ساخت، وظایف آن را ثبت می‌کند و با استفاده از ورودی‌ها و خروجی‌های آن‌ها را به یکدیگر متصل می‌کند. به عنوان مثال، اعمال پلاگین Android Gradle (AGP) در فایل ساخت شما، تمام کارهای لازم برای ساخت APK یا Android را ثبت می‌کند. کتابخانه. افزونه java-library به شما امکان می دهد از کد منبع جاوا یک jar بسازید. افزونه‌های مشابهی برای Kotlin و زبان‌های دیگر وجود دارد، اما پلاگین‌های دیگر برای گسترش افزونه‌ها طراحی شده‌اند. به عنوان مثال، پلاگین protobuf به منظور افزودن پشتیبانی protobuf به پلاگین های موجود مانند AGP یا java-library است.

Gradle قرارداد را بر پیکربندی ترجیح می‌دهد، بنابراین افزونه‌ها با مقادیر پیش‌فرض خوب خارج از جعبه ارائه می‌شوند، اما می‌توانید ساختار را از طریق یک زبان خاص دامنه (DSL) پیکربندی کنید. DSL طوری طراحی شده است که می توانید مشخص کنید چه چیزی بسازید، نه اینکه چگونه آن را بسازید. منطق موجود در افزونه ها "چگونه" را مدیریت می کند. این پیکربندی در چندین فایل ساخت در پروژه شما (و پروژه های فرعی) مشخص شده است.

ورودی های وظیفه می توانند فایل ها و دایرکتوری ها و همچنین اطلاعات دیگری باشند که به صورت انواع جاوا (اعداد صحیح، رشته ها یا کلاس های سفارشی) کدگذاری شده اند. خروجی ها فقط می توانند دایرکتوری یا فایل باشند زیرا باید روی دیسک نوشته شوند. سیم‌کشی یک خروجی کار به ورودی وظیفه دیگر، وظایف را به یکدیگر پیوند می‌دهد تا یکی قبل از دیگری اجرا شود.

در حالی که Gradle از نوشتن کد دلخواه و اعلان‌های وظایف در فایل‌های ساخت شما پشتیبانی می‌کند، این می‌تواند درک ساخت و نگهداری از ابزار را دشوارتر کند. به عنوان مثال، شما می توانید برای کد در داخل افزونه ها تست بنویسید اما در فایل های ساخت. در عوض، شما باید منطق ساخت و اعلان وظایف را به افزونه ها (که شما یا شخص دیگری تعریف می کنید) محدود کنید و نحوه استفاده از آن منطق را در فایل های ساخت خود اعلام کنید.

وقتی یک ساخت Gradle اجرا می شود چه اتفاقی می افتد؟

بیلدهای Gradle در سه فاز اجرا می شوند. هر یک از این فازها قسمت های مختلفی از کد را که در فایل های ساخت خود تعریف می کنید، اجرا می کند.

  • مقداردهی اولیه تعیین می‌کند که کدام پروژه‌ها و پروژه‌های فرعی در بیلد گنجانده شده‌اند، و مسیرهای کلاسی حاوی فایل‌های ساخت و افزونه‌های کاربردی شما را تنظیم می‌کند. این مرحله بر روی یک فایل تنظیمات تمرکز می‌کند که در آن پروژه‌ها را برای ساخت و مکان‌هایی که از آن افزونه‌ها و کتابخانه‌ها واکشی می‌شوند، اعلام می‌کنید.
  • Configuration وظایف هر پروژه را ثبت می کند و فایل ساخت را برای اعمال مشخصات ساخت کاربر اجرا می کند. درک این نکته مهم است که کد پیکربندی شما به داده ها یا فایل های تولید شده در حین اجرا دسترسی نخواهد داشت.
  • Execution "ساخت" واقعی برنامه شما را انجام می دهد. خروجی پیکربندی یک گراف غیر چرخه مستقیم (DAG) از وظایف است که نشان دهنده تمام مراحل ساخت مورد نیاز است که توسط کاربر درخواست شده است (وظایف ارائه شده در خط فرمان یا به عنوان پیش فرض در فایل های ساخت). این نمودار نشان‌دهنده رابطه بین وظایف است، یا به وضوح در اعلان یک کار، یا بر اساس ورودی‌ها و خروجی‌های آن. اگر وظیفه ای ورودی داشته باشد که خروجی کار دیگری است، باید بعد از کار دیگر اجرا شود. این مرحله وظایف قدیمی را به ترتیب تعریف شده در نمودار اجرا می کند. اگر ورودی های یک کار از آخرین اجرای آن تغییر نکرده باشد، Gradle آن را رد می کند.

برای اطلاعات بیشتر به چرخه عمر Gradle Build مراجعه کنید.

DSL های پیکربندی

Gradle از یک زبان مخصوص دامنه (DSL) برای پیکربندی بیلدها استفاده می کند. این رویکرد اعلامی به جای نوشتن دستورالعمل های گام به گام (ضروری) بر تعیین داده های شما متمرکز است.

DSLها تلاش می کنند تا برای همه، متخصصان حوزه و برنامه نویسان، مشارکت در یک پروژه را آسان تر کنند و زبان کوچکی را تعریف کنند که داده ها را به روشی طبیعی تر نشان دهد. پلاگین های Gradle می توانند DSL را برای پیکربندی داده هایی که برای وظایف خود نیاز دارند گسترش دهند.

به عنوان مثال، پیکربندی بخش Android از ساخت شما ممکن است به صورت زیر باشد:

کاتلین

android {
    namespace = "com.example.app"
    compileSdk = 34
    // ...

    defaultConfig {
        applicationId = "com.example.app"
        minSdk = 34
        // ...
    }
}

شیار

android {
    namespace 'com.example.myapplication'
    compileSdk 34
    // ...

    defaultConfig {
        applicationId "com.example.myapplication"
        minSdk 24
        // ...
    }
}

در پشت صحنه، کد DSL شبیه به موارد زیر است:

fun Project.android(configure: ApplicationExtension.() -> Unit) {
    ...
}

interface ApplicationExtension {
    var compileSdk: Int
    var namespace: String?

    val defaultConfig: DefaultConfig

    fun defaultConfig(configure: DefaultConfig.() -> Unit) {
        ...
    }
}

هر بلوک در DSL با یک تابع نمایش داده می شود که برای پیکربندی آن از یک لامبدا و برای دسترسی به آن یک ویژگی با همان نام استفاده می کند. این باعث می شود کد موجود در فایل های ساخت شما بیشتر شبیه مشخصات داده باشد.

وابستگی های خارجی

سیستم ساخت Maven یک مشخصات وابستگی ، ذخیره سازی و سیستم مدیریت را معرفی کرد. کتابخانه ها در مخازن (سرورها یا دایرکتوری ها) با ابرداده ها شامل نسخه و وابستگی به کتابخانه های دیگر ذخیره می شوند. شما مشخص می‌کنید که کدام مخازن جستجو شوند، نسخه‌هایی از وابستگی‌هایی که می‌خواهید استفاده کنید، و سیستم ساخت آنها را در طول ساخت دانلود می‌کند.

Maven Artifacts با نام گروه (شرکت، توسعه دهنده و غیره)، نام مصنوع (نام کتابخانه) و نسخه آن مصنوع شناسایی می شوند. این معمولاً به صورت group:artifact:version نشان داده می شود.

این رویکرد به طور قابل توجهی مدیریت ساخت را بهبود می بخشد. شما اغلب چنین مخازنی به نام "مخزن های Maven" را می شنوید، اما همه چیز در مورد نحوه بسته بندی و انتشار آثار است. این مخازن و ابرداده ها در چندین سیستم ساخت، از جمله Gradle مجددا استفاده شده اند (و Gradle می تواند در این مخازن منتشر کند). مخازن عمومی امکان اشتراک گذاری را برای همه فراهم می کند و مخازن شرکت ها وابستگی های داخلی را در خود نگه می دارند.

همچنین می توانید پروژه خود را به زیر پروژه ها (که در اندروید استودیو به عنوان "ماژول" نیز شناخته می شود) مدولار کنید ، که می توانند به عنوان وابستگی نیز استفاده شوند. هر زیر پروژه خروجی هایی (مانند شیشه ها) تولید می کند که می تواند توسط پروژه های فرعی یا پروژه سطح بالای شما مصرف شود. این می تواند زمان ساخت را با جداسازی قطعاتی که نیاز به بازسازی دارند، و همچنین مسئولیت های جداگانه بهتر در برنامه بهبود بخشد.

ما به جزئیات بیشتری در مورد نحوه تعیین وابستگی ها در Add Build Dependencies خواهیم پرداخت.

انواع ساخت

هنگامی که یک برنامه Android ایجاد می کنید، معمولاً می خواهید چندین نوع بسازید. انواع شامل کدهای مختلف یا با گزینه های مختلف ساخته شده اند و از انواع ساخت و طعم محصول تشکیل شده اند.

انواع ساخت، گزینه های ساخت اعلام شده متفاوت است. به‌طور پیش‌فرض، AGP انواع ساخت «release» و «debug» را تنظیم می‌کند، اما می‌توانید آنها را تنظیم کنید و موارد بیشتری را اضافه کنید (شاید برای مرحله‌بندی یا آزمایش داخلی).

ساخت اشکال زدایی برنامه شما را کوچک یا مبهم نمی کند، سرعت ساخت آن را افزایش می دهد و همه نمادها را همانطور که هست حفظ می کند. همچنین برنامه را به عنوان "اشکال زدایی" علامت گذاری می کند، آن را با یک کلید اشکال زدایی عمومی امضا می کند و امکان دسترسی به فایل های برنامه نصب شده روی دستگاه را فراهم می کند. این امکان کاوش داده های ذخیره شده در فایل ها و پایگاه های داده را در حین اجرای برنامه فراهم می کند.

نسخه انتشار برنامه را بهینه می کند، آن را با کلید انتشار امضا می کند و از فایل های برنامه نصب شده محافظت می کند.

با استفاده از طعم های محصول ، می توانید انواع منبع و وابستگی موجود در برنامه را تغییر دهید. برای مثال، ممکن است بخواهید طعم‌های «دمو» و «کامل» را برای برنامه‌تان ایجاد کنید، یا شاید طعم‌های «رایگان» و «پرداخت‌شده». منبع مشترک خود را در یک فهرست مجموعه منبع "اصلی" می نویسید، و منبع را در مجموعه منبعی که نام آن طعم است، لغو یا اضافه می کنید.

AGP انواع مختلفی را برای هر ترکیبی از نوع ساخت و طعم محصول ایجاد می کند. اگر طعم‌ها را تعریف نکنید، انواع نام‌گذاری شده بر اساس انواع ساخت‌ها هستند. اگر هر دو را تعریف کنید، نوع آن <flavor><Buildtype> نامیده می شود. برای مثال، با انواع ساخت release و debug ، و طعم‌های demo و full ، AGP انواعی را ایجاد می‌کند:

  • demoRelease
  • demoDebug
  • fullRelease
  • fullDebug

مراحل بعدی

اکنون که مفاهیم ساخت را دیدید، به ساختار ساخت اندروید در پروژه خود نگاهی بیندازید.