בדף הזה מוסבר איך להגדיר וריאנטים של build כדי ליצור גרסאות שונות של האפליקציה מפרויקט יחיד, ואיך כדי לנהל כראוי את הגדרות יחסי התלות וחתימה.
כל וריאנט build מייצג גרסה אחרת של האפליקציה, שאפשר ליצור. לדוגמה, אפשר ליצור גרסה אחת של האפליקציה בחינם עם כמות מוגבלת של תוכן, וגרסה בתשלום נוספת כוללת יותר. אפשר גם ליצור גרסאות שונות של האפליקציה שמטרגטות מכשירים שונים, לפי רמת ה-API או וריאציות אחרות של מכשירים.
וריאציות של גרסאות הן התוצאה של Gradle שמשתמשת של כללים לשילוב הגדרות, קוד ומשאבים שהוגדרו סוגים שונים של מוצרים וטעמים של מוצרים. למרות שלא מגדירים וריאנטים של גרסת build באופן ישיר, אתם מגדירים את סוגי ה-build ואת טעמי המוצרים שמרכיבים אותם.
לדוגמה, "הדגמה" טעם המוצר יכול לציין תכונות מסוימות
ודרישות המכשיר, כמו קוד מקור מותאם אישית, משאבים,
ברמות ה-API, ואילו המודל 'ניפוי באגים' סוג ה-build מאפשר להחיל גרסאות build שונות
הגדרות אריזה, כמו אפשרויות לניפוי באגים ומפתחות חתימה.
המשלב בין שניהם הוא 'demoDebug' של האפליקציה, והיא כוללת
השילוב של ההגדרות והמשאבים שכלולים בהדגמה
טעם המוצר, "ניפוי באגים" סוג ה-build, וקבוצת המקור main/
.
הגדרה של סוגי גרסאות build
אפשר ליצור ולהגדיר סוגי build ב-android
של הקובץ build.gradle.kts
ברמת המודול. כשיוצרים את
מודול חדש, Android Studio יוצר באופן אוטומטי את גרסת ה-build של ניפוי הבאגים והגרסה
שונים. למרות שסוג ה-build של ניפוי הבאגים לא מופיע בהגדרת ה-build
קובץ, Android Studio מגדיר אותו ב- debuggable
true
. כך ניתן לנפות באגים באפליקציה במכשירי Android מאובטחים
שמגדירה חתימת אפליקציה באמצעות מאגר מפתחות כללי של ניפוי באגים.
כדי להוסיף, אפשר להוסיף להגדרה את סוג ה-build של ניפוי באגים.
או לשנות הגדרות מסוימות. הדוגמה הבאה מציינת ערך
applicationIdSuffix
לסוג ה-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" } } }
מגניב
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 צריך לסנכרן את הפרויקט עם
הגדרה אישית. כדי לסנכרן את הפרויקט, לוחצים על Sync Now (לביצוע הסנכרון).
בסרגל ההתראות שמופיע אחרי שמבצעים שינוי או לוחצים
סנכרון הפרויקט מסרגל הכלים. אם מדובר ב-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 באופן אוטומטי מקצה את כל הטעמים של המודול הזה למאפיין הזה.
דוגמת הקוד הבאה יוצרת מאפיין גרסה בשם 'גרסה' ומוסיף
'demo' ו'מלא' בטעמים שונים של מוצרים. הטעמים האלה מספקים
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" } } }
מגניב
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
שונים לכל וריאציה.
אחרי שיוצרים ומגדירים את טעמי המוצרים, לוחצים על סנכרון
עכשיו בסרגל ההתראות. כשהסנכרון יסתיים, Gradle
יוצרת באופן אוטומטי וריאנטים של build על סמך סוגי ה-build והמוצר
טעמים שלהם ונותנים להם שמות
<product-flavor><Build-Type>
לדוגמה, אם
ההדגמה נוצרה ו'מלא' טעמים של מוצרים, ומשאירים את ברירת המחדל
'ניפוי באגים' וגם
'השקה' גרסת ה-build הבאה של Gradle, יוצרת את וריאנטי ה-build הבאים:
-
demoDebug
-
demoRelease
-
fullDebug
-
fullRelease
כדי לבחור איזה וריאנט של build ל-build ריצה, מעבר אל Build > בוחרים באפשרות 'יצירת וריאנט' ובוחרים או גרסת build מהתפריט. כדי להתחיל בהתאמה אישית של כל וריאנט של build עם תכונות משלו צריך ליצור ולנהל האלה, כפי שמתואר בדף הזה.
שינוי מזהה האפליקציה לווריאציות של גרסת build
כשמפתחים APK או AAB לאפליקציה, כלי ה-build מתייגים את האפליקציה באמצעות
מזהה האפליקציה שהוגדר בבלוק defaultConfig
מ-build.gradle.kts
כפי שאפשר לראות בדוגמה הבאה. עם זאת, אם רוצים ליצור גרסאות שונות של
אפליקציה להופיע כרישומים נפרדים בחנות Google Play, למשל "חינמי" ו-'pro'
של הגרסה הקודמת, צריך ליצור
ליצור וריאציות שלכל אחת מהן יש
מזהה האפליקציה.
במקרה הזה, צריך להגדיר כל וריאנט של build כגרסה נפרדת
בטעם המוצר. לכל טעם
בתוך הבלוק productFlavors
, אפשר להגדיר מחדש את applicationId
נכס. לחלופין, תוכלו להוסיף פלח למזהה האפליקציה שמוגדר כברירת מחדל
באמצעות applicationIdSuffix
, כפי שמוצג כאן:
Kotlin
android { defaultConfig { applicationId = "com.example.myapp" } productFlavors { create("free") { applicationIdSuffix = ".free" } create("pro") { applicationIdSuffix = ".pro" } } }
מגניב
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" } } }
מגניב
android { ... buildTypes { debug { applicationIdSuffix ".debug" } } }
כי Gradle מחילה את ההגדרות של סוג ה-build אחרי טעם המוצר, מזהה האפליקציה לניפוי באגים בחינם הווריאנט build הוא 'com.example.myapp.free.debug'. האפשרות הזו שימושית אם רוצים להפעיל את שני הפורמטים ניפוי באגים וגרסת ה-build באותו מכשיר, כי לאף שתי אפליקציות לא יכולות להיות אותו מזהה אפליקציה.
אם יש לכם אפליקציה מדור קודם (נוצרה לפני אוגוסט 2021) שאתם מפיצים באמצעות חבילות APK ב-Google Play, ואתם רוצים להשתמש באותו דף אפליקציה כדי להפיץ כמה חבילות APK כל טירגוט לתצורת מכשיר אחרת, כמו רמת ה-API, צריך להשתמש באותו מזהה אפליקציה לכל וריאנט של build, אבל לתת ה-APK הואversionCode
שונה. למידע נוסף, אפשר לקרוא את
תמיכה ב-APKs מרובים. הוצאה לאור
השימוש ב-AAB לא מושפע, כי הוא משתמש בארטיפקט יחיד שמשתמש
את קוד הגרסה ומזהה האפליקציה כברירת מחדל.
טיפ: אם אתם צריכים לציין את מזהה האפליקציה בטופס
בקובץ מניפסט, ניתן להשתמש ב-placeholder של ${applicationId}
בכל
מאפיין מניפסט. במהלך ה-build, Gradle מחליפה את התג הזה בתג
מזהה האפליקציה. למידע נוסף, אפשר לעיין במאמר החדרת build.
למניפסט של המשתנים האלה.
כדאי לשלב כמה טעמים של מוצרים עם מידות טעם
במקרים מסוימים, ייתכן שתרצו לשלב הגדרות מכמה מוצרים טעמים. לדוגמה, יכול להיות שתרצו ליצור מערכי הגדרות אישיות שונים "מלא" ו-'demo' טעמים של מוצרים שמבוססים על רמת ה-API. כדי לעשות את זה, הפלאגין Android Gradle מאפשר ליצור מספר קבוצות של טעמי מוצרים מאפיינים.
כשאתם מפתחים את האפליקציה שלכם, Gradle משלבת מוצר תצורה של טעם מכל מאפיין טעם שתגדירו, יחד עם תצורת ה-build כדי ליצור את הווריאנט הסופי של ה-build. ב-Gradle לא לשלב טעמים של מוצרים ששייכים לאותו מאפיין טעם.
דוגמת הקוד הבאה משתמשת באופרטור
flavorDimensions
כדי ליצור 'מצב' טעם
לקיבוץ של המאפיין "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" ... } } } ...
מגניב
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:
[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.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 } } } ...
מגניב
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 ולוחצים על סנכרון
עכשיו בסרגל ההתראות, Gradle מתעלמת מכל וריאנט של גרסת build שעומדת בדרישות
התנאים שמציינים. וריאציות ה-build לא מופיעות יותר בתפריט
כשלוחצים על Build > בוחרים באפשרות 'יצירת וריאנט' בסרגל התפריטים.
או יצירת וריאציות ב-
סרגל החלון של הכלי.
יצירת קבוצות מקור
כברירת מחדל, מערכת Android Studio יוצרת את main/
קבוצת מקורות וספריות עבור
את כל מה שאתם רוצים לשתף בין כל וריאציות ה-build. אבל,
יכול ליצור קבוצות מקור חדשות כדי לקבוע בדיוק אילו קבצים Gradle תיצור
חבילות לסוגי מבנים ספציפיים, טעמים של מוצרים, שילובים
טעמים של מוצרים (כשמשתמשים בטעם)
מאפיינים) וליצור וריאנטים.
לדוגמה, אפשר להגדיר
פונקציונליות בקבוצת המקור main/
ושימוש בטעם המוצר
בקבוצות מקור כדי לשנות את המיתוג של האפליקציה עבור לקוחות שונים, או
כוללים הרשאות מיוחדות ופונקציונליות רישום ביומן רק לווריאציות של build.
שמשתמשות בסוג ה-build של ניפוי הבאגים.
Gradle מצפה שהקבצים והספריות של קבוצת המקור יאורגנו
בדומה לקבוצת המקור main/
. לדוגמה, Gradle
מצפה לקבצים במחלקה של Kotlin או Java שהם ספציפיים ל"ניפוי הבאגים" סוג ה-build שיהיה
נמצאים בספריות src/debug/kotlin/
או src/debug/java/
.
הפלאגין Android Gradle מספק משימת Gradle מועילה שמראה איך לארגן את הקבצים לכל אחד מסוגי ה-build, בטעמים שונים, וליצור וריאציות. לדוגמה, הדוגמה הבאה מפלט המשימה מתארת את המיקום שבו Gradle מצפה למצוא קבצים מסוימים לניפוי באגים לפתח :type
------------------------------------------------------------ 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]
כדי להציג את הפלט, מבצעים את הפעולות הבאות:
- לוחצים על Gradle בסרגל של חלון הכלים.
מנווטים אל MyApplication > משימות > android ו- לוחצים לחיצה כפולה על sourceSets.
כדי לראות את התיקייה Tasks, צריך לאפשר ל-Gradle ליצור את רשימת משימות במהלך הסנכרון. לשם כך, בצע את הצעדים הבאים:
- לוחצים על קובץ > הגדרות > תכונה ניסיונית (Android Studio > הגדרות > ניסיוני ב-macOS).
- ביטול הבחירה באפשרות לא לעשות ליצור רשימת משימות של Gradle במהלך סנכרון Gradle.
- אחרי ש-Gradle יריץ את המשימה, ייפתח החלון Run כדי להציג את הפלט.
הערה: פלט המשימה מראה גם איך לארגן קבוצות מקור
לקבצים שרוצים להשתמש בהם כדי להריץ בדיקות של האפליקציה, כמו
test/
וandroidTest/
קבוצות מקורות לבדיקה.
כשיוצרים וריאציית build חדשה, מערכת Android Studio לא יוצרת את המקור
להגדיר את הספריות עבורכם, אבל עדיין יוצגו לכם כמה אפשרויות שיעזרו לכם. עבור
לדוגמה, כדי ליצור רק את הספרייה java/
עבור 'ניפוי באגים'.
סוג ה-build:
- פותחים את החלונית Project ובוחרים התצוגה Project בתפריט שבחלק העליון של החלונית.
- נווט אל
MyProject/app/src/
. - לוחצים לחיצה ימנית על הספרייה
src
ובוחרים חדש > ספרייה. - בתפריט שבקטע Gradle Source Sets, בוחרים באפשרות full/Java.
- מקישים על Enter.
מערכת Android Studio יוצרת ספרייה של קבוצת מקורות לסוג ה-build של ניפוי הבאגים
ואז יוצר את הספרייה java/
שבתוכה. לחלופין,
מערכת Android Studio יכולה ליצור את הספריות עבורך כשמוסיפים קובץ חדש אל
את הפרויקט לווריאנט build ספציפי.
לדוגמה, כדי ליצור קובץ XML עם ערכים, עבור 'ניפוי באגים'. סוג ה-build:
- בחלונית Project, לוחצים לחיצה ימנית על
src
הספרייה ובוחרים New (חדש) > XML > קובץ XML של ערכים. - מזינים את השם של קובץ ה-XML או משאירים את שם ברירת המחדל.
- בתפריט שלצד קבוצת מקורות יעד, בוחרים לניפוי באגים.
- לוחצים על סיום.
בגלל שהמודל צוין סוג ה-build כמקור היעד שהוגדר, מערכת Android Studio יוצרת באופן אוטומטי את הספריות הנדרשות יוצרת את קובץ ה-XML. מבנה הספרייה שמתקבל נראה כך איור 1.
![](https://developer.android.com/static/images/tools/debug-directories_2-1_2x.png?authuser=8&hl=he)
איור 1. ספריות חדשות של קבוצות המקור לניפוי באגים לפתח מהסוג הזה.
בסמל של קבוצות מקורות פעילות מופיע אינדיקטור ירוק שמעיד על כך שהן פעילות.
קבוצת המקורות debug
מתווספת ל-[main]
כדי להראות שהיא תמוזג
בקבוצת המקור main
.
באמצעות אותו תהליך, אפשר גם ליצור ספריות של קבוצת מקור עבור
טעמים של מוצרים, כמו src/demo/
, ויוצרים וריאציות, כמו
src/demoDebug/
. בנוסף, אפשר ליצור קבוצות של מקורות לבדיקה
שמטרגטות וריאציות build ספציפיות, כמו
src/androidTestDemoDebug/
למידע נוסף, אפשר לקרוא על
קבוצות של מקורות בדיקה.
שינוי ההגדרות של קבוצת המקור המוגדרת כברירת מחדל
אם יש מקורות שלא מסודרים בקובץ ברירת המחדל של קבוצת המקור
במבנה ש-Gradle מצפה, כפי שתואר בקטע הקודם על
וליצור קבוצות מקור, אפשר להשתמש
בלוק של sourceSets
כדי לשנות את המיקום שבו Gradle רוצה לאסוף
קבצים לכל רכיב בקבוצת מקור.
הבלוק sourceSets
חייב להיות
בבלוק android
. לא צריך להעביר את
קובצי מקור; צריך לספק ל-Gradle רק את הנתיבים,
קובץ build.gradle.kts
ברמת המודול, שבו Gradle יכולה
חיפוש קבצים לכל רכיב של קבוצת מקור. כדי ללמוד על אילו רכיבים אפשר
להגדיר ואם ניתן למפות אותם למספר קבצים או ספריות,
מקורות מידע בנושא ה-API של הפלאגין ל-Android Gradle
דוגמת הקוד הבאה ממפה מקורות מהספרייה 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") ... } } ...
מגניב
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, שהוא ה-cross product של 'demo' טעם המוצר ו"ניפוי באגים" build type, Gradle בוחנת את הספריות האלו ונותן להן את העדיפות הבאה:
-
src/demoDebug/
(קבוצת מקור הווריאנט לבנות) -
src/debug/
(קבוצת מקור מסוג build) -
src/demo/
(קבוצת מקור בטעם המוצר) -
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 ושולחת 'מחלקה כפולה' שגיאה. אני רוצה לקבל גרסאות שונות שלUtility.kt
בשביל סוגי build שונים, כל סוג build חייב להגדיר גרסה משלו של את הקובץ ולא לכלול אותו בקבוצת המקורmain/
. - המניפסטים ממוזגים יחד למניפסט אחד. ניתנת עדיפות באותו סדר כמו ברשימה בדוגמה הקודמת. כלומר, הגדרות המניפסט של build type לשינוי הגדרות המניפסט לטעם של מוצר, וכן הלאה. למידה למידע נוסף על מיזוג מניפסטים
- הקבצים בספריות
values/
מוזגו את כל החלקים. אם לשני קבצים יש שם זהה, למשלstrings.xml
קבצים, העדיפות ניתנת באותו סדר שבו בדוגמה הקודמת. כלומר, ערכים שמוגדרים בקובץ בקבוצת המקור של סוג ה-build לשנות את הערכים שמוגדרים באותו קובץ בטעם של מוצר, וכן הלאה. - מקורות מידע בספריות
res/
ו-asset/
נארזות ביחד. אם יש משאבים עם אותו שם מוגדר שתי קבוצות מקור או יותר, העדיפות ניתנת באותו סדר כמו הרשימה בדוגמה הקודמת. - ב-Gradle יש משאבים ומניפסטים כלולים בספרייה של מודולי התלות הם בעדיפות הנמוכה ביותר בעת פיתוח האפליקציה.
הצהרה על יחסי תלות
כדי להגדיר תלות בווריאנט 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.5.1") }
מגניב
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.5.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 שלא קשור התלות של ספרייה.
לדוגמה, האפליקציה שלך כוללת 'סביבת Staging' אבל התלות כוללת רק 'ניפוי באגים' ו"להשיק" סוגי ה-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") } } }
מגניב
// 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'] } } }
למאפיין טעם נתון שקיים גם באפליקציה וגם בספרייה שלה תלויה, האפליקציה כוללת טעמים שלא נכללים בספרייה.
לדוגמה, גם האפליקציה וגם יחסי התלות של הספרייה שלה כוללים 'רמה'. של טעם טעם. אבל ה'שכבה' המאפיין באפליקציה כולל את הערך "free" וגם 'בתשלום' טעמים, תלות כוללת רק את המילה "demo" וגם 'בתשלום' טעמים של אותם מאפיינים.
חשוב לשים לב שעבור מאפיין טעם נתון שקיים גם באפליקציה וגם בספרייה שלה של יחסי התלות, אין בעיה כשהספרייה כוללת טעם מוצר שהאפליקציה שלכם מה לא. הסיבה לכך היא שהפלאגין אף פעם לא מבקש את הטעם הזה מהתלות.
יש להשתמש ב-
matchingFallbacks
כדי לציין התאמות חלופיות ל-'free' של האפליקציה טעם המוצר, כפי שמוצג כאן: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") } } }
מגניב
// 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" אבל האפליקציה כולל טעמים רק ל'רמה' המאפיין. כשרוצים ליצור את הדוח 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") {} } }
מגניב
// 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
בחומר העזר על DSL של הפלאגין Android Gradle.
קביעת הגדרות החתימה
Gradle לא חותמת על ה-APK או על ה-AAB של גרסת ה-build של הגרסה, אלא אם מגדירים במפורש של החתימה על ה-build הזה. אם עדיין אין לכם מפתח חתימה, יצירת מפתח העלאה ומאגר מפתחות באמצעות Android Studio.
כדי להגדיר ידנית את הגדרות החתימה על סוג ה-build של הגרסה באמצעות הגדרות build של Gradle:
- יוצרים מאגר מפתחות. מאגר מפתחות הוא קובץ בינארי שמכיל קבוצה של מפתחות פרטיים. צריך לשמור את מאגר המפתחות במקום בטוח למקום בטוח.
- יצירת מפתח פרטי. מפתח פרטי משמש לחתימה על האפליקציה למטרת הפצה ואף פעם לא ייכללו באפליקציה ולא ייחשפו לצדדים שלישיים לא מורשים.
-
הוספת ההגדרות האישיות של החתימה על
build.gradle.kts
ברמת המודול file:Kotlin
... android { ... defaultConfig {...} signingConfigs { create("release") { storeFile = file("myreleasekey.keystore") storePassword = "password" keyAlias = "MyReleaseKey" keyPassword = "password" } } buildTypes { getByName("release") { ... signingConfig = signingConfigs.getByName("release") } } }
מגניב
... 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")
מגניב
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.