پیکربندی انواع ساخت

این صفحه به شما نشان می‌دهد که چگونه می‌توانید build variants را پیکربندی کنید تا نسخه‌های مختلفی از برنامه خود را از یک پروژه واحد ایجاد کنید و چگونه وابستگی‌ها و پیکربندی‌های امضای خود را به درستی مدیریت کنید.

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

Build variants نتیجه‌ی استفاده‌ی Gradle از مجموعه‌ای خاص از قوانین برای ترکیب تنظیمات، کد و منابع پیکربندی‌شده در build types و product flavors شما هستند. اگرچه شما build variants را مستقیماً پیکربندی نمی‌کنید، اما build types و product flavors که آنها را تشکیل می‌دهند، پیکربندی می‌کنید.

برای مثال، یک نسخه آزمایشی (دمو) از محصول ممکن است ویژگی‌ها و الزامات دستگاه خاصی مانند کد منبع سفارشی، منابع و حداقل سطوح API را مشخص کند، در حالی که نوع ساخت "اشکال‌زدایی" تنظیمات ساخت و بسته‌بندی متفاوتی مانند گزینه‌های اشکال‌زدایی و کلیدهای امضا را اعمال می‌کند. نوع ساختی که این دو را ترکیب می‌کند، نسخه "demoDebug" برنامه شما است و شامل ترکیبی از پیکربندی‌ها و منابع موجود در نسخه آزمایشی، نوع ساخت "اشکال‌زدایی" و مجموعه main/ منبع است.

پیکربندی انواع ساخت

شما می‌توانید انواع ساخت را درون بلوک android از فایل build.gradle.kts در سطح ماژول ایجاد و پیکربندی کنید. وقتی یک ماژول جدید ایجاد می‌کنید، اندروید استودیو به طور خودکار انواع ساخت اشکال‌زدایی و انتشار را ایجاد می‌کند. اگرچه نوع ساخت اشکال‌زدایی در فایل پیکربندی ساخت ظاهر نمی‌شود، اندروید استودیو آن را با debuggable true پیکربندی می‌کند. این به شما امکان می‌دهد برنامه را در دستگاه‌های اندروید امن اشکال‌زدایی کنید و امضای برنامه را با یک فروشگاه کلید اشکال‌زدایی عمومی پیکربندی کنید.

اگر می‌خواهید تنظیمات خاصی را اضافه یا تغییر دهید، می‌توانید نوع ساخت debug را به پیکربندی خود اضافه کنید. نمونه زیر یک applicationIdSuffix برای نوع ساخت debug مشخص می‌کند و یک نوع ساخت "staging" را پیکربندی می‌کند که با استفاده از تنظیمات نوع ساخت debug مقداردهی اولیه می‌شود:

کاتلین

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

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

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

گرووی

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

        debug {
            applicationIdSuffix ".debug"
            debuggable true
        }

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

توجه: وقتی در یک فایل پیکربندی ساخت تغییراتی ایجاد می‌کنید، اندروید استودیو از شما می‌خواهد که پروژه خود را با پیکربندی جدید همگام‌سازی کنید. برای همگام‌سازی پروژه خود، روی Sync Now در نوار اعلانی که هنگام ایجاد تغییر ظاهر می‌شود کلیک کنید یا روی Sync Project کلیک کنید. از نوار ابزار. اگر اندروید استودیو متوجه هرگونه خطایی در پیکربندی شما شود، پنجره پیام‌ها برای شرح مشکل ظاهر می‌شود.

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

پیکربندی طعم‌های محصول

ایجاد طعم‌دهنده‌های محصول مشابه ایجاد انواع ساخت است. طعم‌دهنده‌های محصول را به بلوک productFlavors در پیکربندی ساخت خود اضافه کنید و تنظیمات مورد نظر خود را در آن قرار دهید. طعم‌دهنده‌های محصول از همان ویژگی‌های defaultConfig پشتیبانی می‌کنند، زیرا defaultConfig در واقع به کلاس ProductFlavor تعلق دارد. این بدان معناست که می‌توانید پیکربندی پایه را برای همه طعم‌دهنده‌ها در بلوک defaultConfig ارائه دهید و هر طعم‌دهنده می‌تواند هر یک از این مقادیر پیش‌فرض، مانند applicationId تغییر دهد. برای کسب اطلاعات بیشتر در مورد شناسه برنامه، بخش Set the application ID را مطالعه کنید.

توجه: شما هنوز هم باید با استفاده از ویژگی package در فایل main/ manifest نام بسته را مشخص کنید. همچنین باید از آن نام بسته در کد منبع خود برای ارجاع به کلاس R یا برای حل هرگونه فعالیت نسبی یا ثبت سرویس استفاده کنید. این به شما امکان می‌دهد با استفاده applicationId به هر طعم محصول یک شناسه منحصر به فرد برای بسته‌بندی و توزیع بدون نیاز به تغییر کد منبع خود بدهید.

همه طعم‌ها باید به یک بُعد طعم نامگذاری شده تعلق داشته باشند، که گروهی از طعم‌های محصول است. شما باید همه طعم‌ها را به یک بُعد طعم اختصاص دهید؛ در غیر این صورت، با خطای ساخت زیر مواجه خواهید شد.

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

اگر یک ماژول مشخص فقط یک بُعد flavor را مشخص کند، افزونه‌ی Android Gradle به طور خودکار تمام flavor های ماژول را به آن بُعد اختصاص می‌دهد.

نمونه کد زیر یک بُعد flavor به نام "version" ایجاد می‌کند و flavorهای محصول "demo" و "full" را اضافه می‌کند. این flavorها applicationIdSuffix و versionNameSuffix مخصوص به خود را ارائه می‌دهند:

کاتلین

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

گرووی

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

توجه: اگر یک برنامه قدیمی (ایجاد شده قبل از آگوست 2021) دارید که با استفاده از APKها در Google Play توزیع می‌کنید، برای توزیع برنامه خود با استفاده از پشتیبانی چندین APK در Google Play، مقدار applicationId یکسانی را به همه انواع اختصاص دهید و به هر نوع یک versionCode متفاوت بدهید. برای توزیع انواع مختلف برنامه خود به عنوان برنامه‌های جداگانه در Google Play، باید یک applicationId متفاوت به هر نوع اختصاص دهید.

پس از ایجاد و پیکربندی طعم‌های محصول خود، روی Sync Now در نوار اعلان کلیک کنید. پس از اتمام همگام‌سازی، Gradle به طور خودکار انواع ساخت را بر اساس انواع ساخت و طعم‌های محصول شما ایجاد می‌کند و آنها را بر اساس <product-flavor><Build-Type> نامگذاری می‌کند. به عنوان مثال، اگر طعم‌های محصول "دمو" و "کامل" ایجاد کرده باشید و انواع ساخت پیش‌فرض "اشکال‌زدایی" و "انتشار" را حفظ کرده باشید، Gradle انواع ساخت زیر را ایجاد می‌کند:

  • demoDebug
  • demoRelease
  • fullDebug
  • fullRelease

برای انتخاب نوع ساخت و اجرا، به Build > Select Build Variant بروید و یک نوع ساخت را از منو انتخاب کنید. برای شروع سفارشی‌سازی هر نوع ساخت با ویژگی‌ها و منابع خاص خود، باید مجموعه‌های منبع را همانطور که در این صفحه توضیح داده شده است، ایجاد و مدیریت کنید .

شناسه برنامه را برای انواع ساخت تغییر دهید

وقتی برای برنامه خود یک APK یا AAB می‌سازید، ابزارهای ساخت، برنامه را با شناسه برنامه تعریف شده در بلوک defaultConfig از فایل build.gradle.kts ، همانطور که در مثال زیر نشان داده شده است، برچسب‌گذاری می‌کنند. با این حال، اگر می‌خواهید نسخه‌های مختلفی از برنامه خود ایجاد کنید تا به صورت فهرست‌های جداگانه در فروشگاه Google Play ظاهر شوند، مانند نسخه "رایگان" و "حرفه‌ای"، باید انواع ساخت جداگانه‌ای ایجاد کنید که هر کدام شناسه برنامه متفاوتی داشته باشند.

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

کاتلین

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

گرووی

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

به این ترتیب، شناسه برنامه برای محصول «رایگان» «com.example.myapp.free» است.

همچنین می‌توانید از applicationIdSuffix برای اضافه کردن یک بخش بر اساس نوع ساخت خود، همانطور که در اینجا نشان داده شده است، استفاده کنید:

کاتلین

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

گرووی

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

از آنجا که Gradle پیکربندی نوع ساخت را پس از product flavor اعمال می‌کند، شناسه برنامه برای نوع ساخت "free debug" برابر با "com.example.myapp.free.debug" است. این زمانی مفید است که می‌خواهید هم نسخه اشکال‌زدایی و هم نسخه نهایی را روی یک دستگاه داشته باشید، زیرا هیچ دو برنامه‌ای نمی‌توانند شناسه برنامه یکسانی داشته باشند.

اگر یک برنامه قدیمی (که قبل از آگوست 2021 ایجاد شده است) دارید که با استفاده از APKها در Google Play توزیع می‌کنید، و می‌خواهید از فهرست برنامه یکسان برای توزیع چندین APK که هر کدام پیکربندی دستگاه متفاوتی، مانند سطح API را هدف قرار می‌دهند، استفاده کنید، باید برای هر نوع ساخت از شناسه برنامه یکسان استفاده کنید اما به هر APK یک versionCode متفاوت بدهید. برای اطلاعات بیشتر، درباره پشتیبانی از چندین APK مطالعه کنید. انتشار با استفاده از AABها تحت تأثیر قرار نمی‌گیرد، زیرا از یک مصنوع واحد استفاده می‌کند که به طور پیش‌فرض از یک کد نسخه و شناسه برنامه واحد استفاده می‌کند.

نکته: اگر نیاز دارید که در فایل مانیفست خود به شناسه برنامه ارجاع دهید، می‌توانید از متغیر ${applicationId} در هر ویژگی مانیفست استفاده کنید. در طول ساخت، Gradle این تگ را با شناسه واقعی برنامه جایگزین می‌کند. برای اطلاعات بیشتر، به بخش تزریق متغیرهای ساخت به مانیفست مراجعه کنید.

ترکیب طعم‌های مختلف محصول با ابعاد طعمی

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

هنگام ساخت برنامه، Gradle پیکربندی product flavor را از هر flavor dimension که تعریف می‌کنید، به همراه پیکربندی build type ترکیب می‌کند تا نسخه نهایی build را ایجاد کند. Gradle طعم‌های محصولی را که متعلق به یک flavor dimension هستند، ترکیب نمی‌کند.

نمونه کد زیر از ویژگی flavorDimensions برای ایجاد یک بُعد طعم "mode" برای گروه‌بندی طعم‌های محصول "کامل" و "دمو" و یک بُعد طعم "api" برای گروه‌بندی پیکربندی‌های طعم محصول بر اساس سطح API استفاده می‌کند:

کاتلین

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

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

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

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

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

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

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

گرووی

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

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

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

    full {
      dimension "mode"
      ...
    }

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

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

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

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

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

با استفاده از پیکربندی ساخت قبلی به عنوان نمونه، Gradle در مجموع ۱۲ نوع ساخت با طرح نامگذاری زیر ایجاد می‌کند:

  • نوع ساخت: [minApi24, minApi23, minApi21][Demo, Full][Debug, Release]
  • APK مربوطه: app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
  • برای مثال،
    نوع ساخت: minApi24DemoDebug
    APK مربوطه: app-minApi24-demo-debug.apk

علاوه بر دایرکتوری‌های مجموعه منبع که می‌توانید برای هر طعم محصول و نوع ساخت جداگانه ایجاد کنید، می‌توانید دایرکتوری‌های مجموعه منبع را برای هر ترکیبی از طعم‌های محصول نیز ایجاد کنید. به عنوان مثال، می‌توانید منابع جاوا را ایجاد و به دایرکتوری src/demoMinApi24/java/ اضافه کنید و Gradle فقط هنگام ساخت نوعی که آن دو طعم محصول را ترکیب می‌کند، از آن منابع استفاده می‌کند.

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

انواع فیلتر

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

با استفاده از پیکربندی ساخت از بخش قبلی به عنوان مثال، فرض کنید قصد دارید فقط از سطوح API 23 و بالاتر برای نسخه آزمایشی برنامه پشتیبانی کنید. می‌توانید از بلوک variantFilter برای فیلتر کردن تمام پیکربندی‌های نوع ساخت که طعم‌های محصول "minApi21" و "demo" را ترکیب می‌کنند، استفاده کنید:

کاتلین

android {
  ...
  buildTypes {...}

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

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

گرووی

android {
  ...
  buildTypes {...}

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

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

وقتی یک فیلتر متغیر به پیکربندی ساخت خود اضافه می‌کنید و در نوار اعلان روی Sync Now کلیک می‌کنید، Gradle هر متغیر ساختی را که شرایط مشخص شده شما را برآورده کند، نادیده می‌گیرد. متغیرهای ساخت دیگر وقتی روی Build > Select Build Variant از نوار منو یا Build Variants کلیک می‌کنید، در منو ظاهر نمی‌شوند. در نوار پنجره ابزار.

ایجاد مجموعه‌های منبع

به طور پیش‌فرض، اندروید استودیو مجموعه و دایرکتوری‌های main/ source را برای هر چیزی که می‌خواهید بین تمام build variants خود به اشتراک بگذارید، ایجاد می‌کند. با این حال، می‌توانید مجموعه‌های منبع جدیدی ایجاد کنید تا دقیقاً کنترل کنید که Gradle کدام فایل‌ها را برای build types خاص، product flavors، ترکیبی از product flavors (هنگام استفاده از ابعاد flavor ) و build variants کامپایل و بسته‌بندی کند.

برای مثال، می‌توانید قابلیت‌های پایه را در مجموعه main/ source تعریف کنید و از مجموعه‌های منبع product flavor برای تغییر نام تجاری برنامه خود برای کلاینت‌های مختلف استفاده کنید، یا مجوزهای ویژه و قابلیت ثبت وقایع را فقط برای نسخه‌های ساختی که از نوع ساخت اشکال‌زدایی استفاده می‌کنند، لحاظ کنید.

Gradle انتظار دارد که فایل‌ها و دایرکتوری‌های مجموعه منبع به شیوه‌ای خاص، مشابه مجموعه main/ source، سازماندهی شوند. برای مثال، Gradle انتظار دارد فایل‌های کلاس Kotlin یا Java که مختص نوع ساخت "debug" شما هستند، در دایرکتوری‌های src/debug/kotlin/ یا src/debug/java/ قرار گیرند.

افزونه‌ی اندروید گریدل (Android Gradle) یک وظیفه‌ی مفید گریدل (Gradle task) ارائه می‌دهد که به شما نشان می‌دهد چگونه فایل‌های خود را برای هر یک از انواع ساخت (build types)، طعم‌های محصول (product flavors) و انواع ساخت (build variants) سازماندهی کنید. برای مثال، نمونه‌ی زیر از خروجی وظیفه، محل مورد انتظار گریدل برای یافتن فایل‌های خاص برای نوع ساخت "debug" را شرح می‌دهد:

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

...

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

برای مشاهده این خروجی، به صورت زیر عمل کنید:

  1. در نوار ابزار پنجره، روی Gradle کلیک کنید.
  2. به مسیر MyApplication > Tasks > android بروید و روی sourceSets دوبار کلیک کنید.

    برای مشاهده پوشه Tasks ، باید به Gradle اجازه دهید لیست وظایف را در حین همگام‌سازی بسازد. برای انجام این کار، این مراحل را دنبال کنید:

    1. روی فایل > تنظیمات > آزمایشی ( Android Studio > تنظیمات > آزمایشی در macOS) کلیک کنید.
    2. لغو انتخاب « در طول همگام‌سازی Gradle، فهرست وظایف Gradle ساخته نشود» .
  3. پس از اجرای وظیفه توسط Gradle، پنجره Run برای نمایش خروجی باز می‌شود.

نکته: خروجی این وظیفه همچنین به شما نشان می‌دهد که چگونه مجموعه‌های منبع فایل‌هایی را که می‌خواهید برای اجرای تست‌های برنامه خود استفاده کنید، مانند مجموعه‌های منبع test/ و androidTest/ testing، سازماندهی کنید.

وقتی یک build variant جدید ایجاد می‌کنید، اندروید استودیو دایرکتوری‌های مجموعه منبع را برای شما ایجاد نمی‌کند، اما چند گزینه برای کمک به شما ارائه می‌دهد. به عنوان مثال، برای ایجاد فقط دایرکتوری java/ برای نوع build "debug" خود:

  1. پنجره پروژه را باز کنید و از منوی بالای پنجره، نمای پروژه را انتخاب کنید.
  2. به مسیر MyProject/app/src/ بروید.
  3. روی پوشه src کلیک راست کرده و New > Directory را انتخاب کنید.
  4. از منوی زیر Gradle Source Sets ، گزینه full/java را انتخاب کنید.
  5. اینتر را فشار دهید.

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

برای مثال، برای ایجاد یک فایل XML مقادیر برای نوع ساخت "debug" خود:

  1. در پنل پروژه ، روی پوشه src کلیک راست کرده و New > XML > Values ​​XML File را انتخاب کنید.
  2. نام فایل XML را وارد کنید یا نام پیش‌فرض را نگه دارید.
  3. از منوی کنار «تنظیم منبع هدف» ، «اشکال‌زدایی» را انتخاب کنید.
  4. روی پایان کلیک کنید.

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

شکل ۱. دایرکتوری‌های جدید مجموعه منابع برای نوع ساخت "debug".

مجموعه‌های منبع فعال یک نشانگر سبز در آیکون خود دارند که نشان می‌دهد فعال هستند. مجموعه منبع debug با پسوند [main] نشان داده می‌شود تا نشان دهد که با مجموعه منبع main ادغام خواهد شد.

با استفاده از همین رویه، می‌توانید دایرکتوری‌های مجموعه منبع را برای طعم‌های محصول، مانند src/demo/ ، و انواع ساخت، مانند src/demoDebug/ ایجاد کنید. علاوه بر این، می‌توانید مجموعه‌های منبع آزمایشی ایجاد کنید که انواع ساخت خاصی را هدف قرار می‌دهند، مانند src/androidTestDemoDebug/ . برای کسب اطلاعات بیشتر، درباره مجموعه‌های منبع آزمایشی مطالعه کنید.

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

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

بلوک sourceSets باید در بلوک android باشد. نیازی به جابجایی فایل‌های منبع نیست؛ فقط باید مسیر(های) مربوط به فایل build.gradle.kts در سطح ماژول را به Gradle ارائه دهید، جایی که Gradle می‌تواند فایل‌های مربوط به هر کامپوننت مجموعه منبع را پیدا کند. برای اطلاع از اینکه کدام کامپوننت‌ها را می‌توانید پیکربندی کنید و اینکه آیا می‌توانید آنها را به چندین فایل یا دایرکتوری نگاشت کنید، به مرجع API افزونه Android Gradle مراجعه کنید.

نمونه کد زیر، منابع را از دایرکتوری app/other/ به اجزای خاصی از مجموعه منابع main نگاشت می‌کند و دایرکتوری ریشه مجموعه منابع androidTest را تغییر می‌دهد:

کاتلین

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

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

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

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

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

گرووی

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

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

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

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

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

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

توجه داشته باشید که یک دایرکتوری منبع فقط می‌تواند به یک مجموعه منبع تعلق داشته باشد. برای مثال، شما نمی‌توانید منابع تست یکسانی را با هر دو مجموعه منبع test و androidTest به اشتراک بگذارید. دلیل این امر این است که اندروید استودیو برای هر مجموعه منبع، ماژول‌های IntelliJ جداگانه‌ای ایجاد می‌کند و نمی‌تواند از ریشه‌های محتوای تکراری در مجموعه‌های منبع پشتیبانی کند.

ساخت با مجموعه‌های منبع

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

  1. src/demoDebug/ (مجموعه سورس ساخت نسخه)
  2. src/debug/ (مجموعه منبع نوع ساخت)
  3. src/demo/ (مجموعه منبع طعم محصول)
  4. src/main/ (مجموعه منبع اصلی)

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

اگر چندین طعم محصول را با هم ترکیب کنید ، اولویت بین طعم‌های محصول توسط بُعد طعمی که به آن تعلق دارند تعیین می‌شود. هنگام فهرست کردن ابعاد طعم با ویژگی android.flavorDimensions ، طعم‌های محصولی که به بُعد طعم اول فهرست شده تعلق دارند، اولویت بالاتری نسبت به طعم‌های متعلق به بُعد طعم دوم دارند و به همین ترتیب ادامه می‌یابد. علاوه بر این، مجموعه‌های منبعی که برای ترکیب طعم‌های محصول ایجاد می‌کنید، اولویت بالاتری نسبت به مجموعه‌های منبعی دارند که به یک طعم محصول منحصر به فرد تعلق دارند.

ترتیب اولویت تعیین می‌کند که کدام مجموعه منبع هنگام ترکیب کد و منابع توسط Gradle اولویت بالاتری دارد. از آنجا که دایرکتوری مجموعه demoDebug/ source احتمالاً حاوی فایل‌هایی است که مختص آن نوع ساخت هستند، اگر demoDebug/ شامل فایلی باشد که در debug/ نیز تعریف شده باشد، Gradle از فایل موجود در مجموعه demoDebug/ source استفاده می‌کند. به طور مشابه، Gradle به فایل‌های موجود در مجموعه build type و product flavor source اولویت بالاتری نسبت به همان فایل‌ها در main/ می‌دهد. Gradle این ترتیب اولویت را هنگام اعمال قوانین ساخت زیر در نظر می‌گیرد:

  • تمام کد منبع موجود در دایرکتوری‌های kotlin/ یا java/ با هم کامپایل می‌شوند تا یک خروجی واحد تولید کنند.

    توجه: برای یک نوع ساخت مشخص، Gradle در صورت مواجهه با دو یا چند دایرکتوری مجموعه منبع که کلاس Kotlin یا Java یکسانی را تعریف کرده‌اند، خطای ساخت می‌دهد. برای مثال، هنگام ساخت یک برنامه اشکال‌زدایی، نمی‌توانید هم src/debug/Utility.kt و هم src/main/Utility.kt را تعریف کنید، زیرا Gradle در طول فرآیند ساخت به هر دوی این دایرکتوری‌ها نگاه می‌کند و خطای "کلاس تکراری" را ایجاد می‌کند. اگر نسخه‌های مختلفی از Utility.kt را برای انواع ساخت مختلف می‌خواهید، هر نوع ساخت باید نسخه فایل خود را تعریف کند و آن را در مجموعه main/ source قرار ندهد.

  • مانیفست‌ها با هم در یک مانیفست واحد ادغام می‌شوند. اولویت به همان ترتیب لیست در مثال قبلی داده می‌شود. یعنی تنظیمات مانیفست برای یک نوع ساخت، تنظیمات مانیفست برای یک طعم محصول را لغو می‌کند و به همین ترتیب ادامه می‌یابد. برای کسب اطلاعات بیشتر، درباره ادغام مانیفست مطالعه کنید.
  • فایل‌های موجود در دایرکتوری‌های values/ با هم ادغام می‌شوند. اگر دو فایل نام یکسانی داشته باشند، مانند دو فایل strings.xml ، اولویت به همان ترتیب لیست در مثال قبلی داده می‌شود. یعنی مقادیر تعریف شده در یک فایل در مجموعه منبع نوع ساخت، مقادیر تعریف شده در همان فایل در یک product flavor را لغو می‌کنند و به همین ترتیب ادامه می‌یابد.
  • منابع موجود در دایرکتوری‌های res/ و asset/ با هم بسته‌بندی می‌شوند. اگر منابعی با نام یکسان در دو یا چند مجموعه منبع تعریف شده باشند، اولویت به همان ترتیب لیست در مثال قبلی داده می‌شود.
  • گریدل هنگام ساخت برنامه، منابع و مانیفست‌های همراه با وابستگی‌های ماژول کتابخانه را در پایین‌ترین اولویت قرار می‌دهد.

اعلان وابستگی‌ها

برای پیکربندی یک وابستگی برای یک نوع ساخت خاص یا مجموعه منبع آزمایشی ، نام نوع ساخت یا مجموعه منبع آزمایشی را قبل از کلمه کلیدی Implementation پیشوند کنید، همانطور که در مثال زیر نشان داده شده است:

کاتلین

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

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

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

گرووی

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

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

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

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

از مدیریت وابستگی آگاه از نوع داده استفاده کنید

افزونه‌ی اندروید Gradle نسخه ۳.۰.۰ و بالاتر شامل یک مکانیزم وابستگی جدید است که هنگام استفاده از یک کتابخانه، به طور خودکار با متغیرها مطابقت پیدا می‌کند. این بدان معناست که متغیر debug یک برنامه به طور خودکار متغیر debug یک کتابخانه را مصرف می‌کند و به همین ترتیب ادامه می‌یابد. همچنین هنگام استفاده از flavorها نیز کار می‌کند: متغیر freeDebug یک برنامه، متغیر freeDebug یک کتابخانه را مصرف خواهد کرد.

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

برای مثال، فرض کنید برنامه شما یک نوع ساخت به نام "staging" را پیکربندی کرده است، اما یکی از وابستگی‌های کتابخانه آن این قابلیت را ندارد. وقتی افزونه سعی می‌کند نسخه "staging" برنامه شما را بسازد، نمی‌داند از کدام نسخه کتابخانه استفاده کند و پیام خطایی مشابه زیر مشاهده خواهید کرد:

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

خطاهای ساخت مربوط به تطبیق متغیرها را برطرف کنید

این افزونه شامل عناصر DSL است که به شما کمک می‌کند نحوه‌ی حل موقعیت‌هایی که تطابق مستقیم بین یک برنامه و یک وابستگی امکان‌پذیر نیست را توسط Gradle کنترل کنید.

در ادامه فهرستی از مسائل مربوط به تطبیق وابستگی آگاه از نوع داده و نحوه حل آنها با استفاده از ویژگی‌های DSL آمده است:

  • برنامه شما شامل یک نوع ساخت است که وابستگی کتابخانه‌ای آن را ندارد.

    برای مثال، برنامه شما شامل یک نوع ساخت «مرحله‌بندی» است، اما یک وابستگی فقط شامل انواع ساخت «اشکال‌زدایی» و «انتشار» است.

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

    از matchingFallbacks برای مشخص کردن تطابق‌های جایگزین برای یک نوع ساخت مشخص، همانطور که در اینجا نشان داده شده است، استفاده کنید:

    کاتلین

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

    گرووی

    // In the app's build.gradle file.
    android {
        buildTypes {
            debug {}
            release {}
            staging {
                // Specifies a sorted list of fallback build types that the
                // plugin can try to use when a dependency does not include a
                // "staging" build type. You may specify as many fallbacks as you
                // like, and the plugin selects the first build type that's
                // available in the dependency.
                matchingFallbacks = ['debug', 'qa', 'release']
            }
        }
    }
  • برای یک بُعد طعم (very dimension) مشخص که هم در برنامه و هم در وابستگی کتابخانه آن وجود دارد، برنامه شما شامل طعم‌هایی است که کتابخانه ندارد.

    برای مثال، هم برنامه شما و هم وابستگی‌های کتابخانه آن شامل یک بُعد طعم "tier" هستند. با این حال، بُعد "tier" در برنامه شامل طعم‌های "رایگان" و "پولی" است، اما یک وابستگی فقط شامل طعم‌های "دمو" و "پولی" برای همان بُعد است.

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

    از matchingFallbacks برای تعیین تطابق‌های جایگزین برای محصول «رایگان» برنامه استفاده کنید، همانطور که در اینجا نشان داده شده است:

    کاتلین

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

    گرووی

    // In the app's build.gradle file.
    android {
        defaultConfig{
        // Don't configure matchingFallbacks in the defaultConfig block.
        // Instead, specify fallbacks for a given product flavor in the
        // productFlavors block, as shown below.
      }
        flavorDimensions 'tier'
        productFlavors {
            paid {
                dimension 'tier'
                // Because the dependency already includes a "paid" flavor in its
                // "tier" dimension, you don't need to provide a list of fallbacks
                // for the "paid" flavor.
            }
            free {
                dimension 'tier'
                // Specifies a sorted list of fallback flavors that the plugin
                // can try to use when a dependency's matching dimension does
                // not include a "free" flavor. Specify as many
                // fallbacks as you like; the plugin selects the first flavor
                // that's available in the dependency's "tier" dimension.
                matchingFallbacks = ['demo', 'trial']
            }
        }
    }
  • یک وابستگی کتابخانه‌ای شامل بُعد طعمی است که برنامه شما ندارد.

    برای مثال، یک وابستگی کتابخانه‌ای شامل flavorهایی برای بُعد "minApi" است، اما برنامه شما flavorهایی را فقط برای بُعد "tier" در نظر می‌گیرد. وقتی می‌خواهید نسخه "freeDebug" برنامه خود را بسازید، افزونه نمی‌داند که آیا از نسخه "minApi23Debug" یا "minApi18Debug" وابستگی استفاده کند.

    توجه داشته باشید که وقتی برنامه شما شامل بُعدی از نوع flavor است که وابستگی کتابخانه آن را ندارد، مشکلی وجود ندارد. دلیلش این است که افزونه فقط با ابعادی که در وابستگی وجود دارند، مطابقت دارد. برای مثال، اگر یک وابستگی شامل بُعدی برای ABIها نباشد، نسخه "freeX86Debug" برنامه شما از نسخه "freeDebug" وابستگی استفاده خواهد کرد.

    همانطور که در نمونه زیر نشان داده شده است، از missingDimensionStrategy در بلوک defaultConfig برای تعیین طعم پیش‌فرض افزونه برای انتخاب از هر بُعد گمشده استفاده کنید. همچنین می‌توانید انتخاب‌های خود را در بلوک productFlavors لغو کنید، بنابراین هر طعم می‌تواند یک استراتژی تطبیق متفاوت برای یک بُعد گمشده تعیین کند.

    کاتلین

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

    گرووی

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

برای اطلاعات بیشتر، به matchingFallbacks و missingDimensionStrategy در مرجع DSL افزونه Gradle اندروید مراجعه کنید.

تنظیمات امضا را پیکربندی کنید

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

برای پیکربندی دستی تنظیمات امضا برای نوع ساخت نسخه خود با استفاده از تنظیمات ساخت Gradle:

  1. یک کلید عمومی ایجاد کنید. کلید عمومی یک فایل باینری است که شامل مجموعه‌ای از کلیدهای خصوصی است. شما باید کلید عمومی خود را در مکانی امن و مطمئن نگهداری کنید.
  2. یک کلید خصوصی ایجاد کنید. یک کلید خصوصی برای امضای برنامه شما برای توزیع استفاده می‌شود و هرگز همراه برنامه ارائه نمی‌شود و برای اشخاص ثالث غیرمجاز افشا نمی‌شود.
  3. پیکربندی امضا را به فایل build.gradle.kts در سطح ماژول اضافه کنید:

    کاتلین

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

    گرووی

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

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

برای دریافت این رمزهای عبور از متغیرهای محیطی:

کاتلین

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

گرووی

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

به عنوان یک روش جایگزین، می‌توانید keystore را از یک فایل properties محلی بارگذاری کنید. به دلایل امنیتی، این فایل را به source control اضافه نکنید. در عوض، آن را به صورت محلی برای هر توسعه‌دهنده تنظیم کنید. برای کسب اطلاعات بیشتر، حذف اطلاعات امضا از فایل‌های build خود را مطالعه کنید.

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

هشدار: کلید اصلی و کلید خصوصی خود را در مکانی امن و مطمئن نگه دارید و از پشتیبان‌گیری ایمن از آنها اطمینان حاصل کنید. اگر از امضای برنامه Play استفاده می‌کنید و کلید آپلود خود را گم می‌کنید، می‌توانید با استفاده از کنسول Play درخواست تنظیم مجدد کنید . اگر برنامه‌ای را بدون امضای برنامه Play منتشر می‌کنید (برای برنامه‌هایی که قبل از آگوست 2021 ایجاد شده‌اند) و کلید امضای برنامه خود را گم می‌کنید، نمی‌توانید هیچ به‌روزرسانی برای برنامه خود منتشر کنید، زیرا همیشه باید تمام نسخه‌های برنامه خود را با همان کلید امضا کنید.

امضای برنامه‌های Wear OS

هنگام انتشار برنامه‌های Wear OS، هم APK ساعت و هم APK اختیاری تلفن باید با یک کلید امضا شوند. برای اطلاعات بیشتر در مورد بسته‌بندی و امضای برنامه‌های Wear OS، به بخش بسته‌بندی و توزیع برنامه‌های Wear مراجعه کنید.