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

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

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

تكون أنواع الإصدارات نتيجة استخدام 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" أي أخطاء في الإعدادات، ستظهر نافذة الرسائل لوصف المشكلة.

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

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 > مهام Google > 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، تُمنَح الأولوية بالترتيب نفسه لقائمة 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 وتوزيعها.