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

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

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

تكون أنواع الإصدارات نتيجة استخدام 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 يطبّق إعدادات نوع الإصدار بعد خيار المنتج، يكون معرّف التطبيق لخيار الإصدار "free debug" هو "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 كل خيار من خيارات الإصدار أو العناصر المقابلة له، تظهر نكهات المنتجات التي تنتمي إلى سمة الصيغة ذات الأولوية الأعلى أولاً، تليها تلك النكهات من السمات ذات الأولوية الأقل، يليها نوع التصميم.

باستخدام إعدادات الإصدار السابقة كمثال، ينشئ 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/ فقط لنوع الإصدار "تصحيح الأخطاء":

  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، تُمنَح الأولوية بالترتيب نفسه لقائمة 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 للمكتبة، وهكذا. وهي تعمل أيضًا عند استخدام النكهات: ستستهلك صيغة 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 وتوزيعها.