Gradle והפלאגין של Android ל-Gradle מספקים דרך גמישה להדר ליצור ואריזות של אפליקציה או ספרייה ל-Android. הדף הזה אוסף חלק הגדרות וטיפים שימושיים שיעזרו לכם להפיק את המקסימום מכל גרסת build. למידע על דרכים לשיפור המהירות של גרסאות ה-build, אופטימיזציה של מהירות ה-build.
אם זו הפעם הראשונה שאתם משתמשים ב-Gradle, כדאי לקרוא את המאמר הגדרת ה-Build כדי ללמוד את העקרונות הבסיסיים. אפשר גם לבדוק את חומר עזר ל-DSL בפלאגין של Android תיעוד למידע נוסף על המאפיינים שבהם נעשה שימוש בדף הזה.
ניהול פרויקטים ומקורות
הנה כמה הגדרות לניהול המודולים של הפרויקט מקורות מידע. למידע נוסף על יצירה וניהול של פרויקטים ומודולים, אפשר לקרוא בקטע Projects Overview (סקירה כללית של הפרויקטים).
שינוי ההגדרות של קבוצת המקור המוגדרת כברירת מחדל
אפשר להשתמש בבלוק
sourceSets
ברמת המודול build.gradle
כדי לשנות את המיקום שבו Gradle מחפשת קבצים עבור כל רכיב
קבוצת מקור.
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'] // When you list multiple directories, Gradle uses all of them to collect // sources. You should avoid specifying a directory which is a parent to one // or more other directories you specify. res.srcDirs = ['other/res1', 'other/res2'] // For each source set, you can specify only one Android manifest. // The following points Gradle to a different manifest for this source set. 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' ... } } } ...
Kotlin
android { ... sourceSets { // Encapsulates configurations for the main source set. getByName("main") { // Changes the directory for Java sources. The default directory is // 'src/main/java'. java.setSrcDirs("other/java") // When you list multiple directories, Gradle uses all of them to collect // sources. You should avoid specifying a directory which is a parent to one // or more other directories you specify. res.setSrcDirs("other/res1", "other/res2") // For each source set, you can specify only one Android manifest. // The following points Gradle to a different manifest for this source set. 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") ... } } } ...
ניהול ספריות ויחסי תלות
Gradle מספקת מנגנון חזק לניהול יחסי תלות, ספריות מרוחקות או מודולים של ספריות מקומיים.
טירגוט גרסאות build ספציפיות עם הגדרות תלות
אם רוצים תלות רק בקבוצת מקור ספציפית של וריאנט build או בקבוצת מקורות בדיקה ספציפית, צריך להשתמש באותיות רישיות תלות הגדרה אישית ולהוסיף לו את השם של הווריאנט של ה-build, או את השם של גרסת ה-build קבוצת המקור לבדיקה.
Groovy
android {...} // Creates Gradle dependency configurations to use in the dependencies block. configurations { // For variants that combine a product flavor and build type, you need to // intitialize a placeholder for its dependency configuration. freeDebugRuntimeOnly{} ... } dependencies { // Adds an implementation dependency only to the "free" product flavor. freeImplementation 'com.google.firebase:firebase-ads:21.5.1' // Adds a runtimeOnly dependency only to the "freeDebug" build variant. freeDebugRuntimeOnly fileTree(dir: 'libs', include: ['*.jar']) // 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' }
Kotlin
android {...} dependencies { // Use ""() notation for custom flavors and build types // Adds an implementation dependency only to the "free" product flavor. "freeImplementation"("com.google.firebase:firebase-ads:21.5.1") // Adds a runtimeOnly dependency only to the "freeDebug" build variant. "freeDebugRuntimeOnly"(fileTree("dir" to "libs", "include" to "*.jar")) // 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") }
יוצרים גרסאות שונות של האפליקציה
Gradle והפלאגין של Android מאפשרים ליצור גרסאות שונות של ממודול יחיד, באמצעות הגדרה של גרסאות build.
הגדרת קודי גרסאות דינמיים
כברירת מחדל, כש-Gradle יוצר חבילות APK לפרויקט, לכל APK יש את
פרטי גרסה זהים, כפי שצוין בקובץ build.gradle
ברמת המודול.
כי חנות Google Play לא מאפשרת להשתמש בכמה חבילות APK לאותה אפליקציה
שלכולם יש פרטי גרסה זהים, צריך לוודא שלכל APK
versionCode ייחודי משלו לפני
להעלות לחנות Play.
אפשר לעשות זאת באמצעות לוגיקה מותאמת אישית של build שמקצה קוד גרסה אחר לכל APK בזמן ה-build. לדוגמה, כשיוצרים חבילות APK נפרדות לכל אחד מהם ממשק ABI, ניהול גרסאות של APK אוטומטי ייראה בערך כך:
Groovy
android { ... defaultConfig { ... versionCode 4 } splits { ... } } // Map for the version code that gives each ABI a value. ext.abiCodes = ['armeabi-v7a':1, mips:2, x86:3] // For per-density APKs, create a similar map like this: // ext.densityCodes = ['hdpi': 1, 'xhdpi': 2, 'xxhdpi': 3, 'xxxhdpi': 4] import com.android.build.OutputFile // For each APK output variant, override versionCode with a combination of // ext.abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode // is equal to defaultConfig.versionCode. If you configure product flavors that // define their own versionCode, variant.versionCode uses that value instead. android.applicationVariants.all { variant -> // Assigns a different version code for each output APK // other than the universal APK. variant.outputs.each { output -> // Stores the value of ext.abiCodes that is associated with the ABI for this variant. def baseAbiVersionCode = // Determines the ABI for this variant and returns the mapped value. project.ext.abiCodes.get(output.getFilter(OutputFile.ABI)) // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes, // the following code does not override the version code for universal APKs. // However, because we want universal APKs to have the lowest version code, // this outcome is desirable. if (baseAbiVersionCode != null) { // Assigns the new version code to versionCodeOverride, which changes the version code // for only the output APK, not for the variant itself. Skipping this step simply // causes Gradle to use the value of variant.versionCode for the APK. output.versionCodeOverride = baseAbiVersionCode * 1000 + variant.versionCode } } }
Kotlin
android { ... defaultConfig { ... versionCode = 4 } splits { ... } } // Map for the version code that gives each ABI a value. val abiCodes = mapOf("armeabi-v7a" to 1, "mips" to 2, "x86" to 3) // For per-density APKs, create a similar map like this: // val densityCodes = mapOf("hdpi" to 1, "xhdpi" to 2, "xxhdpi" to 3, "xxxhdpi" to 4) import com.android.build.api.variant.FilterConfiguration.FilterType.* // For each APK output variant, override versionCode with a combination of // abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode // is equal to defaultConfig.versionCode. If you configure product flavors that // define their own versionCode, variant.versionCode uses that value instead. androidComponents { onVariants { variant -> // Assigns a different version code for each output APK // other than the universal APK. variant.outputs.forEach { output -> val name = output.filters.find { it.filterType == ABI }?.identifier // Stores the value of abiCodes that is associated with the ABI for this variant. val baseAbiCode = abiCodes[name] // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes, // the following code does not override the version code for universal APKs. // However, because we want universal APKs to have the lowest version code, // this outcome is desirable. if (baseAbiCode != null) { // Assigns the new version code to output.versionCode, which changes the version code // for only the output APK, not for the variant itself. output.versionCode.set(baseAbiCode * 1000 + (output.versionCode.get() ?: 0)) } } } }
שילוב של כמה טעמים של מוצרים
במקרים מסוימים, ייתכן שתרצו לשלב הגדרות אישיות מכמה טעמים של מוצרים. כדי לעשות את זה, צריך להתקין את הפלאגין ל-Android של Gradle מאפשרת ליצור קבוצות של טעמים של מוצרים, שנקראות טעמים מאפיינים.
דוגמת הקוד הבאה משתמשת ברכיב
flavorDimensions
כדי ליצור מצב 'מצב' מאפיין טעם לקבוצה
את המילה "מלא" ו-'demo' טעמים של מוצרים, ו-"api" מאפיין טעם לקבוצה
הגדרות אישיות של המוצר על סמך רמת ה-API. Gradle ואז משלב
טעמים של מוצרים מה"מצב" למאפיין ה-API המאפיין.
Groovy
android { ... buildTypes { debug {...} release {...} } // Specifies the flavor dimensions you want to use. The order in which you // list each dimension determines its 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 above--the first dimension has 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. To learn more about assigning version codes to // support app updates and uploading to Google Play, read Multiple APK Support 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" ... } } } ...
Kotlin
android { ... buildTypes { getByName("debug") {...} getByName("release") {...} } // Specifies the flavor dimensions you want to use. The order in which you // list each dimension determines its 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 above--the first dimension has a higher // priority than the second, and so on. create("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. To learn more about assigning version codes to // support app updates and uploading to Google Play, read Multiple APK Support versionCode = 30000 + android.defaultConfig.versionCode versionNameSuffix = "-minApi24" ... } create("minApi23") { dimension = "api" minSdkVersion(23) versionCode = 20000 + android.defaultConfig.versionCode versionNameSuffix = "-minApi23" ... } create("minApi21") { dimension = "api" minSdkVersion(21) versionCode = 10000 + android.defaultConfig.versionCode versionNameSuffix = "-minApi21" ... } } } ...
סינון וריאציות
אפשר לסנן
ליצור וריאנטים שלא רוצים להשתמש בהם
בלוק variantFilter
בקובץ build.gradle
של המודול.
הקוד לדוגמה הבא מורה ל-Gradle לא ליצור וריאנטים שמשלבים ביניהם
את "minApi21" ו-'demo' טעמים של מוצרים:
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) } } } ...
Kotlin
android { ... buildTypes {...} flavorDimensions "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.enabled = false } } } ...
בדיקת האפליקציה
למידע נוסף על הרצה של בדיקות יחידות מקומיות ומשולבות, ניתן לקרוא את המאמר בדיקת האפליקציה.
הגדרת האפשרויות של איתור שגיאות בקוד
אפשר להגדיר אפשרויות מסוימות של שגיאות בקוד באמצעות
בלוק lintOptions
בקובץ build.gradle
ברמת המודול. שפת תרגום
למידע נוסף על השימוש ב-lint בפרויקט Android, כדאי לקרוא את המאמר שיפור הקוד בעזרת Linux.
Groovy
android { ... lintOptions { // Turns off checks for the issue IDs you specify. disable 'TypographyFractions','TypographyQuotes' // Turns on checks for the issue IDs you specify. These checks are in // addition to the default lint checks. enable 'RtlHardcoded','RtlCompat', 'RtlEnabled' // To enable checks for only a subset of issue IDs and ignore all others, // list the issue IDs with the 'check' property instead. This property overrides // any issue IDs you enable or disable using the properties above. checkOnly 'NewApi', 'InlinedApi' // If set to true, turns off analysis progress reporting by lint. quiet true // if set to true (default), stops the build if errors are found. abortOnError false // if true, only report errors. ignoreWarnings true } } ...
Kotlin
android { ... lintOptions { // Turns off checks for the issue IDs you specify. disable("TypographyFractions") disable("TypographyQuotes") // Turns on checks for the issue IDs you specify. These checks are in // addition to the default lint checks. enable("RtlHardcoded") enable("RtlCompat") enable("RtlEnabled") // To enable checks for only a subset of issue IDs and ignore all others, // list the issue IDs with the 'check' property instead. This property overrides // any issue IDs you enable or disable using the properties above. checkOnly("NewApi", "InlinedApi") // If set to true, turns off analysis progress reporting by lint. quiet = true // if set to true (default), stops the build if errors are found. abortOnError = false // if true, only report errors. ignoreWarnings = true } } ...
קביעת הגדרות מניפסט של אינסטרומנטציה
כש-Gradle יוצר את חבילת ה-APK לבדיקה, היא יוצרת באופן אוטומטי את הקובץ AndroidManifest.xml
מגדיר אותו באמצעות <instrumentation>
. אפשר לשנות חלק מההגדרות של הצומת הזה באמצעות
קובץ מניפסט אחר בקבוצת מקור הבדיקה או
הגדרת קובץ build.gradle
ברמת המודול, כפי שמוצג
דוגמת הקוד הבאה
Groovy
android { ... // Each product flavor you configure can override properties in the // defaultConfig block. To learn more, go to Configure Product Flavors. defaultConfig { ... // Specifies the application ID for the test APK. testApplicationId "com.test.foo" // Specifies the fully-qualified class name of the test instrumentation runner. testInstrumentationRunner "android.test.InstrumentationTestRunner" // If set to 'true', enables the instrumentation class to start and stop profiling. // If set to false (default), profiling occurs the entire time the instrumentation // class is running. testHandleProfiling true // If set to 'true', indicates that the Android system should run the instrumentation // class as a functional test. The default value is 'false' testFunctionalTest true } } ...
Kotlin
android { ... // Each product flavor you configure can override properties in the // defaultConfig block. To learn more, go to Configure Product Flavors. defaultConfig { ... // Specifies the application ID for the test APK. testApplicationId = "com.test.foo" // Specifies the fully-qualified class name of the test instrumentation runner. testInstrumentationRunner = "android.test.InstrumentationTestRunner" // If set to 'true', enables the instrumentation class to start and stop profiling. // If set to false (default), profiling occurs the entire time the instrumentation // class is running. testHandleProfiling = true // If set to 'true', indicates that the Android system should run the instrumentation // class as a functional test. The default value is 'false' testFunctionalTest = true } } ...
שינוי סוג ה-build לבדיקה
כברירת מחדל, כל הבדיקות פועלות מול סוג ה-build של ניפוי הבאגים. אפשר לשנות את זה
לסוג build אחר באמצעות המאפיין testBuildType
ב-
את קובץ build.gradle
ברמת המודול. לדוגמה, אם רוצים
להריץ בדיקות מול ה-staging בודקים את סוג ה-build, עורכים את הקובץ כמו שמוצג
את קטע הקוד הבא.
Groovy
android { ... testBuildType "staging" }
Kotlin
android { ... testBuildType "staging" }
הגדרת אפשרויות לבדיקה של Gradle
כדי לציין אפשרויות שישנו את האופן שבו Gradle תריץ את כל הבדיקות,
חסימה של testOptions
ברמת המודול
build.gradle
Groovy
android { ... // Encapsulates options for running tests. testOptions { // Changes the directory where Gradle saves test reports. By default, Gradle saves test reports // in the path_to_your_project/module_name/build/outputs/reports/ directory. // '$rootDir' sets the path relative to the root directory of the current project. reportDir "$rootDir/test-reports" // Changes the directory where Gradle saves test results. By default, Gradle saves test results // in the path_to_your_project/module_name/build/outputs/test-results/ directory. // '$rootDir' sets the path relative to the root directory of the current project. resultsDir "$rootDir/test-results" } }
Kotlin
android { ... // Encapsulates options for running tests. testOptions { // Changes the directory where Gradle saves test reports. By default, Gradle saves test reports // in the path_to_your_project/module_name/build/outputs/reports/ directory. // '$rootDir' sets the path relative to the root directory of the current project. reportDir "$rootDir/test-reports" // Changes the directory where Gradle saves test results. By default, Gradle saves test results // in the path_to_your_project/module_name/build/outputs/test-results/ directory. // '$rootDir' sets the path relative to the root directory of the current project. resultsDir "$rootDir/test-results" } }
כדי לציין אפשרויות לבדיקות של יחידה מקומית בלבד, צריך להגדיר את
testOptions.unitTests
.
Groovy
android { ... testOptions { ... // Encapsulates options for local unit tests. unitTests { // By default, local unit tests throw an exception any time the code you are testing tries to access // Android platform APIs (unless you mock Android dependencies yourself or with a testing // framework like Mockito). However, you can enable the following property so that the test // returns either null or zero when accessing platform APIs, rather than throwing an exception. returnDefaultValues true // Encapsulates options for controlling how Gradle executes local unit tests. For a list // of all the options you can specify, read Gradle's reference documentation. all { // Sets JVM argument(s) for the test JVM(s). jvmArgs '-XX:MaxPermSize=256m' // You can also check the task name to apply options to only the tests you specify. if (it.name == 'testDebugUnitTest') { systemProperty 'debug', 'true' } } } } }
Kotlin
android { ... testOptions { ... // Encapsulates options for local unit tests. unitTests { // By default, local unit tests throw an exception any time the code you are testing tries to access // Android platform APIs (unless you mock Android dependencies yourself or with a testing // framework like Mockito). However, you can enable the following property so that the test // returns either null or zero when accessing platform APIs, rather than throwing an exception. returnDefaultValues true // Encapsulates options for controlling how Gradle executes local unit tests. For a list // of all the options you can specify, read Gradle's reference documentation. all { // Sets JVM argument(s) for the test JVM(s). jvmArgs '-XX:MaxPermSize=256m' // You can also check the task name to apply options to only the tests you specify. if (it.name == 'testDebugUnitTest') { systemProperty 'debug', 'true' } } } } }
אופטימיזציה של ה-build
בקטע הזה מתוארות כמה תצורות שיעזרו לך להאיץ גרסאות build מצטברות. מידע נוסף זמין במאמר הבא: אופטימיזציה של מהירות ה-build.
כיווץ הקוד
ב-Android Studio נעשה שימוש ב-R8, שצורך קבצים של כללי ProGuard, כדי לכווץ את הקוד. חדשים
פרויקטים, Android Studio משתמש בקובץ הגדרות ברירת מחדל (proguard-android.txt
) מ-
tools/proguard/folder
של ה-SDK של Android. לכיווץ קוד נוסף, אפשר לנסות את
קובץ אחד (proguard-android-optimize.txt
) שנמצא באותו המיקום.
Groovy
android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } ... } ...
Kotlin
android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } ... } ...
כדי להוסיף כללים ספציפיים לכל וריאנט של build, צריך להגדיר
נוסף
מאפיין proguardFiles
לכל טעם. לדוגמה,
הדוגמה הבאה מוסיפה את flavor2-rules.pro
ל-"fla2". עכשיו
גרסת הפצה של ' אופטימיזציית 2' משתמש בכל שלושת קובצי הכללים,
המערכת מחילה גם את חסימת ההפצה.
Groovy
android { ... buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } productFlavors { flavor1 { ... } flavor2 { proguardFile 'flavor2-rules.pro' } } } ...
Kotlin
android { ... buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } productFlavors { flavor1 { ... } flavor2 { proguardFile 'flavor2-rules.pro' } } } ...
מפרסמים את האפליקציה
למידע נוסף על פרסום האפליקציה ב-Google Play, כדאי לקרוא את המאמר פרסום האפליקציה.
חתום על האפליקציה שלך
אמנם Android Studio מספק דרך פשוטה להגדיר חתימה על גרסה
מותאמות אישית מממשק המשתמש, ניתן להגדיר באופן ידני את הבלוק
signingConfigs
ב-build.gradle
של המודול
file:
Groovy
android { ... defaultConfig { ... } // Encapsulates signing configurations. signingConfigs { // Creates a signing configuration called "release". release { // Specifies the path to your keystore file. storeFile file("my-release-key.jks") // Specifies the password for your keystore. storePassword "password" // Specifies the identifying name for your key. keyAlias "my-alias" // Specifies the password for your key. keyPassword "password" } } buildTypes { release { // Adds the "release" signing configuration to the release build type. signingConfig signingConfigs.release ... } } } ...
Kotlin
android { ... defaultConfig { ... } // Encapsulates signing configurations. signingConfigs { // Creates a signing configuration called "release". release { // Specifies the path to your keystore file. storeFile file("my-release-key.jks") // Specifies the password for your keystore. storePassword "password" // Specifies the identifying name for your key. keyAlias "my-alias" // Specifies the password for your key. keyPassword "password" } } buildTypes { release { // Adds the "release" signing configuration to the release build type. signingConfig signingConfigs.release ... } } } ...
הסרת פרטי החתימה הפרטית מהפרויקט
כברירת מחדל, הגדרות החתימה מתועדות בטקסט פשוט
קובץ build.gradle
. אם אתם עובדים עם צוות
בפרויקט בקוד פתוח, אפשר להעביר את המידע הרגיש הזה אל מחוץ ל-build
אחר כך תפתחו את הקובץ הבא.
- יוצרים קובץ בשם
keystore.properties
בתיקיית השורש של את הפרויקט, ולכלול את המידע הבא:storePassword=myStorePassword keyPassword=myKeyPassword keyAlias=myKeyAlias storeFile=myStoreFileLocation
- בקובץ
build.gradle
, טוענים אתkeystore.properties
את הקובץ באופן הבא (הוא צריך להיות לפני החסימה של Android):Groovy
// Creates a variable called keystorePropertiesFile, and initializes it to the // keystore.properties file. def keystorePropertiesFile = rootProject.file("keystore.properties") // Initializes a new Properties() object called keystoreProperties. def keystoreProperties = new Properties() // Loads the keystore.properties file into the keystoreProperties object. keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) android { ... } ...
Kotlin
// Creates a variable called keystorePropertiesFile, and initializes it to the // keystore.properties file. def keystorePropertiesFile = rootProject.file("keystore.properties") // Initializes a new Properties() object called keystoreProperties. def keystoreProperties = new Properties() // Loads the keystore.properties file into the keystoreProperties object. keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) android { ... } ...
- יש להזין את פרטי החתימה ששמורים ב
keystoreProperties
object:Groovy
android { signingConfigs { config { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile file(keystoreProperties['storeFile']) storePassword keystoreProperties['storePassword'] } } ... } ...
Kotlin
android { signingConfigs { config { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile file(keystoreProperties['storeFile']) storePassword keystoreProperties['storePassword'] } } ... } ...
- לוחצים על סנכרון עכשיו בסרגל ההתראות.
מידע נוסף על חתימת אפליקציה זמין במאמר חתימה על האפליקציה.
פיתוח אפליקציות בקלות רבה יותר
הטיפים הבאים יעזרו לכם לפתח אפליקציה ל-Android בקלות רבה יותר.
שיתוף שדות מותאמים אישית וערכי משאבים עם הקוד של האפליקציה
בזמן ה-build, מערכת Gradle יוצרת את הכיתה BuildConfig
כך
יכול לבדוק מידע על גרסת ה-build הנוכחית. אפשר גם להוסיף
שדות מותאמים אישית למחלקה BuildConfig
מה-build שלך ב-Gradle
את קובץ התצורה באמצעות ה-method buildConfigField()
וגישה
את הערכים האלה בקוד זמן הריצה של האפליקציה. באותו אופן, אפשר להוסיף משאב באפליקציה
עם resValue()
.
Groovy
android { ... buildTypes { release { // These values are defined only for the release build, which // is typically used for full builds and continuous builds. buildConfigField("String", "BUILD_TIME", "\"${minutesSinceEpoch}\"") resValue("string", "build_time", "${minutesSinceEpoch}") ... } debug { // Use static values for incremental builds to ensure that // resource files and BuildConfig aren't rebuilt with each run. // If these rebuild dynamically, they can interfere with // Apply Changes as well as Gradle UP-TO-DATE checks. buildConfigField("String", "BUILD_TIME", "\"0\"") resValue("string", "build_time", "0") } } } ...
Kotlin
android { ... buildTypes { release { // These values are defined only for the release build, which // is typically used for full builds and continuous builds. buildConfigField("String", "BUILD_TIME", "\"${minutesSinceEpoch}\"") resValue("string", "build_time", "${minutesSinceEpoch}") ... } debug { // Use static values for incremental builds to ensure that // resource files and BuildConfig aren't rebuilt with each run. // If these rebuild dynamically, they can interfere with // Apply Changes as well as Gradle UP-TO-DATE checks. buildConfigField("String", "BUILD_TIME", "\"0\"") resValue("string", "build_time", "0") } } } ...
בקוד האפליקציה, אפשר לגשת למאפיינים באופן הבא:
Kotlin
... Log.i(TAG, BuildConfig.BUILD_TIME) Log.i(TAG, getString(R.string.build_time))
Java
... Log.i(TAG, BuildConfig.BUILD_TIME); Log.i(TAG, getString(R.string.build_time));
שיתוף מאפיינים באמצעות המניפסט
במקרים מסוימים, ייתכן שתצטרכו להצהיר על אותו נכס בשני החשבונות
המניפסט והקוד שלך (לדוגמה, כאשר מצהירים על רשויות עבור
FileProvider
).
במקום לעדכן את אותו נכס בכמה מיקומים כדי לשקף
להגדיר נכס יחיד בbuild.gradle
של המודול
כדי שהוא יהיה זמין גם למניפסט וגם לקוד, כפי שמוצג
היא דוגמה. למידע נוסף, ניתן לקרוא את המאמר החדרת משתני build אל
מניפסט.
Groovy
android { // For settings specific to a product flavor, configure these properties // for each flavor in the productFlavors block. defaultConfig { // Creates a property for the FileProvider authority. def filesAuthorityValue = applicationId + ".files" // Creates a placeholder property to use in the manifest. manifestPlaceholders = [filesAuthority: filesAuthorityValue] // Adds a new field for the authority to the BuildConfig class. buildConfigField("String", "FILES_AUTHORITY", "\"${filesAuthorityValue}\"") } ... } ...
Kotlin
android { // For settings specific to a product flavor, configure these properties // for each flavor in the productFlavors block. defaultConfig { // Creates a property for the FileProvider authority. val filesAuthorityValue = applicationId + ".files" // Creates a placeholder property to use in the manifest. manifestPlaceholders["filesAuthority"] = filesAuthorityValue // Adds a new field for the authority to the BuildConfig class. buildConfigField("String", "FILES_AUTHORITY", "\"${filesAuthorityValue}\"") } ... } ...
במניפסט, יש לגשת ל-placeholder באופן הבא:
<manifest> ... <application> ... <provider android:name="android.support.v4.content.FileProvider" android:authorities="${filesAuthority}" android:exported="false" android:grantUriPermissions="true"> ... </provider> </application> </manifest>
כשניגשים לשדה FILES_AUTHORITY
בקוד של האפליקציה
בערך כך:
Kotlin
... val contentUri: Uri = FileProvider.getUriForFile(context, BuildConfig.FILES_AUTHORITY, myFile)
Java
... Uri contentUri = FileProvider.getUriForFile(getContext(), BuildConfig.FILES_AUTHORITY, myFile);