הגדרת וריאנטים של build

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

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

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

לדוגמה, סוג המוצר 'דמו' עשוי לציין מאפיינים מסוימים ודרישות למכשירים, כמו קוד מקור מותאם אישית, משאבים ורמות API מינימלי, בעוד שסוג ה-build 'ניפוי באגים' מחיל הגדרות שונות של build ואריזות, כמו אפשרויות לניפוי באגים ומפתחות חתימה. גרסת ה-build המשולבת של השניים היא הגרסה 'demoDebug' של האפליקציה, והיא כוללת שילוב של ההגדרות והמשאבים הכלולים בטעמה של המוצר 'demo', סוג ה-build 'debug' וקבוצת המקור main/.

הגדרת סוגי build

אפשר ליצור ולהגדיר סוגי build בתוך הבלוק android בקובץ build.gradle.kts ברמת המודול. כשיוצרים מודול חדש, Android Studio יוצרת באופן אוטומטי את סוגי ה-build של ניפוי הבאגים והגרסה המהדורה. סוג ה-build לניפוי באגים לא מופיע בקובץ התצורה של ה-build, אבל Android Studio מגדירה אותו באמצעות debuggable true. כך תוכלו לנפות באגים באפליקציה במכשירי Android מאובטחים ולהגדיר את חתימת האפליקציה באמצעות מאגר מפתחות גנרי לניפוי באגים.

אפשר להוסיף את סוג ה-build לניפוי באגים להגדרות אם רוצים להוסיף או לשנות הגדרות מסוימות. בדוגמה הבאה מצוין applicationIdSuffix לסוג ה-build לצורך ניפוי באגים, ומוגדר סוג build מסוג 'staging' שמאותחל באמצעות הגדרות מסוג ה-build לצורך ניפוי באגים:

Kotlin

android {
    defaultConfig {
        manifestPlaceholders["hostName"] = "www.example.com"
        ...
    }
    buildTypes {
        getByName("release") {
            isMinifyEnabled = true
            proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
        }

        getByName("debug") {
            applicationIdSuffix = ".debug"
            isDebuggable = true
        }

        /**
         * The `initWith` property lets you copy configurations from other build types,
         * then configure only the settings you want to change. This one copies the debug build
         * type, and then changes the manifest placeholder and application ID.
         */
        create("staging") {
            initWith(getByName("debug"))
            manifestPlaceholders["hostName"] = "internal.example.com"
            applicationIdSuffix = ".debugStaging"
        }
    }
}

Groovy

android {
    defaultConfig {
        manifestPlaceholders = [hostName:"www.example.com"]
        ...
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        debug {
            applicationIdSuffix ".debug"
            debuggable true
        }

        /**
         * The `initWith` property lets you copy configurations from other build types,
         * then configure only the settings you want to change. This one copies the debug build
         * type, and then changes the manifest placeholder and application ID.
         */
        staging {
            initWith debug
            manifestPlaceholders = [hostName:"internal.example.com"]
            applicationIdSuffix ".debugStaging"
        }
    }
}

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

מידע נוסף על כל המאפיינים שאפשר להגדיר באמצעות סוגי גרסאות build זמין במסמך העזרה של BuildType.

הגדרת גרסאות של מוצרים

יצירת טעמים של מוצרים דומה ליצירת סוגי גרסאות build. מוסיפים את טעמי המוצרים לבלוק productFlavors בתצורת ה-build וכוללים את ההגדרות הרצויות. גרסאות המוצר תומכות באותם מאפיינים כמו defaultConfig, כי defaultConfig שייך למעשה לסוג ProductFlavor. כלומר, אפשר לספק את ההגדרות הבסיסיות לכל הגרסאות בבלוק defaultConfig, וכל גרסה יכולה לשנות כל אחד מערכי ברירת המחדל האלה, כמו applicationId. למידע נוסף על מזהה האפליקציה, ראו הגדרת מזהה האפליקציה.

הערה: עדיין צריך לציין שם חבילה באמצעות המאפיין package בקובץ המניפסט main/. צריך להשתמש בשם החבילה הזה גם בקוד המקור כדי להפנות לכיתה R או כדי לפתור כל רישום פעילות או שירות יחסי. כך תוכלו להשתמש ב-applicationId כדי לתת לכל גרסת מוצר מזהה ייחודי לחבילה ולהפצה, בלי לשנות את קוד המקור.

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

  Error: All flavors must now belong to a named flavor dimension.
  The flavor 'flavor_name' is not assigned to a flavor dimension.

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

בדוגמת הקוד הבאה יוצרים מאפיין 'גרסה' ומוסיפים את הגרסאות 'דמו' ו'מלא'. לטעמים האלה יש applicationIdSuffix ו-versionNameSuffix משלהם:

Kotlin

android {
    ...
    defaultConfig {...}
    buildTypes {
        getByName("debug"){...}
        getByName("release"){...}
    }
    // Specifies one flavor dimension.
    flavorDimensions += "version"
    productFlavors {
        create("demo") {
            // Assigns this product flavor to the "version" flavor dimension.
            // If you are using only one dimension, this property is optional,
            // and the plugin automatically assigns all the module's flavors to
            // that dimension.
            dimension = "version"
            applicationIdSuffix = ".demo"
            versionNameSuffix = "-demo"
        }
        create("full") {
            dimension = "version"
            applicationIdSuffix = ".full"
            versionNameSuffix = "-full"
        }
    }
}

Groovy

android {
    ...
    defaultConfig {...}
    buildTypes {
        debug{...}
        release{...}
    }
    // Specifies one flavor dimension.
    flavorDimensions "version"
    productFlavors {
        demo {
            // Assigns this product flavor to the "version" flavor dimension.
            // If you are using only one dimension, this property is optional,
            // and the plugin automatically assigns all the module's flavors to
            // that dimension.
            dimension "version"
            applicationIdSuffix ".demo"
            versionNameSuffix "-demo"
        }
        full {
            dimension "version"
            applicationIdSuffix ".full"
            versionNameSuffix "-full"
        }
    }
}

הערה: אם יש לכם אפליקציה מדור קודם (שנוצרה לפני אוגוסט 2021) שאתם מפיצים באמצעות קובצי APK ב-Google Play, כדי להפיץ את האפליקציה באמצעות תמיכה בכמה קובצי APK ב-Google Play, צריך להקצות את אותו ערך applicationId לכל הווריאציות ולתת לכל וריאנט versionCode שונה. כדי להפיץ גרסאות שונות של האפליקציה כאפליקציות נפרדות ב-Google Play, צריך להקצות applicationId שונה לכל גרסה.

אחרי שיוצרים ומגדירים את גרסאות המוצר, לוחצים על Sync Now (סנכרון עכשיו) בסרגל ההתראות. בסיום הסנכרון, Gradle יוצר באופן אוטומטי וריאנטים של גרסאות build על סמך סוגי ה-build וסוג המוצר, ומעניק להם שמות בהתאם ל-<product-flavor><Build-Type>. לדוגמה, אם יצרתם טעמי מוצר בשם 'demo' ו-'full' ושמרתם את סוגי ה-build שמוגדרים כברירת מחדל, 'debug' ו-'release', Gradle ייצור את וריאנטים הבאים של ה-build:

  • demoDebug
  • demoRelease
  • fullDebug
  • fullRelease

כדי לבחור איזו גרסת build ליצור ולהריץ, עוברים אל Build > Select Build Variant ובוחרים גרסת build מהתפריט. כדי להתחיל להתאים אישית כל וריאנט build עם מאפיינים ומשאבים משלו, צריך ליצור ולנהל קבוצות מקור, כפי שמתואר בדף הזה.

שינוי מזהה האפליקציה של וריאנטים של גרסאות build

כשאתם יוצרים קובץ APK או AAB לאפליקציה, כלי ה-build מתייגים את האפליקציה באמצעות מזהה האפליקציה שמוגדר בבלוק defaultConfig בקובץ build.gradle.kts, כפי שמוצג בדוגמה הבאה. עם זאת, אם אתם רוצים ליצור גרסאות שונות של האפליקציה שיופיעו ככרטיסי מוצר נפרדים בחנות Google Play, כמו גרסה 'חינמית' וגרסה 'Pro', תצטרכו ליצור גרסאות build נפרדות עם מזהה אפליקציה שונה לכל אחת מהן.

במקרה כזה, צריך להגדיר כל וריאנט build כטעם מוצר נפרד. לכל גרסת build בתוך הבלוק productFlavors, אפשר להגדיר מחדש את המאפיין applicationId, או להוסיף פלח למזהה האפליקציה שמוגדר כברירת מחדל באמצעות applicationIdSuffix, כפי שמתואר כאן:

Kotlin

android {
    defaultConfig {
        applicationId = "com.example.myapp"
    }
    productFlavors {
        create("free") {
            applicationIdSuffix = ".free"
        }
        create("pro") {
            applicationIdSuffix = ".pro"
        }
    }
}

Groovy

android {
    defaultConfig {
        applicationId "com.example.myapp"
    }
    productFlavors {
        free {
            applicationIdSuffix ".free"
        }
        pro {
            applicationIdSuffix ".pro"
        }
    }
}

כך, מזהה האפליקציה של גרסת המוצר 'חינם' הוא ‎com.example.myapp.free.

אפשר גם להשתמש ב-applicationIdSuffix כדי לצרף פלח על סמך סוג ה-build, כפי שמוצג כאן:

Kotlin

android {
    ...
    buildTypes {
        getByName("debug") {
            applicationIdSuffix = ".debug"
        }
    }
}

Groovy

android {
    ...
    buildTypes {
        debug {
            applicationIdSuffix ".debug"
        }
    }
}

מכיוון ש-Gradle מחיל את ההגדרה של סוג ה-build אחרי טעמי המוצר, מזהה האפליקציה של וריאנט ה-build 'free debug' הוא 'com.example.myapp.free.debug'. האפשרות הזו שימושית אם רוצים להריץ גם את הגרסה לניפוי באגים וגם את הגרסה המהדורה באותו מכשיר, כי לא יכולות להיות שתי אפליקציות עם אותו מזהה אפליקציה.

אם יש לכם אפליקציה מדור קודם (שנוצרה לפני אוגוסט 2021) שאתם מפיצים באמצעות חבילות APK ב-Google Play, ואתם רוצים להשתמש באותה כרטיס אפליקציה כדי להפיץ כמה חבילות APK, שכל אחת מהן מטרגטת הגדרת מכשיר שונה, כמו רמת ה-API, עליכם להשתמש באותו מזהה אפליקציה לכל גרסת build, אבל לתת לכל APK ערך versionCode שונה. למידע נוסף, קראו את המאמר תמיכה בכמה קובצי APK. פרסום באמצעות AAB לא מושפע, כי הוא מתבסס על ארטיפקט יחיד שמשתמש בקוד גרסה ומזהה אפליקציה יחידים כברירת מחדל.

טיפ: אם אתם צריכים להפנות למזהה האפליקציה בקובץ המניפסט, תוכלו להשתמש ב-placeholder‏ ${applicationId} בכל מאפיין מניפסט. במהלך ה-build, Gradle מחליף את התג הזה במזהה האפליקציה בפועל. מידע נוסף זמין במאמר הזרקת משתני build למניפסט.

שילוב של כמה טעמים של מוצרים עם מימדי טעמים

במקרים מסוימים, יכול להיות שתרצו לשלב הגדרות אישיות מכמה גרסאות של המוצר. לדוגמה, יכול להיות שתרצו ליצור הגדרות שונות למוצרים 'מלא' ו'דמו' שמבוססות על רמת ה-API. כדי לעשות זאת, תוכלו להשתמש בפלאגין Android Gradle כדי ליצור כמה קבוצות של טעמי מוצרים כמאפייני טעמים.

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

בדוגמת הקוד הבאה נעשה שימוש במאפיין flavorDimensions כדי ליצור מאפיין 'mode' שמאפשר לקבץ את הגרסאות של המוצר 'full' ו-'demo', ומאפיין 'api' שמאפשר לקבץ את הגדרות הגרסאות של המוצר לפי רמת ה-API:

Kotlin

android {
  ...
  buildTypes {
    getByName("debug") {...}
    getByName("release") {...}
  }

  // Specifies the flavor dimensions you want to use. The order in which you
  // list the dimensions determines their priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.
  flavorDimensions += listOf("api", "mode")

  productFlavors {
    create("demo") {
      // Assigns this product flavor to the "mode" flavor dimension.
      dimension = "mode"
      ...
    }

    create("full") {
      dimension = "mode"
      ...
    }

    // Configurations in the "api" product flavors override those in "mode"
    // flavors and the defaultConfig block. Gradle determines the priority
    // between flavor dimensions based on the order in which they appear next
    // to the flavorDimensions property, with the first dimension having a higher
    // priority than the second, and so on.
    create("minApi24") {
      dimension = "api"
      minSdk = 24
      // To ensure the target device receives the version of the app with
      // the highest compatible API level, assign version codes in increasing
      // value with API level.
      versionCode = 30000 + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi24"
      ...
    }

    create("minApi23") {
      dimension = "api"
      minSdk = 23
      versionCode = 20000  + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi23"
      ...
    }

    create("minApi21") {
      dimension = "api"
      minSdk = 21
      versionCode = 10000  + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi21"
      ...
    }
  }
}
...

Groovy

android {
  ...
  buildTypes {
    debug {...}
    release {...}
  }

  // Specifies the flavor dimensions you want to use. The order in which you
  // list the dimensions determines their priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.
  flavorDimensions "api", "mode"

  productFlavors {
    demo {
      // Assigns this product flavor to the "mode" flavor dimension.
      dimension "mode"
      ...
    }

    full {
      dimension "mode"
      ...
    }

    // Configurations in the "api" product flavors override those in "mode"
    // flavors and the defaultConfig block. Gradle determines the priority
    // between flavor dimensions based on the order in which they appear next
    // to the flavorDimensions property, with the first dimension having a higher
    // priority than the second, and so on.
    minApi24 {
      dimension "api"
      minSdkVersion 24
      // To ensure the target device receives the version of the app with
      // the highest compatible API level, assign version codes in increasing
      // value with API level.

      versionCode 30000 + android.defaultConfig.versionCode
      versionNameSuffix "-minApi24"
      ...
    }

    minApi23 {
      dimension "api"
      minSdkVersion 23
      versionCode 20000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi23"
      ...
    }

    minApi21 {
      dimension "api"
      minSdkVersion 21
      versionCode 10000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi21"
      ...
    }
  }
}
...

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

לדוגמה, בהתאם להגדרת ה-build הקודמת, Gradle יוצר סה"כ 12 וריאנטים של build לפי סכימה הבאה למתן שמות:

  • וריאנט build: [minApi24, minApi23, minApi21][Demo, Full][Debug, Release]
  • קובץ ה-APK התואם: app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
  • לדוגמה,
    וריאנט build: minApi24DemoDebug
    חבילת ה-APK התואמת: app-minApi24-demo-debug.apk

בנוסף לספריות של קבוצות המקור שאפשר ליצור לכל גרסת build ולכל גרסת טעימה של המוצר, אפשר גם ליצור ספריות של קבוצות מקור לכל שילוב של גרסאות הטעימה של המוצר. לדוגמה, אפשר ליצור ולהוסיף מקורות Java לספרייה src/demoMinApi24/java/, ו-Gradle משתמש במקורות האלה רק כשמפתחים וריאנט שמשלב את שני טעמי המוצר האלה.

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

סינון וריאנטים

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

לדוגמה, בהתאם להגדרת ה-build מהקטע הקודם, נניח שאתם מתכננים לתמוך רק ב-API ברמה 23 ואילך בגרסה הניסיונית של האפליקציה. תוכלו להשתמש בבלוק variantFilter כדי לסנן את כל הגדרות הווריאציות של ה-build שמשלבות את 'minApi21' ו'demo':

Kotlin

android {
  ...
  buildTypes {...}

  flavorDimensions += listOf("api", "mode")
  productFlavors {
    create("demo") {...}
    create("full") {...}
    create("minApi24") {...}
    create("minApi23") {...}
    create("minApi21") {...}
  }
}

androidComponents {
    beforeVariants { variantBuilder ->
        // To check for a certain build type, use variantBuilder.buildType == "<buildType>"
        if (variantBuilder.productFlavors.containsAll(listOf("api" to "minApi21", "mode" to "demo"))) {
            // Gradle ignores any variants that satisfy the conditions above.
            variantBuilder.enable = false
        }
    }
}
...

Groovy

android {
  ...
  buildTypes {...}

  flavorDimensions "api", "mode"
  productFlavors {
    demo {...}
    full {...}
    minApi24 {...}
    minApi23 {...}
    minApi21 {...}
  }

  variantFilter { variant ->
      def names = variant.flavors*.name
      // To check for a certain build type, use variant.buildType.name == "<buildType>"
      if (names.contains("minApi21") && names.contains("demo")) {
          // Gradle ignores any variants that satisfy the conditions above.
          setIgnore(true)
      }
  }
}
...

אחרי שמוסיפים מסנן וריאנטים להגדרת ה-build ולוחצים על Sync Now בסרגל ההתראות, Gradle מתעלם מכל וריאנטים של build שעומדים בתנאים שציינתם. וריאנטים של גרסאות build לא מופיעים יותר בתפריט כשלוחצים על Build > Select Build Variant בסרגל התפריטים או על Build Variants בסרגל חלון הכלים.

יצירת קבוצות מקורות

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

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

מערכת Gradle מצפה שהקבצים והספריות של קבוצת המקור יהיו מאורגנים באופן מסוים, בדומה לקבוצת המקור main/. לדוגמה, קובצי הכיתה של Kotlin או Java שספציפיים לסוג ה-build 'debug' אמורים להימצא בתיקיות src/debug/kotlin/ או src/debug/java/.

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

------------------------------------------------------------
Project :app
------------------------------------------------------------

...

debug
----
Compile configuration: debugCompile
build.gradle name: android.sourceSets.debug
Java sources: [app/src/debug/java]
Kotlin sources: [app/src/debug/kotlin, app/src/debug/java]
Manifest file: app/src/debug/AndroidManifest.xml
Android resources: [app/src/debug/res]
Assets: [app/src/debug/assets]
AIDL sources: [app/src/debug/aidl]
RenderScript sources: [app/src/debug/rs]
JNI sources: [app/src/debug/jni]
JNI libraries: [app/src/debug/jniLibs]
Java-style resources: [app/src/debug/resources]

כדי להציג את הפלט הזה, מבצעים את הפעולות הבאות:

  1. לוחצים על Gradle בסרגל של חלון הכלים.
  2. עוברים אל MyApplication‏ > Tasks‏ > android ולוחצים לחיצה כפולה על sourceSets.

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

    1. לוחצים על File (קובץ) > Settings (הגדרות) > Experimental (ניסיוני) (Android Studio > Settings (הגדרות) > Experimental (ניסיוני) ב-macOS).
    2. מבטלים את הבחירה באפשרות Do not build Gradle task list during Gradle sync.
  3. אחרי ש-Gradle יבצע את המשימה, החלון Run ייפתח כדי להציג את הפלט.

הערה: בפלט של המשימה מוסבר גם איך לארגן קבוצות מקורות של קבצים שבהם רוצים להשתמש כדי להריץ בדיקות לאפליקציה, כמו קבוצות מקורות לבדיקה של test/ ו-androidTest/.

כשיוצרים גרסת build חדשה, מערכת Android Studio לא יוצרת בשבילכם את הספריות של קבוצת המקורות, אבל היא מספקת כמה אפשרויות שיעזרו לכם. לדוגמה, כדי ליצור רק את התיקייה java/ לסוג ה-build 'debug':

  1. פותחים את החלונית Project ובוחרים בתצוגה Project מהתפריט שבחלק העליון של החלונית.
  2. נווט אל MyProject/app/src/.
  3. לוחצים לחיצה ימנית על הספרייה src ובוחרים באפשרות New‏ > Directory.
  4. בתפריט בקטע Gradle Source Sets, בוחרים באפשרות full/java.
  5. מקישים על Enter.

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

לדוגמה, כדי ליצור קובץ XML של ערכים לסוג ה-build 'debug':

  1. בחלונית Project, לוחצים לחיצה ימנית על הספרייה src ובוחרים באפשרות New‏ > XML‏ > Values XML File.
  2. מזינים את השם של קובץ ה-XML או משאירים את שם ברירת המחדל.
  3. בתפריט שלצד Target Source Set, בוחרים באפשרות debug.
  4. לוחצים על סיום.

מכיוון שציינתם את סוג ה-build 'debug' כקבוצת המקור של היעד, Android Studio יוצרת את הספריות הנדרשות באופן אוטומטי כשהיא יוצרת את קובץ ה-XML. מבנה הספריות שנוצר נראה כמו באיור 1.

איור 1. ספריות של קבוצת מקורות חדשה לסוג ה-build 'debug'.

קבוצות מקורות פעילות מסומנות בסמל ירוק כדי לציין שהן פעילות. קבוצת המקור debug מקבלת את הסיומת [main] כדי לציין שהיא תשולב בקבוצת המקור main.

באמצעות אותה פרוצדורה, אפשר גם ליצור תיקיות של קבוצות מקורות למאפייני מוצרים, כמו src/demo/, ולגרסאות build, כמו src/demoDebug/. בנוסף, אפשר ליצור קבוצות מקורות לבדיקה שמטרגטות וריאנטים ספציפיים של גרסאות build, כמו src/androidTestDemoDebug/. מידע נוסף זמין במאמר בדיקת קבוצות מקור.

שינוי ההגדרות של קבוצת מקורות ברירת המחדל

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

הבלוק sourceSets חייב להיות בבלוק android. אין צורך להעביר את קובצי המקור למיקום אחר. צריך רק לספק ל-Gradle את הנתיבים היחסיים לקובץ build.gradle.kts ברמת המודול, שבהם Gradle יכול למצוא קבצים לכל רכיב של קבוצת מקורות. במאמר Android Gradle plugin API reference מוסבר אילו רכיבים אפשר להגדיר ואם אפשר למפות אותם לכמה קבצים או תיקיות.

דוגמת הקוד הבאה ממפה מקורות מהספרייה app/other/ לרכיבים מסוימים של קבוצת המקורות main, ומשנה את ספריית השורש של קבוצת המקורות androidTest:

Kotlin

android {
  ...
  // Encapsulates configurations for the main source set.
  sourceSets.getByName("main") {
    // Changes the directory for Java sources. The default directory is
    // 'src/main/java'.
    java.setSrcDirs(listOf("other/java"))

    // If you list multiple directories, Gradle uses all of them to collect
    // sources. Because Gradle gives these directories equal priority, if
    // you define the same resource in more than one directory, you receive an
    // error when merging resources. The default directory is 'src/main/res'.
    res.setSrcDirs(listOf("other/res1", "other/res2"))

    // Note: Avoid specifying a directory that is a parent to one
    // or more other directories you specify. For example, avoid the following:
    // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings']
    // Specify either only the root 'other/res1' directory or only the
    // nested 'other/res1/layouts' and 'other/res1/strings' directories.

    // For each source set, you can specify only one Android manifest.
    // By default, Android Studio creates a manifest for your main source
    // set in the src/main/ directory.
    manifest.srcFile("other/AndroidManifest.xml")
    ...
  }

  // Create additional blocks to configure other source sets.
  sourceSets.getByName("androidTest") {
      // If all the files for a source set are located under a single root
      // directory, you can specify that directory using the setRoot property.
      // When gathering sources for the source set, Gradle looks only in locations
      // relative to the root directory you specify. For example, after applying the
      // configuration below for the androidTest source set, Gradle looks for Java
      // sources only in the src/tests/java/ directory.
      setRoot("src/tests")
      ...
  }
}
...

Groovy

android {
  ...
  sourceSets {
    // Encapsulates configurations for the main source set.
    main {
      // Changes the directory for Java sources. The default directory is
      // 'src/main/java'.
      java.srcDirs = ['other/java']

      // If you list multiple directories, Gradle uses all of them to collect
      // sources. Because Gradle gives these directories equal priority, if
      // you define the same resource in more than one directory, you receive an
      // error when merging resources. The default directory is 'src/main/res'.
      res.srcDirs = ['other/res1', 'other/res2']

      // Note: Avoid specifying a directory that is a parent to one
      // or more other directories you specify. For example, avoid the following:
      // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings']
      // Specify either only the root 'other/res1' directory or only the
      // nested 'other/res1/layouts' and 'other/res1/strings' directories.

      // For each source set, you can specify only one Android manifest.
      // By default, Android Studio creates a manifest for your main source
      // set in the src/main/ directory.
      manifest.srcFile 'other/AndroidManifest.xml'
      ...
    }

    // Create additional blocks to configure other source sets.
    androidTest {

      // If all the files for a source set are located under a single root
      // directory, you can specify that directory using the setRoot property.
      // When gathering sources for the source set, Gradle looks only in locations
      // relative to the root directory you specify. For example, after applying the
      // configuration below for the androidTest source set, Gradle looks for Java
      // sources only in the src/tests/java/ directory.
      setRoot 'src/tests'
      ...
    }
  }
}
...

חשוב לזכור שספריית מקור יכולה להשתייך רק לקבוצת מקורות אחת. לדוגמה, אי אפשר לשתף את אותם מקורות בדיקה עם קבוצות המקורות test ו-androidTest. הסיבה לכך היא ש-Android Studio יוצרת מודולים נפרדים של IntelliJ לכל קבוצת מקורות, ולא יכולה לתמוך בספריות תוכן כפולות בקבוצות מקורות שונות.

פיתוח באמצעות קבוצות מקורות

אפשר להשתמש בספריות של קבוצות מקורות כדי להכיל את הקוד והמשאבים שאתם רוצים לארוז רק עם הגדרות מסוימות. לדוגמה, אם אתם יוצרים את גרסת ה-build 'demoDebug', שהיא המוצר המשולב של סוג ה-build 'debug' וסוג המוצר 'demo', Gradle בודק את הספריות האלה ומקצה להן את העדיפות הבאה:

  1. src/demoDebug/ (קבוצת מקורות של וריאנטים של build)
  2. src/debug/ (build type source set)
  3. src/demo/ (קבוצת מקורות של גרסת המוצר)
  4. src/main/ (קבוצת המקור הראשית)

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

אם משלבים כמה טעמים של מוצרים, העדיפות בין טעמי המוצרים נקבעת לפי המאפיין של הטעם שאליו הם שייכים. כשמציינים מאפייני טעמים באמצעות המאפיין android.flavorDimensions, טעמי המוצרים ששייכים למאפיין הטעם הראשון שציינתם בעדיפות גבוהה יותר מאלה ששייכים למאפיין הטעם השני, וכן הלאה. בנוסף, למערכי מקורות שאתם יוצרים לשילובים של טעמי מוצרים יש עדיפות גבוהה יותר מאשר למערכי מקורות ששייכים לטעם מוצר ספציפי.

סדר העדיפויות קובע לאיזה קבוצת מקורות יש עדיפות גבוהה יותר כש-Gradle משלבת קוד ומשאבים. סביר להניח שספריית demoDebug/ מכילה קובצי מקור ספציפיים לגרסה הזו של ה-build, ולכן אם demoDebug/ כולל קובץ שמוגדר גם ב-debug/, Gradle משתמש בקובץ בקבוצת המקור demoDebug/. באופן דומה, Gradle מעניק לקבצים בקבוצות המקור של סוג ה-build וסוג המוצר עדיפות גבוהה יותר מאשר לקבצים ב-main/. Gradle מתייחס לסדר העדיפות הזה כשמחילים את כללי ה-build הבאים:

  • כל קוד המקור בתיקיות kotlin/ או java/ עובר הידור יחד כדי ליצור פלט יחיד.

    הערה: לגבי וריאנט build נתון, Gradle יוצר שגיאת build אם הוא נתקל בשתי ספריות או יותר של קבוצות מקורות שהוגדרה בהן אותה כיתה של Kotlin או Java. לדוגמה, כשמפתחים אפליקציה לניפוי באגים, אי אפשר להגדיר גם את src/debug/Utility.kt וגם את src/main/Utility.kt, כי Gradle בודק את שתי הספריות האלה במהלך תהליך ה-build ומציג את השגיאה 'duplicate class'. אם רוצים גרסאות שונות של Utility.kt לסוגים שונים של גרסאות build, צריך להגדיר לכל סוג build גרסה משלו של הקובץ ולא לכלול אותו בקבוצת המקורות main/.

  • המניפסטים מוזגו למניפסט אחד. העדיפות ניתנת לפי הסדר של הרשימה בדוגמה הקודמת. כלומר, הגדרות המניפסט של סוג build מבטלות את הגדרות המניפסט של גרסת המוצר, וכן הלאה. למידע נוסף, קראו את המאמר בנושא מיזוג מניפסט.
  • הקבצים בספריות values/ מוזגו יחד. אם לשני קבצים יש שם זהה, למשל שני קבצים מסוג strings.xml, העדיפות ניתנת לפי הסדר שמופיע ברשימה בדוגמה הקודמת. כלומר, ערכים שהוגדרו בקובץ בקבוצת המקורות של סוג ה-build מבטלים את הערכים שהוגדרו באותו קובץ ב-flavor של המוצר, וכן הלאה.
  • המשאבים בספריות res/ ו-asset/ נארזים יחד. אם יש משאבים עם אותו שם שהוגדרו בשתי קבוצות מקורות או יותר, העדיפות ניתנת לפי הסדר של הרשימה בדוגמה הקודמת.
  • ב-Gradle, המשאבים והמניפסטים שכלולים בקשרי התלות של מודולים בספריות מקבלים את העדיפות הנמוכה ביותר בזמן ה-build של האפליקציה.

הצהרת יחסי תלות

כדי להגדיר תלות בגרסת build ספציפית או בקבוצת מקורות לבדיקה, מוסיפים את השם של גרסת ה-build או של קבוצת מקורות הבדיקה לפני מילת המפתח Implementation, כפי שמתואר בדוגמה הבאה:

Kotlin

dependencies {
    // Adds the local "mylibrary" module as a dependency to the "free" flavor.
    "freeImplementation"(project(":mylibrary"))

    // Adds a remote binary dependency only for local tests.
    testImplementation("junit:junit:4.12")

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation("com.android.support.test.espresso:espresso-core:3.6.1")
}

Groovy

dependencies {
    // Adds the local "mylibrary" module as a dependency to the "free" flavor.
    freeImplementation project(":mylibrary")

    // Adds a remote binary dependency only for local tests.
    testImplementation 'junit:junit:4.12'

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.6.1'
}

מידע נוסף על הגדרת יחסי תלות זמין במאמר הוספת יחסי תלות ל-build.

שימוש בניהול יחסי תלות שמתחשב באפשרויות

פלאגין Android Gradle מגרסה 3.0.0 ואילך כולל מנגנון תלות חדש שמתאים באופן אוטומטי בין וריאנטים כשמשתמשים בספרייה. המשמעות היא שהגרסה debug של האפליקציה צורכת באופן אוטומטי את הגרסה debug של הספרייה, וכן הלאה. הוא פועל גם כשמשתמשים בטעמים: וריאנט freeDebug של אפליקציה ישתמש בווריאנט freeDebug של ספרייה.

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

לדוגמה, נניח שהאפליקציה שלכם מגדירה סוג build שנקרא 'staging', אבל אחת מיחסי התלות בספריות שלה לא מגדירה אותו. כשהתוסף ינסה ליצור את הגרסה 'staging' של האפליקציה, הוא לא ידע באיזו גרסה של הספרייה להשתמש, ותופיע הודעת שגיאה שדומה להודעה הבאה:

Error:Failed to resolve: Could not resolve project :mylibrary.
Required by:
    project :app

פתרון שגיאות build שקשורות להתאמת וריאנטים

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

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

  • האפליקציה שלכם כוללת סוג build שלא נכלל בספרייה שאליה יש תלות.

    לדוגמה, האפליקציה כוללת סוג build מסוג 'staging', אבל יחסי התלות כוללים רק סוגי build מסוג 'debug' ו-'release'.

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

    משתמשים ב-matchingFallbacks כדי לציין התאמות חלופיות לסוג build נתון, כפי שמוצג כאן:

    Kotlin

    // In the app's build.gradle.kts file.
    android {
        buildTypes {
            getByName("debug") {}
            getByName("release") {}
            create("staging") {
                // Specifies a sorted list of fallback build types that the
                // plugin can try to use when a dependency does not include a
                // "staging" build type. You may specify as many fallbacks as you
                // like, and the plugin selects the first build type that's
                // available in the dependency.
                matchingFallbacks += listOf("debug", "qa", "release")
            }
        }
    }

    Groovy

    // In the app's build.gradle file.
    android {
        buildTypes {
            debug {}
            release {}
            staging {
                // Specifies a sorted list of fallback build types that the
                // plugin can try to use when a dependency does not include a
                // "staging" build type. You may specify as many fallbacks as you
                // like, and the plugin selects the first build type that's
                // available in the dependency.
                matchingFallbacks = ['debug', 'qa', 'release']
            }
        }
    }
    
  • בממד מסוים של טעמים שקיים גם באפליקציה וגם בספרייה שאליה היא תלויה, האפליקציה כוללת טעמים שלא קיימים בספרייה.

    לדוגמה, גם האפליקציה וגם יחסי התלות שלה בספריות כוללים מאפיין 'tier'. עם זאת, המאפיין 'tier' באפליקציה כולל את הגרסאות 'free' ו-'paid', אבל יחסי התלות כוללים רק את הגרסאות 'demo' ו-'paid' של אותו מאפיין.

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

    משתמשים ב-matchingFallbacks כדי לציין התאמות חלופיות למאפיין הטעם 'חינם' של האפליקציה, כפי שמוצג כאן:

    Kotlin

    // In the app's build.gradle.kts file.
    android {
        defaultConfig{
        // Don't configure matchingFallbacks in the defaultConfig block.
        // Instead, specify fallbacks for a given product flavor in the
        // productFlavors block, as shown below.
      }
        flavorDimensions += "tier"
        productFlavors {
            create("paid") {
                dimension = "tier"
                // Because the dependency already includes a "paid" flavor in its
                // "tier" dimension, you don't need to provide a list of fallbacks
                // for the "paid" flavor.
            }
            create("free") {
                dimension = "tier"
                // Specifies a sorted list of fallback flavors that the plugin
                // can try to use when a dependency's matching dimension does
                // not include a "free" flavor. Specify as many
                // fallbacks as you like; the plugin selects the first flavor
                // that's available in the dependency's "tier" dimension.
                matchingFallbacks += listOf("demo", "trial")
            }
        }
    }
    

    Groovy

    // In the app's build.gradle file.
    android {
        defaultConfig{
        // Don't configure matchingFallbacks in the defaultConfig block.
        // Instead, specify fallbacks for a given product flavor in the
        // productFlavors block, as shown below.
      }
        flavorDimensions 'tier'
        productFlavors {
            paid {
                dimension 'tier'
                // Because the dependency already includes a "paid" flavor in its
                // "tier" dimension, you don't need to provide a list of fallbacks
                // for the "paid" flavor.
            }
            free {
                dimension 'tier'
                // Specifies a sorted list of fallback flavors that the plugin
                // can try to use when a dependency's matching dimension does
                // not include a "free" flavor. Specify as many
                // fallbacks as you like; the plugin selects the first flavor
                // that's available in the dependency's "tier" dimension.
                matchingFallbacks = ['demo', 'trial']
            }
        }
    }
    
  • יחס תלות בספרייה כולל מאפיין טעימה שאינו נכלל באפליקציה.

    לדוגמה, יחסי תלות בספרייה כוללים טעמים למאפיין 'minApi', אבל האפליקציה שלכם כוללת טעמים רק למאפיין 'tier'. כשרוצים ליצור את הגרסה 'freeDebug' של האפליקציה, הפלאגין לא יודע אם להשתמש בגרסת התלות 'minApi23Debug' או בגרסת התלות 'minApi18Debug'.

    חשוב לזכור שאין בעיה אם האפליקציה כוללת מאפיין טעימה שיחסי התלות בספרייה לא כוללים. הסיבה לכך היא שהתוסף מתאים בין טעמים רק של המאפיינים שקיימים ביחס התלות. לדוגמה, אם יחסי תלות לא כוללים מאפיין ל-ABI, בגרסה freeX86Debug של האפליקציה ישתמשו בגרסה freeDebug של יחסי התלות.

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

    Kotlin

    // In the app's build.gradle.kts file.
    android {
        defaultConfig{
        // Specifies a sorted list of flavors that the plugin can try to use from
        // a given dimension. This tells the plugin to select the "minApi18" flavor
        // when encountering a dependency that includes a "minApi" dimension.
        // You can include additional flavor names to provide a
        // sorted list of fallbacks for the dimension.
        missingDimensionStrategy("minApi", "minApi18", "minApi23")
        // Specify a missingDimensionStrategy property for each
        // dimension that exists in a local dependency but not in your app.
        missingDimensionStrategy("abi", "x86", "arm64")
        }
        flavorDimensions += "tier"
        productFlavors {
            create("free") {
                dimension = "tier"
                // You can override the default selection at the product flavor
                // level by configuring another missingDimensionStrategy property
                // for the "minApi" dimension.
                missingDimensionStrategy("minApi", "minApi23", "minApi18")
            }
            create("paid") {}
        }
    }
    

    Groovy

    // In the app's build.gradle file.
    android {
        defaultConfig{
        // Specifies a sorted list of flavors that the plugin can try to use from
        // a given dimension. This tells the plugin to select the "minApi18" flavor
        // when encountering a dependency that includes a "minApi" dimension.
        // You can include additional flavor names to provide a
        // sorted list of fallbacks for the dimension.
        missingDimensionStrategy 'minApi', 'minApi18', 'minApi23'
        // Specify a missingDimensionStrategy property for each
        // dimension that exists in a local dependency but not in your app.
        missingDimensionStrategy 'abi', 'x86', 'arm64'
        }
        flavorDimensions 'tier'
        productFlavors {
            free {
                dimension 'tier'
                // You can override the default selection at the product flavor
                // level by configuring another missingDimensionStrategy property
                // for the 'minApi' dimension.
                missingDimensionStrategy 'minApi', 'minApi23', 'minApi18'
            }
            paid {}
        }
    }
    

למידע נוסף, ראו matchingFallbacks ו-missingDimensionStrategy במסמך העזרה של Android Gradle plugin DSL.

הגדרת הגדרות החתימה

Gradle לא חותם על קובץ ה-APK או ה-AAB של גרסה ייעודית להפצה, אלא אם מגדירים באופן מפורש הגדרת חתימה לגרסה הזו. אם עדיין אין לכם מפתח חתימה, יוצרים מפתח העלאה ומאגר מפתחות באמצעות Android Studio.

כדי להגדיר באופן ידני את הגדרות החתימה לסוג ה-build של הגרסה המשוחררת באמצעות הגדרות build של Gradle:

  1. יוצרים מאגר מפתחות. מאגר מפתחות הוא קובץ בינארי שמכיל קבוצה של מפתחות פרטיים. חובה לשמור את מאגר המפתחות במקום בטוח ומאובטח.
  2. יוצרים מפתח פרטי. מפתח פרטי משמש לחתימה על האפליקציה לצורך הפצה, והוא אף פעם לא נכלל באפליקציה או נחשף לצדדים שלישיים לא מורשים.
  3. מוסיפים את הגדרות החתימה לקובץ build.gradle.kts ברמת המודול:

    Kotlin

    ...
    android {
        ...
        defaultConfig {...}
        signingConfigs {
            create("release") {
                storeFile = file("myreleasekey.keystore")
                storePassword = "password"
                keyAlias = "MyReleaseKey"
                keyPassword = "password"
            }
        }
        buildTypes {
            getByName("release") {
                ...
                signingConfig = signingConfigs.getByName("release")
            }
        }
    }

    Groovy

    ...
    android {
        ...
        defaultConfig {...}
        signingConfigs {
            release {
                storeFile file("myreleasekey.keystore")
                storePassword "password"
                keyAlias "MyReleaseKey"
                keyPassword "password"
            }
        }
        buildTypes {
            release {
                ...
                signingConfig signingConfigs.release
            }
        }
    }

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

כדי לקבל את הסיסמאות האלה ממשתני הסביבה:

Kotlin

storePassword = System.getenv("KSTOREPWD")
keyPassword = System.getenv("KEYPWD")

Groovy

storePassword System.getenv("KSTOREPWD")
keyPassword System.getenv("KEYPWD")

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

אחרי שתשלימו את התהליך הזה, תוכלו להפיץ את האפליקציה ולפרסם אותה ב-Google Play.

אזהרה: חשוב לשמור את מאגר המפתחות ואת המפתח הפרטי במקום בטוח ומאובטח, ולוודא שיש לכם גיבויים מאובטחים שלהם. אם אתם משתמשים בחתימת האפליקציה של Play ואתם מאבדים את מפתח ההעלאה, תוכלו לבקש איפוס דרך Play Console. אם אתם מפרסמים אפליקציה ללא חתימת אפליקציה ב-Play (לאפליקציות שנוצרו לפני אוגוסט 2021) ואתם מאבדים את מפתח חתימת האפליקציה, לא תוכלו לפרסם עדכונים לאפליקציה כי תמיד צריך לחתום על כל הגרסאות של האפליקציה באמצעות אותו מפתח.

חתימה על אפליקציות Wear OS

כשמפרסמים אפליקציות ל-Wear OS, חבילת ה-APK לשעון וחבילת ה-APK האופציונלית לטלפון חייבות להיות חתומות באותו מפתח. מידע נוסף על אריזה וחתימת אפליקציות ל-Wear OS זמין במאמר אריזה והפצה של אפליקציות ל-Wear.