ضبط صيغ الإصدار

توضّح لك هذه الصفحة كيفية ضبط صيغ الإصدار لإنشاء إصدارات مختلفة من تطبيقك من مشروع واحد وكيفية إدارة التبعيات وإعدادات التوقيع بشكل صحيح.

يمثّل كل صيغة إصدار إصدارًا مختلفًا من تطبيقك يمكنك إنشاؤه. على سبيل المثال، قد تريد إنشاء إصدار واحد من تطبيقك يكون مجانيًا ويتضمّن مجموعة محدودة من المحتوى، وإصدار آخر مدفوع يتضمّن المزيد من المحتوى. يمكنك أيضًا إنشاء إصدارات مختلفة من تطبيقك تستهدف أجهزة مختلفة، استنادًا إلى مستوى واجهة برمجة التطبيقات أو أنواع الأجهزة الأخرى.

تكون أنواع الإصدارات نتيجة استخدام Gradle لمجموعة معيّنة من القواعد لدمج الإعدادات والرموز البرمجية والموارد التي تم ضبطها في أنواع الإصدارات وأنواع المنتجات. على الرغم من أنّك لا تضبط خيارات الإصدار مباشرةً، يمكنك ضبط أنواع الإصدارات وأنواع المنتجات التي تشكلها.

على سبيل المثال، قد يحدِّد نوع المنتج "إصدار تجريبي" ميزات معيّنة ومتطلبات الجهاز، مثل رمز المصدر المخصّص والموارد والحد الأدنى لمستويات واجهة برمجة التطبيقات، في حين يطبِّق نوع الإصدار "تصحيح الأخطاء" إعدادات مختلفة للإصدار والتعبئة، مثل خيارات تصحيح الأخطاء ومفاتيح التوقيع. إنّ خيار الإصدار الذي يجمع هذين الخيارَين هو إصدار "demoDebug" من تطبيقك، ويتضمّن مجموعة من الإعدادات والموارد المضمّنة في خيار main/ لإصدار المنتج ونوع الإصدار "debug" ومجموعة مصادر main/.

ضبط أنواع الإصدار

يمكنك إنشاء أنواع الإنشاء وضبطها داخل كتلة android في ملف build.gradle.kts على مستوى الوحدة. عند إنشاء وحدة جديدة، ينشئ "استوديو Android" تلقائيًا نوعَي الإصدار المخصّص لتصحيح الأخطاء والإصدار العلني. على الرغم من أنّ نوع إصدار تصحيح الأخطاء لا يظهر في ملف إعدادات الإصدار ، يضبطه "استوديو Android" باستخدام debuggable true. يتيح لك ذلك تصحيح أخطاء التطبيق على أجهزة Android الآمنة ويؤدي إلى ضبط ميزة "توقيع التطبيق" باستخدام متجر مفاتيح عام لتصحيح الأخطاء.

يمكنك إضافة نوع الإصدار المخصّص لتصحيح الأخطاء إلى الإعدادات إذا كنت تريد إضافة أو تغيير إعدادات معيّنة. يحدِّد النموذج التالي applicationIdSuffix لنوع الإصدار المخصّص لتصحيح الأخطاء ويضبط نوع إصدار "الإصدار التجريبي" الذي يتم إعداده باستخدام الإعدادات من نوع الإصدار المخصّص لتصحيح الأخطاء:

Kotlin

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

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

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

رائع

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

        debug {
            applicationIdSuffix ".debug"
            debuggable true
        }

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

ملاحظة: عند إجراء تغييرات على ملف إعدادات الإصدار، يطلب منك Android Studio مزامنة مشروعك مع الإعدادات الجديدة. لمزامنة مشروعك، انقر على المزامنة الآن في شريط الإشعارات الذي يظهر عند إجراء تغيير أو انقر على مزامنة المشروع من شريط الأدوات. إذا رصد تطبيق Android Studio أي أخطاء في الإعدادات، ستظهر نافذة الرسائل لوصف المشكلة.

لمعرفة المزيد من المعلومات عن جميع السمات التي يمكنك ضبطها باستخدام أنواع الإصدارات، اطّلِع على مرجع BuildType.

ضبط أنواع المنتجات

يشبه إنشاء أنواع المنتجات إنشاء أنواع الإصدارات. أضِف أنواع المنتجات إلى العنصر productFlavors في إعدادات الإصدار وأدرِج الإعدادات التي تريدها. تتيح أنواع المنتجات استخدام السمات نفسها التي يستخدمها defaultConfig، لأنّ defaultConfig ينتمي في الواقع إلى فئة ProductFlavor. وهذا يعني أنّه يمكنك تقديم الإعدادات الأساسية لجميع النُسخ في العنصر defaultConfig، ويمكن لكل نسخة تغيير أيّ من هذه القيم التلقائية، مثل applicationId. للحصول على مزيد من المعلومات عن رقم تعريف التطبيق، يُرجى الاطّلاع على مقالة ضبط رقم تعريف التطبيق.

ملاحظة: لا يزال عليك تحديد اسم حزمة باستخدام سمة package في ملف بيان main/. يجب أيضًا استخدام اسم الحزمة هذا في رمز المصدر للإشارة إلى فئة R أو لحلّ أي تسجيل لنشاط أو خدمة ذات صلة. يتيح لك ذلك استخدام applicationId لمنح كلّ نكهة من نكهات المنتج معرّفًا فريدًا لتعبئتها وتوزيعها بدون الحاجة إلى تغيير رمز المصدر.

يجب أن تنتمي جميع النكهات إلى سمة نكهة مُسمّاة، وهي مجموعة من نكهات المنتجات. يجب تخصيص جميع النكهات لسمة نكهة، وإلا سيظهر لك خطأ الإنشاء التالي.

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

إذا كانت وحدة معيّنة تحديد سمة نكهة واحدة فقط، سيحدّد المكوّن الإضافي لـ Android Gradle تلقائيًا جميع نكهات الوحدة لهذه السمة.

ينشئ نموذج الرمز البرمجي التالي سمة إصدار باسم "الإصدار" ويضيف إصدارَي المنتج "تجريبي" و "كامل". تقدّم هذه النكهات applicationIdSuffix و versionNameSuffix الخاصة بها:

Kotlin

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

رائع

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

ملاحظة: إذا كان لديك تطبيق قديم (تم إنشاؤه قبل آب/أغسطس 2021) توزّعه باستخدام حِزم APK على Google Play، يمكنك توزيع تطبيقك باستخدام ميزة دعم حِزم APK المتعدّدة في Google Play من خلال ضبط القيمة applicationId نفسها على جميع الصيغ ومنح كل صيغة قيمة مختلفة versionCode. لتوزيع خيارات مختلفة من تطبيقك كتطبيقات منفصلة في Google Play، عليك منح كل خيار قيمة مختلفة من applicationId.

بعد إنشاء أنواع المنتجات وضبطها، انقر على مزامنة الآن في شريط الإشعارات. بعد اكتمال المزامنة، تنشئ Gradle تلقائيًا أنواع الإصدارات استنادًا إلى أنواع الإصدارات وأنواع المنتجات، وتسميها وفقًا لملف <product-flavor><Build-Type>. على سبيل المثال، إذا أنشأت نكهات المنتج "إصدار تجريبي" و "إصدار كامل"، واحتفظت بأنواع الإصدارات الافتراضية "تصحيح أخطاء" و "إصدار"، تنشئ Gradle الصيغ التالية للإصدار:

  • demoDebug
  • demoRelease
  • fullDebug
  • fullRelease

لاختيار نوع الإصدار الذي تريد إنشاؤه و تشغيله، انتقِل إلى إنشاء > اختيار نوع الإصدار وحدد نوع إصدار من القائمة. لبدء تخصيص كلّ خيار من خيارات الإصدار باستخدام الميزات ومقاييس الأداء الخاصة به، عليك إنشاء مجموعات ومقاييس الأداء للمصدر وإدارتها، كما هو موضّح في هذه الصفحة.

تغيير رقم تعريف التطبيق لأنواع الإصدارات

عند إنشاء حزمة APK أو حزمة AAB لتطبيقك، تضع أدوات الإنشاء علامة على التطبيق باستخدام رقم تعريف التطبيق المحدَّد في القسم defaultConfig من ملفbuild.gradle.kts ، كما هو موضّح في المثال التالي. ومع ذلك، إذا كنت تريد إنشاء إصدارات مختلفة من تطبيقك لتظهر كبيانات منفصلة في "متجر Google Play"، مثل إصدار "مجاني" وإصدار "مدفوع"، عليك إنشاء صيغ إصدار منفصلة لكل منها معرّف تطبيق مختلف.

في هذه الحالة، حدِّد كل خيار من خيارات الإصدار على أنّه نكهة منتج منفصلة. بالنسبة إلى كل إصدار، داخل العنصر productFlavors، يمكنك إعادة تعريف سمةapplicationId ، أو يمكنك بدلاً من ذلك إلحاق قسم بمعرّف التطبيق التلقائي باستخدام applicationIdSuffix، كما هو موضّح هنا:

Kotlin

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

رائع

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

بهذه الطريقة، يكون معرّف التطبيق لإصدار المنتج "المجاني" هو "com.example.myapp.free".

يمكنك أيضًا استخدام applicationIdSuffix لإلحاق شريحة استنادًا إلى نوع الإصدار، كما هو موضّح هنا:

Kotlin

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

رائع

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

بما أنّ Gradle يطبّق إعدادات نوع الإصدار بعد خيار المنتج، يكون معرّف التطبيق لخيار الإصدار "التصحيح المجاني للأخطاء" هو "com.example.myapp.free.debug". يكون هذا مفيدًا عندما تريد تثبيت كل من ملف debugging وملف الإصدار على الجهاز نفسه، لأنّه لا يمكن أن يتضمّن تطبيقان رقم تعريف التطبيق نفسه.

إذا كان لديك تطبيق قديم (تم إنشاؤه قبل آب (أغسطس) 2021) توزّعه باستخدام حِزم APK على Google Play، وأردت استخدام بطاقة بيانات التطبيق نفسها لتوزيع حِزم APK متعددة تستهدف كلّ منها إعدادات جهاز مختلفة، مثل مستوى واجهة برمجة التطبيقات، يجب استخدام رقم تعريف التطبيق نفسه لكلّ إصدار من إصدارات التطبيق، ولكن يجب منح كل حزمة APK قيمة مختلفة من versionCode. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة إتاحة حِزم APK متعددة. لا يتأثر النشر باستخدام حِزم APK القابلة للنشر، لأنّها تستخدِم عنصرًا واحدًا يستخدِم تلقائيًا رمز إصدار واحدًا ومعرّف تطبيق واحدًا.

ملاحظة: إذا كنت بحاجة إلى الإشارة إلى رقم تعريف التطبيق فيملف البيان، يمكنك استخدام العنصر النائب ${applicationId} في أي سمة بيان. أثناء عملية الإنشاء، يستبدل Gradle هذه العلامة بمعرّف التطبيق الحقيقي. لمزيد من المعلومات، يُرجى الاطّلاع على مقالة إدراج متغيّرات ملف الالتجميع في البيان.

دمج نكهات منتجات متعددة مع سمات النكهة

في بعض الحالات، قد تحتاج إلى دمج الإعدادات من مجموعات منتجات متعددة. على سبيل المثال، قد تحتاج إلى إنشاء إعدادات مختلفة لإصدارَي المنتج "الكامل" و "الإصدار التجريبي" استنادًا إلى مستوى واجهة برمجة التطبيقات. لإجراء ذلك، يتيح لك المكوّن الإضافي لـ Gradle في Android إنشاء مجموعات متعدّدة من أنواع المنتجات كسمات للأنواع.

عند إنشاء تطبيقك، يجمع Gradle إعدادات نكهة المنتج من كل سمة نكهة تحدّدها، بالإضافة إلى إعدادات نوع الإصدار، لإنشاء خيار الإصدار النهائي. لا تدمج Gradle نكهات المنتجات التي تنتمي إلى سمة النكهة نفسها.

يستخدم نموذج الرمز البرمجي التالي السمة flavorDimensions لإنشاء سمة ملفّ أذونات "وضع" لتجميع ملفّات أذونات المنتج "كامل" و "إصدار تجريبي" وسمة ملفّ أذونات "واجهة برمجة التطبيقات" لتجميع إعدادات ملفّ أذونات المنتج استنادًا إلى مستوى واجهة برمجة التطبيقات:

Kotlin

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

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

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

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

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

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

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

رائع

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

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

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

    full {
      dimension "mode"
      ...
    }

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

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

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

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

إنّ عدد صيغ الإصدار التي ينشئها Gradle يساوي حاصل ضرب عدد النُسخ في كل سمة نسخة وعدد أنواع الإصدارات التي تضبطها. عندما يُحدِّد Gradle اسمًا لكلّ صيغة إصدار أو عناصر مقابلة، تظهر أولاً smaks المنتج التي تنتمي إلى سمة النكهة ذات الأولوية الأعلى، ثم يليها تلك التي تنتمي إلى السمات ذات الأولوية الأقل، ثم يليها نوع الإصدار.

باستخدام إعدادات الإصدار السابقة كمثال، ينشئ Gradle إجمالي 12 خيارًا للإصدار باستخدام مخطّط التسمية التالي:

  • نوع التصميم: [minApi24, minApi23, minApi21][Demo, Full][Debug, Release]
  • حزمة APK المقابلة: app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
  • على سبيل المثال:
    نوع الإصدار: minApi24DemoDebug
    حزمة APK المقابلة: app-minApi24-demo-debug.apk

بالإضافة إلى أدلة مجموعة المصادر التي يمكنك إنشاؤها لكل ملف شخصي خاص بالإصدار ونوع الإصدار، يمكنك أيضًا إنشاء أدلة مجموعة مصادر لكل مجموعة من الملفات الشخصية للإصدار. على سبيل المثال، يمكنك إنشاء وإضافة مصادر Java إلى الدليل src/demoMinApi24/java/، ولا يستخدم Gradle هذه المصادر إلا عند إنشاء إصدار يجمع بين هذين الصيغتَين للمنتج.

إنّ مجموعات المصادر التي تنشئها لتركيبات ملفّات تعريف المنتج لها أولوية أعلى من مجموعات المصادر التي تنتمي إلى كل ملف تعريف منتج individual. لمزيد من المعلومات عن مجموعات المصادر وكيفية دمج Gradle للموارد، اقرأ القسم عن كيفية إنشاء مجموعات المصادر.

فلترة الأسعار المتغيرة

ينشئ Gradle خيار إصدار لكل مجموعة ممكنة من نكهات المنتج وأنواع الإصدارات التي تضبطها. ومع ذلك، قد تكون هناك أنواع بنيات معيّنة لا تحتاج إليها أو لا تُعدّ منطقية في سياق مشروعك. لإزالة بعض إعدادات أنواع الإصدارات، أنشئ فلترًا لأنواع الإصدارات في ملف build.gradle.kts على مستوى الوحدة.

باستخدام إعدادات الإصدار من القسم السابق كمثال، لنفترض أنّك تخطّط لإتاحة الإصدار التمهيدي من التطبيق فقط لمستويات واجهة برمجة التطبيقات 23 والإصدارات الأحدث. يمكنك استخدام العنصر variantFilter لفلترة جميع إعدادات الصيغ المختلفة للإصدار التي تجمع بين نكهات المنتج "minApi21" و "demo":

Kotlin

android {
  ...
  buildTypes {...}

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

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

رائع

android {
  ...
  buildTypes {...}

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

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

بعد إضافة فلتر الصيغة إلى إعدادات الإصدار والنقر على مزامنة الآن في شريط الإشعارات، يتجاهل Gradle أي صِيغ إصدار تستوفي الشروط التي تحدّدها. لم تعُد خيارات الإصدار تظهر في القائمة عند النقر على الإصدار > اختيار خيار الإصدار من شريط القوائم أو خيارات الإصدار في شريط نافذة الأدوات.

إنشاء مجموعات مصادر

ينشئ Android Studio تلقائيًا main/ مجموعة المصادر والأدلة لكل ما تريد مشاركته بين جميع صيغ الإصدار. ومع ذلك، يمكنك إنشاء مجموعات مصادر جديدة للتحكّم بدقة في الملفات التي يجمعها Gradle ويجمعها لأنواع إصدارات معيّنة وأنواع منتجات ومجموعات أنواع المنتجات (عند استخدام سمات النكهة) وأنواع الإصدارات.

على سبيل المثال، يمكنك تحديد الوظيفة الأساسية في مجموعة مصادر main/ واستخدام مجموعات مصادر ملف تعريف المنتج لتغيير العلامة التجارية لتطبيقك للعملاء المختلفين، أو تضمين أذونات خاصة ووظيفة تسجيل فقط لأنواع الإصدارات التي تستخدم نوع الإصدار المخصّص لتصحيح الأخطاء.

يتوقّع Gradle تنظيم ملفات مجموعة المصادر وأدلائها بطريقة معيّنة تشبه مجموعة مصادر main/. على سبيل المثال، يتوقع Gradle أن تكون ملفات فئة Kotlin أو Java الخاصة بنوع الإصدار "debug" موجودة في الدليلَين src/debug/kotlin/ أو src/debug/java/.

يقدّم المكوّن الإضافي لنظام Gradle المتوافق مع Android مهمة Gradle مفيدة توضّح لك كيفية تنظيم ملفاتك لكل نوع من أنواع التصميمات وأنواع المنتجات ونُسخ التصميم. على سبيل المثال، يصف العيّنة التالية من ناتج المهمة المكان الذي يتوقّع فيه Gradle العثور على ملفات معيّنة لنوع الإصدار "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.

    للاطّلاع على مجلد المهام، يجب السماح لـ Gradle بإنشاء قائمة المهام أثناء المزامنة. ولإجراء ذلك، اتبع الخطوات التالية:

    1. انقر على ملف > الإعدادات > ميزات تجريبية (استوديو Android > الإعدادات > ميزات تجريبية على نظام التشغيل macOS).
    2. أزِل العلامة من المربّع بجانب عدم إنشاء قائمة مهام Gradle أثناء مزامنة Gradle.
  3. بعد تنفيذ Gradle للمهمة، تفتح نافذة Run (تشغيل) لعرض المخرجات.

ملاحظة: يوضّح لك أيضًا ناتج المهمة كيفية تنظيم مجموعات المصادر للملفات التي تريد استخدامها لإجراء اختبارات لتطبيقك، مثل test/ وandroidTest/ مجموعات مصادر الاختبار.

عند إنشاء نوع إصدار جديد، لا ينشئ Android Studio أدلة مجموعة ملف المصدر بدلاً منك، ولكنه يمنحك بعض الخيارات لمساعدتك. على سبيل المثال، لإنشاء الدليل java/ فقط لنوع الإصدار "debug" :

  1. افتح لوحة المشروع واختَر عرض المشروع من القائمة في أعلى اللوحة.
  2. انتقِل إلى MyProject/app/src/.
  3. انقر بزر الماوس الأيمن على دليل src واختَر جديد > دليل.
  4. من القائمة ضمن مجموعات مصادر Gradle، اختَر full/java.
  5. اضغط على Enter.

ينشئ "استوديو Android" دليل مجموعة مصادر لنوع الإصدار المخصّص لتصحيح الأخطاء، ثمّ ينشئ الدليل java/ داخله. بدلاً من ذلك، يمكن لخدمة Android Studio إنشاء الأدلة نيابةً عنك عند إضافة ملف جديد إلى مشروعك لإصدار محدّد.

على سبيل المثال، لإنشاء ملف XML للقيم لنوع الإصدار "debug":

  1. في لوحة المشروع، انقر بزر الماوس الأيمن على الدليل src واختَر جديد > XML > ملف XML للقيم.
  2. أدخِل اسم ملف XML أو احتفظ بالاسم التلقائي.
  3. من القائمة بجانب مجموعة مصادر الاستهداف، انقر على تصحيح الأخطاء.
  4. انقر على إنهاء.

بما أنّه تم تحديد نوع الإصدار "debug" على أنّه مجموعة المصادر المستهدَفة، ينشئ "استوديو Android" تلقائيًا الأدلة اللازمة عند إنشاء ملف XML. تبدو بنية الدليل الناتجة كما هو موضّح في الشكل 1.

الشكل 1: مجموعة مصادر جديدة تُنشئ أدلة لنوع الإصدار "debug"

تتضمّن مجموعات المصادر النشطة مؤشرًا أخضر في رمزها للإشارة إلى أنّها نشطة. تتم إضافة [main] إلى مجموعة رمز المصدر debug للإشارة إلى أنّه سيتم دمجها في مجموعة رمز المصدر main.

باستخدام الإجراء نفسه، يمكنك أيضًا إنشاء أدلة مجموعات مصادر لملفاتك المخصّصة لإصدارات محددة من المنتج، مثل src/demo/، وملفاتك المخصّصة لأنواع الإصدارات، مثل src/demoDebug/. بالإضافة إلى ذلك، يمكنك إنشاء مجموعات مصادر اختبار تستهدف أنواع إصدارات معيّنة، مثل src/androidTestDemoDebug/. لمزيد من المعلومات، يمكنك الاطّلاع على مقالة اختبار مجموعات المصادر.

تغيير إعدادات مجموعة المصادر التلقائية

إذا كانت لديك مصادر غير منظَّمة في ملف مجموعة المصادر التلقائية وفقًا للبنية التي يتوقّعها Gradle، كما هو موضّح في القسم السابق حول إنشاء مجموعات المصادر، يمكنك استخدام العنصر sourceSets لتغيير المكان الذي يبحث فيه Gradle عن جمع الملفات لكل مكوّن من مجموعة مصادر.

يجب أن يكون العنصر sourceSets في العنصر android. لست بحاجة إلى إعادة تحديد موقع ملفات المصدر، ما عليك سوى تزويد Gradle بالمسارات، بالنسبة إلىملف build.gradle.kts على مستوى الوحدة، حيث يمكن لـ Gradle العثور على ملفات لكل مكوّن من مكوّنات مجموعة المصادر. للتعرّف على المكوّنات التي يمكنك ضبطها وما إذا كان بإمكانك ربطها بملفات أو أدلة متعددة، اطّلِع على مرجع واجهة برمجة التطبيقات لمكوّن إضافي Gradle لنظام التشغيل Android.

يربط نموذج الرمز البرمجي التالي المصادر من الدليل app/other/ بمكونات معيّنة من مجموعة المصادر main ويغيّر الدليل الجذر لمجموعة المصادر androidTest:

Kotlin

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

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

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

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

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

رائع

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

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

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

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

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

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

يُرجى العلم أنّ الدليل المصدر يمكن أن ينتمي إلى مجموعة مصادر واحدة فقط. على سبيل المثال، لا يمكنك مشاركة مصادر الاختبار نفسها مع مجموعتَي المصادر test وandroidTest. ويعود سبب ذلك إلى أنّ "استوديو Android" ينشئ وحدات IntelliJ منفصلة لكل مجموعة مصادر، ولا يمكنه السماح بنسخ جذور المحتوى في مجموعات المصادر.

الإنشاء باستخدام مجموعات الرموز المصدر

يمكنك استخدام أدلة مجموعة المصادر لتضمين الرمز البرمجي والموارد التي تريد حزمها مع إعدادات معيّنة فقط. على سبيل المثال، إذا كنت بصدد إنشاء الصيغة "demoDebug" للإصدار، وهي ناتجة عن تفاعل بين نوع الإصدار "demo" ونوع الإصدار "debug"، يفحص Gradle هذه الأدلة ويمنحها الأولوية التالية:

  1. src/demoDebug/ (مجموعة مصادر تنويعة التصميم)
  2. src/debug/ (مجموعة مصادر نوع التصميم)
  3. src/demo/ (مجموعة مصادر صيغة المنتج)
  4. src/main/ (مجموعة المصادر الرئيسية)

يجب أن تتضمّن مجموعات المصادر التي تم إنشاؤها لمجموعات من أنواع المنتجات جميع سمات الأنواع. على سبيل المثال، يجب أن تكون مجموعة مصادر أنواع الإصدارات هي مجموعة من نوع الإصدار وجميع سمات النكهة. لا يُسمح بدمج الرموز البرمجية والموارد التي تتضمّن مجلدات تغطي عدة سمات نكهات ولكن ليس كلها.

في حال دمج نكهات منتجات متعددة، يتم تحديد الأولوية بين نكهات المنتجات حسب سمة النكهة التي تنتمي إليها. عند إدراج سمات النكهات باستخدام السمة android.flavorDimensions، تكون نكهات المنتجات التي تنتمي إلى سمة النكهة الأولى التي تُدرِجها لها أولوية أعلى من تلك التي تنتمي إلى سمة النكهة الثانية، وهكذا. بالإضافة إلى ذلك، تحظى مجموعات المصادر التي تنشئها لمجموعات من أنواع المنتجات بأولوية أعلى من مجموعات المصادر التي تنتمي إلى نوع منتج فردي.

يحدِّد ترتيب الأولوية مجموعة المصادر التي لها أولوية أعلى عندما يجمع Gradle الرموز البرمجية والموارد. بما أنّ دليل مجموعة المصادر demoDebug/ يحتوي على الأرجح على ملفات خاصة بنوع الإصدار هذا، إذا كان demoDebug/ يحتوي على ملف تم تحديده أيضًا في debug/، سيستخدم Gradle الملف في مجموعة المصادر demoDebug/. وبالمثل، يمنح Gradle الملفات في نوع الإنشاء ونكهة المنتج مجموعة مصادر أولوية أعلى من الملفات نفسها في main/. يراعي Gradle ترتيب الأولوية هذا عند تطبيق قواعد الإنشاء التالية:

  • يتم تجميع كل رمز المصدر في الدليلَين kotlin/ أو java/ معًا لإنشاء مخرج واحد.

    ملاحظة: بالنسبة إلى نوع إصدار معيّن، يُرسِل Gradle خطأ في الإصدار إذا صادف دليلَي مجموعة مصادر أو أكثر حدّدا فئة Kotlin أو Java نفسها. على سبيل المثال، عند إنشاء تطبيق تصحيح أخطاء، لا يمكنك تحديد كل من src/debug/Utility.kt و src/main/Utility.kt، لأنّ Gradle يفحص كلاً من هذين الدليلَين أثناء عملية الإنشاء ويُرسِل خطأ "فئة مكرّرة" . إذا كنت تريد إصدارات مختلفة من Utility.kt لأنواع تصاميم مختلفة، يجب أن يحدِّد كل نوع تصميم إصداره الخاص من الملف وألا يتم تضمينه في مجموعة مصادر main/.

  • يتم دمج ملفات البيان معًا في ملف بيان واحد. يتم منح الأولوية بالترتيب نفسه المُدرَج في القائمة في المثال السابق. وهذا يعني أنّ إعدادات البيان لنوع الإصدار تلغي إعدادات البيان لإصدار المنتج، وما إلى ذلك. للاطّلاع على مزيد من المعلومات، يمكنك الاطّلاع على مقالة دمج البيان.
  • يتم دمج الملفات في أدلة values/ معًا. إذا كان لملفَين الاسم نفسه، مثل ملفي strings.xml، تُمنَح الأولوية بالترتيب نفسه لقائمة في المثال السابق. وهذا يعني أنّ القيم المحدّدة في ملف في مجموعة مصادر نوع الإنشاء تلغي القيم المحدّدة في الملف نفسه في أحد أنواع المنتج، وما إلى ذلك.
  • يتم تجميع الموارد في الدليلَين res/ وasset/ معًا. إذا كانت هناك موارد تحمل الاسم نفسه محدّدة في مجموعتَي مصادر أو أكثر، يتم منح الأولوية بالترتيب نفسه للقوائم في المثال السابق.
  • يمنح Gradle الموارد والملفات البيانية المضمّنة في مكتبة متطلّبات وحدة أدنى أولوية عند إنشاء التطبيق.

الإفصاح عن التبعيات

لضبط تبعية لخيار بناء معيّن أو مجموعة مصادر اختبار، أضِف اسم خيار البناء أو مجموعة مصادر الاختبار قبل الكلمة الرئيسية Implementation، كما هو موضّح في المثال التالي:

Kotlin

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

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

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation("com.android.support.test.espresso:espresso-core:3.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'
}

لمزيد من المعلومات عن ضبط التبعيات، اطّلِع على إضافة تبعيات الإنشاء.

استخدام إدارة التبعية المراعية للأنواع

يتضمّن الإصدار 3.0.0 من "مكوّن Android Gradle الإضافي" والإصدارات الأحدث آلية جديدة للاعتماد تطابق تلقائيًا الصيغ عند استخدام مكتبة. وهذا يعني أنّ صيغة debug للتطبيق تستهلك تلقائيًا صيغة debug للمكتبة، وهكذا. ويعمل هذا الإجراء أيضًا عند استخدام ملفّات APK المخصّصة لإصدارات محدّدة من التطبيق: سيستهلك إصدار freeDebug من التطبيق إصدار freeDebug من المكتبة.

لكي يتطابق المكوّن الإضافي مع الأسعار المتغيرة بدقة، عليك توفير عناصر احتياطية مطابقة كما هو موضّح في القسم التالي، وذلك في الحالات التي لا تتوفّر فيها مطابقة مباشرة.

على سبيل المثال، لنفترض أنّ تطبيقك يضبط نوع إصدار يُسمى "مرحلة الاختبار"، ولكن أحد متطلّبات مكتبته لا يضبطه. عندما يحاول المكوّن الإضافي إنشاء الإصدار "التجريبي" من تطبيقك، لن يعرف إصدار المكتبة الذي يجب استخدامه، وستظهر لك رسالة خطأ مشابهة لما يلي:

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

حلّ أخطاء الإصدار المتعلقة بمطابقة الأسعار المتغيرة

يتضمّن المكوّن الإضافي عناصر لغة وصف لغة برمجة (DSL) لمساعدتك في التحكّم في كيفية حلّ Gradle للمواقف التي لا تتوفّر فيها إمكانية مطابقة الصيغة المباشرة بين التطبيق والمكوّن الإضافي.

في ما يلي قائمة بالمشاكل المتعلّقة بمطابقة التبعيات مع مراعاة الصيغ وكيفية حلّها باستخدام خصائص لغة وصف البيانات (DSL):

  • يشتمل تطبيقك على نوع إصدار لا يتضمّنه أحد متطلّبات المكتبة.

    على سبيل المثال، يتضمّن تطبيقك نوع الإصدار "الإصدار التجريبي"، ولكن لا يتضمّن أحد التبعيات سوى نوعَي الإصدار "تصحيح الأخطاء" و "الإصدار العلني".

    يُرجى العلم أنّه لا توجد مشكلة عندما يتضمّن أحد متطلّبات المكتبة نوع ملف برمجي غير متوفر في تطبيقك. ويعود السبب في ذلك إلى أنّ المكوّن الإضافي لا يطلب أبدًا نوع الإنشاء هذا من المكوّن الإضافي التابع.

    استخدِم matchingFallbacks لتحديد مطابقات بديلة لنوع إصدار معيّن، كما هو موضّح هنا:

    Kotlin

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

    رائع

    // In the app's build.gradle file.
    android {
        buildTypes {
            debug {}
            release {}
            staging {
                // Specifies a sorted list of fallback build types that the
                // plugin can try to use when a dependency does not include a
                // "staging" build type. You may specify as many fallbacks as you
                // like, and the plugin selects the first build type that's
                // available in the dependency.
                matchingFallbacks = ['debug', 'qa', 'release']
            }
        }
    }
    
  • بالنسبة إلى سمة نكهة معيّنة متوفّرة في كلّ من التطبيق وملف مكتبته الاعتمادي، يتضمّن تطبيقك نكهات لا تتضمّنها المكتبة.

    على سبيل المثال، يتضمّن كلّ من تطبيقك وعناصر المكتبة الاعتمادية سمة نكهة "المستوى". ومع ذلك، تتضمّن سمة "المستوى" في التطبيق خيارَي "مجاني" و "مدفوع"، ولكن لا يتضمّن الاعتماد سوى خيارَي "إصدار تجريبي" و "مدفوع" للسمة نفسها.

    يُرجى العلم أنّه بالنسبة إلى سمة نكهة معيّنة متوفّرة في كلّ من التطبيق وملف مكتبته ، لا توجد مشكلة في أن تتضمّن المكتبة نكهة منتج لا يتضمنها تطبيقك. ويعود السبب في ذلك إلى أنّ المكوّن الإضافي لا يطلب أبدًا هذا الإصدار من الحزمة المُستخدَمة من المكوّن الإضافي.

    استخدِم matchingFallbacks لتحديد مطابقات بديلة لإصدار التطبيق "المجاني" كما هو موضّح هنا:

    Kotlin

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

    رائع

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

    على سبيل المثال، تتضمّن إحدى العناصر الاعتمادية للمكتبة نكهات لسمة "minApi"، ولكن تطبيقك يتضمّن نكهات لسمة "المستوى" فقط. عندما تريد إنشاء إصدار "freeDebug" من تطبيقك، لا يعرف المكوّن الإضافي ما إذا كان سيستخدم الإصدار "minApi23Debug" أو "minApi18Debug" من العنصر المُستخدَم.

    يُرجى العلم أنّه لا توجد مشكلة عندما يتضمّن تطبيقك سمة نكهة لا تتضمّنها مكتبة تابعة. ويعود السبب في ذلك إلى أنّ المكوّن الإضافي لا يطابق سوى أنواع السمات التي تتوفّر في العنصر المُستخدَم. على سبيل المثال، إذا لم يتضمّن أحد التبعيات سمة لـ ABI، سيستخدم إصدار "freeX86Debug" من تطبيقك إصدار "freeDebug" من التبعية.

    استخدِم missingDimensionStrategy في العنصر defaultConfig لتحديد النكهة التلقائية التي يمكن للمكوّن الإضافي الاختيار من بينها لكل سمة غير متوفّرة، كما هو موضّح في المثال التالي. يمكنك أيضًا إلغاء اختياراتك في العنصر productFlavors ، لكي يتمكّن كلّ إصدار من تحديد استراتيجية مطابقة مختلفة لسمة غير متوفّرة.

    Kotlin

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

    رائع

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

لمزيد من المعلومات، يُرجى الاطّلاع على matchingFallbacks وmissingDimensionStrategy في مرجع DSL الخاص بالمكوّن الإضافي لنظام Gradle المتوافق مع Android.

ضبط إعدادات التوقيع

لا يوقّع Gradle حِزمة APK أو حِزمة AAB لإصدار تطبيقك ما لم تحدِّد صراحةً إعدادات توقيع لهذا الإصدار. إذا لم يكن لديك مفتاح توقيع حتى الآن، أنشئ مفتاح تحميل وملف تخزين مفاتيح باستخدام "استوديو Android".

لضبط إعدادات التوقيع يدويًا لنوع إصدار الإصدار باستخدام إعدادات إنشاء Gradle:

  1. أنشئ ملف تخزين مفاتيح. ملف تخزين المفاتيح هو ملف ثنائي يحتوي على مجموعة من المفاتيح الخاصة. يجب الاحتفاظ بملف تخزين المفاتيح في مكان آمن وموثوق به.
  2. أنشئ مفتاحًا خاصًا. يُستخدَم مفتاح خاص لتوقيع تطبيقك من أجل توزيعه، ولا يتم تضمينه مطلقًا مع التطبيق أو الإفصاح عنه لجهات خارجية غير مصرَّح بها.
  3. أضِف إعدادات التوقيع إلى ملف build.gradle.kts على مستوى الوحدة:

    Kotlin

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

    رائع

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

ملاحظة: إنّ تضمين كلمات مرور مفتاح الإصدار وملف تخزين المفاتيح داخل ملف الإنشاء ليس من الممارسات الأمنية الجيدة. بدلاً من ذلك، يمكنك ضبط ملف الإنشاء للحصول على كلمات المرور هذه من متغيّرات البيئة أو أن تطلب منك عملية الإنشاء إدخال كلمات المرور هذه.

للحصول على كلمات المرور هذه من متغيّرات البيئة:

Kotlin

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

رائع

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

بدلاً من ذلك، يمكنك تحميل ملف تخزين المفاتيح من ملف خصائص على الجهاز. لأسباب تتعلّق بالأمان، لا ينبغي إضافة هذا الملف إلى أداة التحكّم في المصدر. بدلاً من ذلك، يمكنك إعداده محليًا لكل مطوِّر. لمزيد من المعلومات، يُرجى الاطّلاع على المقالة إزالة معلومات التوقيع من ملفات الإنشاء.

بعد إكمال هذه العملية، يمكنك توزيع تطبيقك ونشره على Google Play.

تحذير: احتفِظ بملف تخزين المفاتيح والمفتاح الخاص في مكان آمن وموثوق به، وتأكَّد من توفُّر نُسخ احتياطية آمنة منهما. إذا كنت تستخدم ميزة "توقيع التطبيق" من Play وفقدت مفتاح التحميل، يمكنك طلب إعادة ضبطه باستخدام Play Console. إذا كنت بصدد نشر تطبيق بدون ميزة "توقيع التطبيق" من Play (للتطبيقات التي تم إنشاؤها قبل آب/أغسطس 2021) و فقدت مفتاح توقيع التطبيق، لن تتمكّن من نشر أي تحديثات لتطبيقك، لأنّه عليك دائمًا توقيع جميع إصدارات تطبيقك باستخدام المفتاح نفسه.

توقيع تطبيقات Wear OS

عند نشر تطبيقات Wear OS، يجب توقيع كل من حزمة APK المخصّصة للساعة وحزمة APK الاختيارية المخصّصة للهاتف باستخدام المفتاح نفسه. لمزيد من المعلومات عن حزم تطبيقات Wear OS وتوقيعها، اطّلِع على مقالة تجميع تطبيقات Wear OS وتوزيعها.