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

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

اگر تازه وارد Gradle هستید، با خواندن Configure Your Build اصول اولیه را بیاموزید. همچنین می توانید اسناد مرجع DSL افزونه اندروید را بررسی کنید تا در مورد ویژگی های استفاده شده در این صفحه اطلاعات بیشتری کسب کنید.

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

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

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

می‌توانید از بلوک 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.5.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.5.1")
}

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

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

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

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

می توانید این کار را با منطق ساخت سفارشی انجام دهید که در زمان ساخت، کد نسخه متفاوتی را به هر 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))
            }
        }
    }
}

چندین طعم محصول را با هم ترکیب کنید

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

نمونه کد زیر از ویژگی flavorDimensions برای ایجاد یک بعد طعم "mode" برای گروه بندی طعم های محصول "full" و "demo" و یک بعد طعم "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 را پیکربندی کنید

می‌توانید با استفاده از بلوک lintOptions در فایل build.gradle در سطح ماژول، گزینه‌های پرز خاصی را پیکربندی کنید. برای کسب اطلاعات بیشتر در مورد استفاده از lint برای پروژه اندرویدی خود، Improve Your Code with 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 سطح ماژول خود، این را به نوع ساخت دیگری تغییر دهید. به عنوان مثال، اگر می‌خواهید آزمایش‌های خود را بر اساس نوع ساخت «staging» خود اجرا کنید، فایل را همانطور که در قطعه زیر نشان داده شده است ویرایش کنید.

شیار

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 Studio از R8 استفاده می‌کند که فایل‌های قوانین ProGuard را مصرف می‌کند تا کد شما را کوچک کند . برای پروژه‌های جدید، Android Studio از یک فایل تنظیمات پیش‌فرض ( proguard-android.txt ) از tools/proguard/folder Android SDK استفاده می‌کند. برای کوچک کردن بیشتر کد، فایل 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 Studio یک راه ساده برای پیکربندی امضا برای ساخت‌های انتشار از UI ارائه می‌کند، می‌توانید به صورت دستی بلوک 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 را به صورت زیر بارگیری کنید (این باید قبل از بلوک اندروید باشد):

    شیار

    // 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. روی همگام‌سازی اکنون در نوار اعلان کلیک کنید.

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

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

نکات زیر به توسعه اپلیکیشن اندروید شما کمک می کند.

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

در زمان ساخت، Gradle کلاس BuildConfig را تولید می کند تا کد برنامه شما بتواند اطلاعات مربوط به ساخت فعلی را بررسی کند. همچنین می توانید با استفاده از روش buildConfigField() فیلدهای سفارشی را به کلاس BuildConfig از فایل پیکربندی ساخت Gradle خود اضافه کنید و به آن مقادیر در کد زمان اجرا برنامه خود دسترسی داشته باشید. به همین ترتیب، می توانید مقادیر منابع برنامه را با 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 ماژول خود تعریف کنید تا هم برای مانیفست و هم برای کد شما در دسترس باشد، همانطور که در نمونه زیر نشان داده شده است. برای کسب اطلاعات بیشتر، Inject Build Variables را در Manifest بخوانید.

شیار

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);