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

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

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

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

على سبيل المثال، قد تحدّد صيغة المنتج "العرض التوضيحي" ميزات ومتطلبات معيّنة للأجهزة، مثل رمز المصدر المخصّص والموارد والحد الأدنى لمستويات واجهة برمجة التطبيقات، في حين يطبّق نوع الإصدار "تصحيح الأخطاء" إعدادات مختلفة للإصدار وحزمة التطبيق، مثل خيارات تصحيح الأخطاء ومفاتيح التوقيع. وصيغة الإصدار التي تجمع بين هذين الإصدارين هي إصدار "demoDebug" الخاص بتطبيقك، وهي تشمل مجموعة من الإعدادات والموارد المضمَّنة في صيغة المنتج "الإصدار التجريبي" ونوع التصميم "demoDebug" ومجموعة المصدر 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" مزامنة مشروعك مع الإعدادات الجديدة. لمزامنة مشروعك، انقر على المزامنة الآن في شريط الإشعارات الذي يظهر عند إجراء تغيير، أو انقر على مزامنة المشروع من شريط الأدوات. إذا لاحظ "استوديو Android" أي أخطاء في الإعدادات، ستظهر نافذة الرسائل لوصف المشكلة.

لمعرفة المزيد من المعلومات عن جميع السمات التي يمكنك ضبطها باستخدام أنواع الإصدارات، اطّلِع على مرجع 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.

إذا كانت وحدة معيّنة تحدد سمة واحدة فقط للصيغة، فإن المكوّن الإضافي لنظام Gradle المتوافق مع Android يخصّص تلقائيًا جميع أشكال الوحدة لتلك السمة.

ينشئ نموذج الرمز البرمجي التالي سمة نكهة باسم "version" ويضيف نكهات المنتج "الإصدار التجريبي" و "الكامل". وتتميز هاتان النكهات بطابعها الخاص، وهي 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". يكون هذا مفيدًا عندما تريد إصدار كل من تصحيح الأخطاء والإصدار على نفس الجهاز، لأنه لا يمكن أن يحتوي تطبيقان على معرّف التطبيق ذاته.

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

ملاحظة: إذا كنت بحاجة إلى الإشارة إلى معرّف التطبيق في ملف البيان، يمكنك استخدام العنصر النائب ${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 هذه المصادر إلا عند إنشاء صيغة تجمع بين نكهتَي المنتج هاتين.

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

فلترة الصيغ

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

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

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" مجموعة المصادر والأدلة main/ تلقائيًا لكل ما تريد مشاركته بين جميع صيغ الإصدارات. في المقابل، يمكنك إنشاء مجموعات مصادر جديدة للتحكّم بدقة في الملفات التي يجمعها وحِزم Gradle لأنواع تصميم معيّنة ونكهات المنتجات ومجموعات نكهات المنتجات (عند استخدام سمات النكهات) وخيارات التصميم.

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

تتوقّع منصة Gradle أن يتم تنظيم ملفات وأدلة مجموعة المصدر بطريقة معيّنة تشبه مجموعة المصادر main/. على سبيل المثال، من المتوقّع أن تكون ملفات فئة 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" أدلة مجموعة المصادر نيابةً عنك، لكنّه يقدّم لك بعض الخيارات لمساعدتك. على سبيل المثال، لإنشاء دليل java/ فقط لنوع الإصدار "تصحيح الأخطاء":

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

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

على سبيل المثال، لإنشاء ملف XML الخاص بالقيم لنوع الإصدار "تصحيح الأخطاء"، يمكنك اتّباع الخطوات التالية:

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

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

الشكل 1. أدلة جديدة لمجموعة المصادر لنوع الإصدار "تصحيح الأخطاء".

تحتوي مجموعات المصادر النشطة على مؤشر أخضر في رمزها يشير إلى أنها نشطة. تتم إضافة لاحقة debug إلى مجموعة المصدر باللاحقة [main] لتوضيح أنه سيتم دمجها في المجموعة المصدر 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"، وهي عبارة عن منتج متكامل لنكهة منتج "إصدار تجريبي" ونوع إصدار "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.5.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.5.1'
}

لمزيد من المعلومات حول ضبط التبعيات، راجِع إضافة تبعيات الإصدار.

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

يشتمل الإصدار 3.0.0 من المكوّن الإضافي لنظام Gradle المتوافق مع Android والإصدارات الأحدث على آلية تبعية جديدة تتطابق تلقائيًا مع الصيغ عند استخدام مكتبة. ويعني هذا أنّ صيغة 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 وتوزيعها.