نکات و دستورالعمل‌های Gradle

Gradle و افزایه Android ویژه Gradle روشی انعطاف‌پذیر برای کامپایل، ساخت، و بسته‌بندی برنامه یا کتابخانه Android شما ارائه می‌دهند. این صفحه برخی‌از نکات و پیکربندی‌های مفید را جمع‌آوری می‌کند تا به شما کمک کند بیشترین بهره را از هر ساخت ببرید. اگر می‌خواهید با روش‌های سریع‌تر کردن ساخت آشنا شوید، بهینه‌سازی سرعت ساخت را بخوانید.

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

مدیریت پروژه‌ها و منابع

در اینجا چند پیکربندی برای مدیریت کردن ماژول‌های پروژه و منابع آن‌ها آورده شده است. برای کسب اطلاعات بیشتر درباره ایجاد و مدیریت پروژه‌ها و واحدها، نمای کلی پروژه‌ها را بخوانید.

تغییر پیکربندی‌های مجموعه منبع پیش‌فرض

می‌توانید از بلوک sourceSets در فایل سطح ماژول build.gradle استفاده کنید تا جایی را که Gradle برای جمع‌آوری فایل‌ها برای هر مؤلفه از مجموعه منبع جستجو می‌کند تغییر دهید.

شیک

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'
      ...
    }
  }
}
...

کاتلین

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 سازوکار قدرتمندی برای مدیریت وابستگی‌ها ارائه می‌دهد، چه کتابخانه‌های راه دور باشند و چه ماژول‌های کتابخانه محلی.

هدف قرار دادن ساخت‌های خاص با پیکربندی‌های وابستگی

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

شیک

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.6.1'
}

کاتلین

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.6.1")
}

ایجاد نسخه‌های مختلف برنامه

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

پیکربندی کدهای نسخه پویا

به‌طور پیش‌فرض، وقتی Gradle فایل‌های APK را برای پروژه‌تان تولید می‌کند، هر APK اطلاعات نسخه یکسانی دارد، همان‌طور که در فایل build.gradle سطح ماژول مشخص شده است. چون «فروشگاه Google Play» اجازه نمی‌دهد چند APK برای یک برنامه وجود داشته باشد که همه آن‌ها اطلاعات نسخه یکسانی داشته باشند، باید مطمئن شوید که هر APK قبل‌از بارگذاری در «فروشگاه Play»، کد نسخه منحصربه‌فرد خودش را داشته باشد.

می‌توانید این کار را با منطق ساخت سفارشی انجام دهید که کد نسخه متفاوتی را به هر APK در زمان ساخت اختصاص می‌دهد. برای مثال، هنگام ایجاد فایل‌های APK جداگانه برای هر ABI، نسخه‌بندی خودکار APK چیزی شبیه به این است:

شیک

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
    }
  }
}

کاتلین

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 برای ایجاد پیمانه طعم «حالت» برای گروه‌بندی نسخه‌های ویژه محصول «کامل» و «نمونه»، و پیمانه طعم «api» برای گروه‌بندی پیکربندی‌های نسخه ویژه محصول براساس سطح API استفاده می‌کند. سپس Gradle نسخه‌های ویژه محصول را از بُعد «حالت» با نسخه‌های ویژه محصول از بُعد «api» ترکیب می‌کند.

شیک

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"
      ...
    }
  }
}
...

کاتلین

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» را ترکیب می‌کنند نسازد:

شیک

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)
      }
  }
}
...

کاتلین

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
        }
    }
}
...

آزمایش برنامه

برای کسب اطلاعات بیشتر درباره اجرای آزمایش‌های واحد محلی و یکپارچه، آزمایش کردن برنامه را بخوانید.

پیکربندی گزینه‌های lint

می‌توانید برخی‌از گزینه‌های lint را بااستفاده از بلوک lintOptions در فایل build.gradle سطح ماژول پیکربندی کنید. برای کسب اطلاعات بیشتر درباره استفاده از lint برای پروژه Android، مقاله بهبود کد با Lint را بخوانید.

شیک

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
    }
}
...

کاتلین

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 سطح ماژول خود تغییر دهید، همان‌طور که در نمونه کد زیر نشان داده شده است.

شیک

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
  }
}
...

کاتلین

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
  }
}
...

تغییر نوع ساخت آزمایشی

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

شیک

android {
    ...
    testBuildType "staging"
}

کاتلین

android {
    ...
    testBuildType "staging"
}

پیکربندی گزینه‌های آزمایش Gradle

برای مشخص کردن گزینه‌هایی که نحوه اجرای همه آزمایش‌هایتان توسط Gradle را تغییر می‌دهد، testOptions را در سطح ماژول build.gradle پیکربندی کنید.

شیک

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"
  }
}

کاتلین

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 را پیکربندی کنید.

شیک

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'
        }
      }
    }
  }
}

کاتلین

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'
        }
      }
    }
  }
}

بهینه‌سازی ساخت

این بخش پیکربندی‌هایی را ارائه می‌دهد که به افزایش سرعت ساخت‌های کامل و افزایشی شما کمک می‌کند. برای کسب اطلاعات بیشتر، بهینه‌سازی سرعت ساخت را بخوانید.

کوچک کردن کد

«استودیو Android» از R8 استفاده می‌کند که فایل‌های قوانین ProGuard را برای کوچک کردن کد مصرف می‌کند. برای پروژه‌های جدید، «استودیو Android» از فایل تنظیمات پیش‌فرض (proguard-android.txt) از tools/proguard/folder کیت توسعه نرم‌افزار Android استفاده می‌کند. برای کوچک کردن بیشتر کد، فایل proguard-android-optimize.txt را که در همان مکان است امتحان کنید.

شیک

android {
  buildTypes {
    release {
      minifyEnabled true
      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
                                           'proguard-rules.pro'
    }
  }
  ...
}
...

کاتلین

android {
  buildTypes {
    release {
      minifyEnabled true
      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
                                           'proguard-rules.pro'
    }
  }
  ...
}
...

برای افزودن قوانینی که مختص هر تنوع ساخت است، ویژگی proguardFiles اضافی را برای هر طعم پیکربندی کنید. برای مثال، نمونه زیر flavor2-rules.pro را به «flavor2» اضافه می‌کند. اکنون نسخه پخش «flavor2» از هر سه فایل قانون استفاده می‌کند زیرا فایل‌های بلوک پخش نیز اعمال می‌شوند.

شیک

android {
  ...
  buildTypes {
    release {
      minifyEnabled true
      proguardFiles getDefaultProguardFile('proguard-android.txt'),
             'proguard-rules.pro'
    }
  }
  productFlavors {
    flavor1 {
      ...
    }
    flavor2 {
      proguardFile 'flavor2-rules.pro'
    }
  }
}
...

کاتلین

android {
  ...
  buildTypes {
    release {
      minifyEnabled true
      proguardFiles getDefaultProguardFile('proguard-android.txt'),
             'proguard-rules.pro'
    }
  }
  productFlavors {
    flavor1 {
      ...
    }
    flavor2 {
      proguardFile 'flavor2-rules.pro'
    }
  }
}
...

انتشار برنامه

برای کسب اطلاعات بیشتر درباره انتشار برنامه در Google Play، انتشار برنامه را بخوانید.

برنامه‌تان را امضا کنید

اگرچه «استودیو Android» روشی ساده برای پیکربندی امضا برای ساخت‌های نسخه پخش ازطریق واسط کاربر ارائه می‌دهد، می‌توانید به‌صورت دستی بلوک signingConfigs را در فایل build.gradle واحدتان پیکربندی کنید:

شیک

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
      ...
    }
  }
}
...

کاتلین

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 واحد ثبت می‌شوند. اگر با تیمی یا پروژه متن‌بازی کار می‌کنید، می‌توانید با انجام مراحل زیر این اطلاعات حساس را از فایل‌های ساخت خارج کنید.

  1. فایلی با نام keystore.properties در دایرکتوری ریشه پروژه‌تان ایجاد کنید و اطلاعات زیر را در آن بگنجانید:
    storePassword=myStorePassword
    keyPassword=myKeyPassword
    keyAlias=myKeyAlias
    storeFile=myStoreFileLocation
    
  2. در فایل build.gradle، فایل keystore.properties را به‌صورت زیر بار کنید (این کار باید قبل‌از بلوک android انجام شود):

    شیک

    // 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 {
      ...
    }
    ...

    کاتلین

    // 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 {
      ...
    }
    ...
  3. اطلاعات امضا ذخیره‌شده در شیء keystoreProperties را وارد کنید:

    شیک

    android {
      signingConfigs {
        config {
          keyAlias keystoreProperties['keyAlias']
          keyPassword keystoreProperties['keyPassword']
          storeFile file(keystoreProperties['storeFile'])
          storePassword keystoreProperties['storePassword']
        }
      }
      ...
    }
    ...

    کاتلین

    android {
      signingConfigs {
        config {
          keyAlias keystoreProperties['keyAlias']
          keyPassword keystoreProperties['keyPassword']
          storeFile file(keystoreProperties['storeFile'])
          storePassword keystoreProperties['storePassword']
        }
      }
      ...
    }
    ...
  4. روی اکنون همگام‌سازی شود در نوار اعلان کلیک کنید.

برای کسب اطلاعات بیشتر درباره امضای برنامه، امضای برنامه را بخوانید.

ساده‌سازی توسعه برنامه

نکات زیر به آسان‌تر شدن توسعه برنامه Android شما کمک می‌کند.

هم‌رسانی فیلدهای سفارشی و مقادیر منبع با کد برنامه‌تان

در زمان ساخت، Gradle کلاس BuildConfig را تولید می‌کند تا کد برنامه شما بتواند اطلاعات مربوط به ساخت فعلی را بررسی کند. همچنین می‌توانید فیلدهای سفارشی را بااستفاده از روش buildConfigField() به کلاس BuildConfig از فایل پیکربندی Gradle build اضافه کنید و به آن مقادیر در کد زمان اجرای برنامه‌تان دسترسی پیدا کنید. به‌همین ترتیب، می‌توانید مقادیر منبع برنامه را با resValue() اضافه کنید.

شیک

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")
    }
  }
}
...

کاتلین

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")
    }
  }
}
...

در کد برنامه‌تان، می‌توانید به‌صورت زیر به ویژگی‌ها دسترسی داشته باشید:

کاتلین

...
Log.i(TAG, BuildConfig.BUILD_TIME)
Log.i(TAG, getString(R.string.build_time))

جاوا

...
Log.i(TAG, BuildConfig.BUILD_TIME);
Log.i(TAG, getString(R.string.build_time));

هم‌رسانی کردن ویژگی‌ها با مانیفست

در برخی موارد، ممکن است لازم باشد دارایی یکسانی را هم در مانیفست و هم در کدتان اعلام کنید (برای مثال، هنگام اعلام مراجع برای FileProvider). به‌جای به‌روزرسانی دارایی یکسان در چند مکان برای اعمال تغییر، دارایی واحدی را در فایل build.gradle واحدی تعریف کنید تا هم برای مانیفست و هم برای کدتان دردسترس باشد، همان‌طور که در نمونه زیر نشان داده شده است. برای کسب اطلاعات بیشتر، تزریق متغیرهای ساخت به مانیفست را بخوانید.

شیک

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}\"")
  }
  ...
}
...

کاتلین

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}\"")
  }
  ...
}
...

در مانیفست، به‌صورت زیر به جای‌بان دسترسی پیدا کنید:

<manifest>
  ...
  <application>
    ...
    <provider
      android:name="android.support.v4.content.FileProvider"
      android:authorities="${filesAuthority}"
      android:exported="false"
      android:grantUriPermissions="true">
      ...
    </provider>
  </application>
</manifest>

دسترسی به فیلد FILES_AUTHORITY در کد برنامه‌تان چیزی شبیه به این است:

کاتلین

...
val contentUri: Uri = FileProvider.getUriForFile(context, BuildConfig.FILES_AUTHORITY, myFile)

جاوا

...
Uri contentUri = FileProvider.getUriForFile(getContext(),
  BuildConfig.FILES_AUTHORITY,
  myFile);