סקירה כללית של Gradle build

אפליקציות ל-Android מתוכננות בדרך כלל באמצעות גרסת ה-build של Gradle המערכת. לפני שנסביר בפירוט איך להגדיר את ה-build, נלמד את המושגים שמאחורי ה-build כדי לראות את המערכת כולה.

מה זה build?

מערכת build הופכת את קוד המקור לאפליקציה להפעלה. גרסאות build בדרך כלל כוללות מספר כלים שמאפשרים לנתח, להדר, לקשר ולאחסן את באפליקציה או בספרייה. Gradle משתמשת בגישה מבוססת-משימות כדי לארגן ולהפעיל את הפקודות האלה.

משימות כוללות פקודות שמתרגמות את הקלט שלהן הפלט. יישומי פלאגין מגדירים משימות ואת ההגדרות שלהן. המערכת מיישמת את וריאציית המודעה פלאגין של ה-build רושם את המשימות שלו ומחבר אותן יחד באמצעות של הקלט והפלט. לדוגמה, החלת פלאגין Android Gradle (AGP) לקובץ ה-build שלך יתועדו כל המשימות שדרושות כדי לבנות APK, ספריית Android. הפלאגין java-library מאפשר ליצור צנצנת ממקור Java יישומי פלאגין דומים קיימים עבור Kotlin ובשפות אחרות, אבל יישומי פלאגין אחרים מיועדים להרחבת יישומי פלאגין. לדוגמה, הפלאגין protobuf נועד להוסיף תמיכה ב-Protobuf ביישומי פלאגין קיימים כמו AGP או java-library.

ב-Gradle מעדיפה מוסכמה על פני הגדרות אישיות, כך שיישומי הפלאגין יהיו טובים כברירת מחדל, אבל אפשר להגדיר עוד יותר את ה-build באמצעות Domain-specific Language (DSL) ה-DSL מתוכנן אז אתם יכולים לציין מה לבנות, במקום איך לבנות אותו. הלוגיקה יישומי הפלאגין מנהלים את הפקודה "how". התצורה הזו מצוינת במספר ליצור קבצים בפרויקט (ובפרויקטים משניים).

הקלט של המשימה יכול להיות קבצים וספריות וגם מידע אחר שמקודד כמו סוגי Java (שלמים, מחרוזות או מחלקות בהתאמה אישית). הפלט יכול להיות ספרייה בלבד או קבצים כפי שצריך להיכתב בדיסק. העברת פלט של משימה למכשיר אחר קלט של משימה, מקשר בין המשימות כך שאחת מהן צריכה לרוץ לפני השנייה.

אומנם ב-Gradle יש תמיכה בכתיבת הצהרות על משימות וקודים שרירותיים ב-build והם עשויים להקשות על הכלים להבין את גרסת ה-build שלכם שכדאי לשמור. לדוגמה, תוכלו לכתוב בדיקות של קוד בתוך יישומי פלאגין אבל לא בקובצי build. במקום זאת, צריך להגביל את הלוגיקה והמשימות של ה-build יישומי פלאגין (שאת/ה או מישהו אחר מגדירים) ומצהירים כיצד צריך להשתמש בלוגיקה הזו בקובצי ה-build שלכם.

מה קורה כשמריצים את גרסת ה-build של Gradle?

תהליך הפיתוח של Gradle פועל בשלושה שלבים. כל אחד מהשלבים האלה מבצע חלקים שונים בקוד שמגדירים בקובצי ה-build.

  • האתחול קובע אילו פרויקטים ותת-פרויקטים ייכללו את ה-build, ולהגדיר נתיבי כיתות שמכילים את קובצי ה-build שלכם יישומי פלאגין. השלב הזה מתמקד בקובץ הגדרות שבו אתם מצהירים על פרויקטים ואת המיקומים שמהם יש לאחזר יישומי פלאגין וספריות.
  • הגדרה רושמת משימות לכל פרויקט ומפעילה את ה-build כדי להחיל את מפרט ה-build של המשתמש. חשוב להבין שלקוד התצורה לא תהיה גישה לנתונים או לקבצים שהופקו במהלך הביצוע.
  • הביצוע מבצע את ה"בניין" בפועל של האפליקציה שלך. הפלט של התצורה הוא Directed Acyclic Graph (DAG) של משימות, שמייצג את כל שלבי ה-build הנדרשים שהמשתמש ביקש (ה משימות שסופקו בשורת הפקודה או כברירת מחדל בקובצי build). הזה שמייצג את הקשר בין משימות, שהן מפורשות או על סמך הקלט והפלט שלו. אם למשימה יש קלט הוא הפלט של משימה אחרת, ולאחר מכן היא צריכה לרוץ אחרי המשימה השנייה. הזה שלב זה מפעיל משימות לא עדכניות לפי הסדר המוגדר בתרשים; אם משימה הקלט לא השתנה מאז ההרצה האחרונה שלו, Gradle תדלג עליו.

מידע נוסף מופיע במאמר מחזור החיים של Gradle.

הגדרת DSL

Gradle משתמשת בשפה ספציפית לדומיין (DSL) כדי להגדיר לבנות. הגישה המוצהרתית הזו מתמקדת בציון הנתונים שלכם לכתיבת הוראות מפורטות (חשובות).

DSL מנסים להקל על כולם, מומחי דומיינים ומתכנתים, תורמים לפרויקט, להגדיר שפה קטנה שמייצגת נתונים בדרך טבעית יותר. יישומי פלאגין של Gradle יכולים להרחיב את ה-DSL כדי להגדיר את הנתונים שהם למשימות שלהם.

לדוגמה, הגדרת החלק של Android ב-build עשויה להיראות כך:

Kotlin

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

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

Groovy

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 מיוצג על ידי פונקציה שלוקחת lambda להגדיר אותו, ונכס עם אותו שם כדי לגשת אליו. זה הופך את בקוד בקובצי ה-build שלכם, הוא דומה יותר למפרט נתונים.

יחסי תלות חיצוניים

במערכת ה-build של Maven הוסיפה מפרט של תלויות, אחסון וניהול. הספריות מאוחסנות ב- repositories (שרתים או ספריות), עם מטא-נתונים כולל את הגרסה שלהן ואת התלות שלהן בספריות אחרות. אתם מציינים אילו מאגרי הנתונים לחיפוש, גרסאות של יחסי התלות שבהם רוצים להשתמש והמערכת מורידה אותן במהלך ה-build.

ארטיפקטים של Maven מזוהים לפי שם הקבוצה (חברה, מפתח וכו'), ארטיפקט (שם הספרייה) והגרסה של פריט המידע הזה שנוצר בתהליך הפיתוח (Artifact). בדרך כלל מיוצגת בתור group:artifact:version.

הגישה הזו משפרת משמעותית את ניהול ה-build. בדרך כלל תשמעו תשובות כאלה שנקראים "Maven repositories", פריטי מידע שנוצרו בתהליך הפיתוח (Artifact) נארזים ומתפרסמים. המאגרים והמטא-נתונים האלה נעשה בו שימוש חוזר במספר מערכות פיתוח, כולל Gradle (ו-Gradle יכול לפרסם למטרות הבאות: מאגרים אלה). מאגרים ציבוריים מאפשרים לכולם לשתף, וגם שמסדירים את יחסי התלות הפנימיים של החברה.

אפשר גם לשנות את הפרויקט לפרויקטים משניים. (שנקראות גם 'מודולים' ב-Android Studio), ואפשר להשתמש בהן גם של יחסי התלות. כל תת-פרויקט מייצר פלטים (כמו צנצנות) נצרכים בפרויקטים משניים או בפרויקט ברמה העליונה. זה יכול לשפר את זמן ה-build אפשר לבודד את החלקים שצריך לבנות מחדש, וליצור הפרדה טובה יותר ובתחומי האחריות באפליקציה.

נפרט יותר על האופן שבו אפשר לציין יחסי תלות בקטע הוספת build של יחסי התלות.

יצירת וריאציות

כשיוצרים אפליקציה ל-Android, בדרך כלל רצוי לפתח מספר גרסאות וריאציות. הווריאנטים מכילים קוד שונה או שהם נוצרים עם קוד שונה והם מורכבים מסוגי build וטעמים של מוצרים.

סוגי ה-build משתנים בין אפשרויות ה-build המוצהרות. כברירת מחדל, AGP מגדירה 'השקה' ו'ניפוי באגים' אבל אפשר לשנות אותם ולהוסיף עוד (אולי בדיקות Staging או בדיקות פנימיות).

גרסת build לניפוי באגים לא מקטינה או מעורפלת (obfuscation) של האפליקציה, ולזרז את התהליך ליצור ולשמר את כל הסמלים כמו שהם. הוא גם מסמן את האפליקציה כ- "ניתן לניפוי באגים", חותמים עליו באמצעות מפתח ניפוי באגים גנרי ומאפשרים גישה שהותקנו במכשיר. כך אפשר לחקור שנשמרו נתונים בקבצים ובמסדי נתונים בזמן הפעלת האפליקציה.

גרסת build מבצעת אופטימיזציה של האפליקציה, חותמת עליה באמצעות מפתח הגרסה שלכם מגן על קובצי האפליקציה המותקנים.

באמצעות טעמי מוצרים, אפשר לשנות את המקור הכלול ואת התלות וריאנטים עבור האפליקציה. לדוגמה, ייתכן שתרצו ליצור "הדגמה (דמו)" ו'מלא' טעמים מתאימים לאפליקציה, או אולי 'חינם' וגם 'בתשלום' טעמים. אתם כותבים את המקור המשותף בשדה 'ראשי' ספריית source set, לשנות או להוסיף מקור בקבוצת מקורות שנקראת על שם הטעם.

AGP יוצרת וריאנטים לכל שילוב של סוג build וטעם של המוצר. אם המיקום לא מגדירים טעמים, הווריאנטים נקראים על שם סוגי ה-build. אם מגדירים את שניהם, הווריאנט נקרא <flavor><Buildtype>. לדוגמה, באמצעות גרסת build release ו-debug, בטעמים demo ו-full, יצירת AGP וריאנטים:

  • demoRelease
  • demoDebug
  • fullRelease
  • fullDebug

השלבים הבאים

עכשיו, אחרי שקראתם את המושגים של ה-build, כדאי להציץ בגרסת ה-build של Android של המבנה בפרויקט.