توضّح لك هذه الصفحة كيفية ضبط تنويعات التصميم لإنشاء إصدارات مختلفة من تطبيقك من مشروع واحد، وكيفية إدارة التبعيات وإعدادات التحقق بشكل صحيح.
تمثّل كل تنويعة تصميم إصدارًا مختلفًا من تطبيقك يمكنك إنشاؤه. على سبيل المثال، قد ترغب في إنشاء إصدار واحد من تطبيقك يكون مجانيًا مع مجموعة محدودة من المحتوى، وإصدار آخر مدفوع يتضمن المزيد. يمكنك أيضًا إنشاء إصدارات مختلفة من تطبيقك تستهدف أجهزة مختلفة، استنادًا إلى مستوى واجهة برمجة التطبيقات أو غير ذلك من الاختلافات بين الأجهزة.
تنتج تنويعات التصميم عن استخدام Gradle لمجموعة معيّنة من القواعد لدمج الإعدادات والرموز والموارد التي تم ضبطها في أنواع الإصدارات وصيغ المنتجات. على الرغم من أنّك لا تضبط إعدادات تنويعات التصميم مباشرةً، يمكنك ضبط إعدادات أنواع الإصدارات وصيغ المنتجات التي تتكوّن منها.
على سبيل المثال، قد تحدّد صيغة المنتج "التجريبية" ميزات ومتطلبات معيّنة للجهاز، مثل الرمز المصدر المخصّص والموارد والحد الأدنى لمستويات واجهة برمجة التطبيقات، بينما يطبّق نوع الإصدار "تصحيح الأخطاء" إعدادات مختلفة للإصدار والحزمة، مثل خيارات تصحيح الأخطاء ومفاتيح التوقيع. تنويعة التصميم التي تجمع بين هذين النوعين هي إصدار "demoDebug" من تطبيقك، وتتضمّن مجموعة من الإعدادات والموارد المضمّنة في صيغة المنتج "demo" ونوع الإصدار "debug" ومجموعة رموز المصدر main/.
ضبط أنواع الإصدارات
يمكنك إنشاء أنواع الإصدارات وضبطها داخل مجموعة android
في ملف build.gradle.kts على مستوى الوحدة. عند إنشاء وحدة جديدة، ينشئ "استوديو Android" تلقائيًا نوعَي الإصدار لتصحيح الأخطاء والإصدار النهائي. على الرغم من أنّ نوع الإصدار المخصص لتصحيح الأخطاء لا يظهر في ملف إعدادات التصميم، يضبطه "استوديو Android" باستخدام debuggable
true. يتيح لك ذلك تصحيح أخطاء التطبيق على أجهزة Android الآمنة وضبط توقيع التطبيق باستخدام ملف تخزين مفاتيح عام لتصحيح الأخطاء.
يمكنك إضافة نوع الإصدار المخصص لتصحيح الأخطاء إلى الإعدادات إذا أردت إضافة إعدادات معيّنة أو تغييرها. يحدّد النموذج التالي
applicationIdSuffix لنوع الإصدار المخصص لتصحيح الأخطاء ويضبط نوع الإصدار "staging" الذي تتم تهيئته باستخدام الإعدادات من نوع الإصدار المخصص لتصحيح الأخطاء:
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" وتضيف صيغ المنتج "demo" و "full". توفّر هذه الإصدارات
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، عليك تخصيص قيمة applicationId نفسها لجميع الصيغ ومنح كل صيغة قيمة versionCode مختلفة لتوزيع تطبيقك باستخدام إمكانية استخدام حِزم APK متعددة في Google Play. لتوزيع خيارات مختلفة من تطبيقك كتطبيقات منفصلة في Google Play، عليك تخصيص applicationId مختلف لكل خيار.
بعد إنشاء نكهات المنتج وضبطها، انقر على المزامنة الآن في شريط الإشعارات. بعد اكتمال المزامنة، ينشئ Gradle تلقائيًا تنويعات التصميم استنادًا إلى أنواع الإصدارات وصيغ المنتجات ويسمّيها وفقًا لـ <product-flavor><Build-Type>. على سبيل المثال، إذا أنشأت صيغ المنتج "demo" و "full"، واحتفظت بأنواع الإصدارات التلقائية "debug" و"release"، سينشئ Gradle تنويعات التصميم التالية:
-
demoDebug -
demoRelease -
fullDebug -
fullRelease
لاختيار تنويعة التصميم التي تريد إنشاءها وتشغيلها، انتقِل إلى إنشاء > اختيار تنويعة التصميم واختَر تنويعة التصميم من القائمة. لبدء تخصيص كل تنويعة تصميم بميزاتها ومواردها الخاصة، عليك إنشاء مجموعات رموز المصدر وإدارتها، كما هو موضّح في هذه الصفحة.
تغيير رقم تعريف التطبيق لتنويعات التصميم
عند إنشاء حزمة APK أو حزمة تطبيق Android (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 متعددة
يستهدف كل منها إعدادات جهاز مختلفة، مثل مستوى واجهة برمجة التطبيقات،
فعليك استخدام رقم تعريف التطبيق نفسه لكل تنويعة تصميم، ولكن يجب منح كل
حزمة APK سمة versionCode مختلفة. لمزيد من المعلومات، يُرجى الاطّلاع على إتاحة حِزم APK متعددة. لا يتأثر النشر باستخدام حِزمات AAB، لأنّها تستخدم عنصرًا واحدًا يستخدم رمز إصدار واحدًا ورقم تعريف تطبيق واحدًا بشكل تلقائي.
ملاحظة: إذا كنت بحاجة إلى الإشارة إلى معرّف التطبيق في ملف البيان، يمكنك استخدام العنصر النائب ${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" و "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" تلقائيًا مجموعة رموز المصدر main/ والأدلة لكل ما تريد مشاركته بين جميع تنويعات التصميم. ومع ذلك، يمكنك إنشاء مجموعات رموز مصدر جديدة للتحكّم بدقة في الملفات التي يجمعها Gradle ويحزمها لأنواع إصدارات معيّنة وصيغ منتجات ومجموعات من صيغ المنتجات (عند استخدام سمات الصيغ) وتنويعات التصميم.
على سبيل المثال، يمكنك تحديد الوظائف الأساسية في مجموعة رموز المصدر main/ واستخدام مجموعات رموز المصدر الخاصة بصيغ المنتج لتغيير العلامة التجارية لتطبيقك لعملاء مختلفين، أو تضمين أذونات خاصة ووظائف تسجيل فقط لتنويعات التصميم التي تستخدم نوع الإصدار المخصص لتصحيح الأخطاء.
تتوقّع Gradle أن يتم تنظيم ملفات وأدلة مجموعات رموز المصدر بطريقة معيّنة، على غرار مجموعة رموز المصدر main/. على سبيل المثال، يتوقّع Gradle أن تكون ملفات فئات Kotlin أو Java الخاصة بنوع الإصدار "تصحيح الأخطاء" موجودة في دليل src/debug/kotlin/ أو src/debug/java/.
يوفّر المكوّن الإضافي لنظام Gradle المتوافق مع Android مهمة مفيدة في Gradle توضّح لك كيفية تنظيم ملفاتك لكل نوع من أنواع الإصدارات ونكهات المنتجات وتنويعات التصميم. على سبيل المثال، يوضّح النموذج التالي من مخرجات المهمة المكان الذي يتوقّع Gradle العثور فيه على ملفات معيّنة لنوع الإصدار "تصحيح الأخطاء":
------------------------------------------------------------ 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]
لعرض هذه النتيجة، اتّبِع الخطوات التالية:
- انقر على Gradle في شريط نافذة الأدوات.
انتقِل إلى MyApplication > Tasks > android وانقر مرّتين على sourceSets.
للاطّلاع على مجلد المهام، عليك السماح لـ Gradle بإنشاء قائمة المهام أثناء المزامنة. ولإجراء ذلك، اتبع الخطوات التالية:
- انقر على ملف > الإعدادات > تجريبي (استوديو Android > الإعدادات > تجريبي على نظام التشغيل macOS).
- ألغِ اختيار عدم إنشاء قائمة مهام Gradle أثناء مزامنة Gradle.
- بعد أن ينفّذ Gradle المهمة، تفتح نافذة Run لعرض النتيجة.
ملاحظة: يعرض لك ناتج المهمة أيضًا كيفية تنظيم مجموعات رموز المصدر
للملفات التي تريد استخدامها لإجراء اختبارات لتطبيقك، مثل
test/ وandroidTest/
مجموعات رموز المصدر للاختبار.
عند إنشاء تنويعة تصميم جديدة، لا ينشئ "استوديو Android" أدلة مجموعات رموز المصدر، ولكنّه يوفّر لك بعض الخيارات لمساعدتك. على سبيل المثال، لإنشاء دليل java/ فقط لنوع الإصدار "debug":
- افتح لوحة المشروع واختَر عرض المشروع من القائمة في أعلى اللوحة.
- الانتقال إلى تطبيق
MyProject/app/src/ - انقر بزر الماوس الأيمن على دليل
srcواختَر جديد > دليل. - من القائمة ضمن مجموعات رموز مصدر Gradle، اختَر full/java.
- اضغط على Enter.
ينشئ "استوديو Android" دليل مجموعة رموز المصدر لنوع الإصدار المخصص لتصحيح الأخطاء، ثم ينشئ دليل java/ بداخله. بدلاً من ذلك، يمكن أن ينشئ "استوديو Android" الأدلة لك عند إضافة ملف جديد إلى مشروعك لتنويعة تصميم معيّنة.
على سبيل المثال، لإنشاء ملف XML للقيم لنوع الإصدار "تصحيح الأخطاء":
- في لوحة المشروع، انقر بزر الماوس الأيمن على دليل
srcواختَر جديد > XML > ملف XML للقيم. - أدخِل اسمًا لملف XML أو احتفِظ بالاسم التلقائي.
- من القائمة بجانب مجموعة رموز المصدر المستهدَفة، اختَر تصحيح الأخطاء.
- انقر على إنهاء.
بما أنّه تم تحديد نوع الإصدار "تصحيحي" كمجموعة رموز المصدر المستهدَفة، ينشئ "استوديو 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"، وهي ناتج ضرب ديكارتي لصنف المنتج "demo" ونوع الإصدار "debug"، ينظر Gradle إلى هذه الأدلة ويمنحها الأولوية التالية:
-
src/demoDebug/(مجموعة رموز مصدر تنويعة التصميم) -
src/debug/(مجموعة رموز مصدر نوع الإصدار) -
src/demo/(مجموعة رموز مصدر صيغة المنتج) -
src/main/(مجموعة رموز المصدر الرئيسية)
يجب أن تتضمّن مجموعات رموز المصادر التي تم إنشاؤها لمجموعات صيغ المنتج جميع سمات الصيغ. على سبيل المثال، يجب أن تكون مجموعة رموز مصدر تنويعة التصميم هي مزيج من نوع التصميم وجميع سمات الصيغ. لا يمكن دمج الرموز البرمجية والموارد التي تتضمّن مجلدات تغطي سمات صيغ متعددة ولكن ليس جميعها.
إذا جمعت بين عدة صيغ للمنتج، يتم تحديد الأولوية بين صيغ المنتج حسب سمة الصيغة التي تنتمي إليها. عند إدراج سمات الصيغ باستخدام السمة
android.flavorDimensions، يتم تحديد أولوية صيغ المنتج حسب ترتيب الإعلان عن سماتها، بحيث تكون الأولوية للسمات السابقة على السمات اللاحقة. بالإضافة إلى ذلك،
تكون لمجموعات رموز المصدر التي تنشئها لمجموعات صيغ المنتج أولوية أعلى
من مجموعات رموز المصدر التي تنتمي إلى صيغة منتج فردية.
يحدّد ترتيب الأولوية مجموعة رموز المصدر التي لها أولوية أعلى عندما يجمع Gradle بين الرموز والموارد. بما أنّ دليل مجموعة رموز المصدر demoDebug/ يحتوي على الأرجح على ملفات خاصة بتنويعة التصميم هذه، إذا كان demoDebug/ يتضمّن ملفًا تم تحديده أيضًا في debug/، يستخدم Gradle الملف في مجموعة رموز المصدر demoDebug/. وبالمثل، يمنح Gradle الملفات في مجموعات رموز المصدر الخاصة بنوع الإصدار وصيغة المنتج أولوية أعلى من الملفات نفسها في main/.
يأخذ Gradle ترتيب الأولوية هذا في الاعتبار عند تطبيق قواعد الإصدار التالية:
- يتم تجميع كل الرموز المصدرية في الدليلَين
kotlin/أوjava/معًا لإنشاء مخرجات واحدة.ملاحظة: بالنسبة إلى تنويعة تصميم معيّنة، يعرض Gradle خطأً في التصميم إذا واجه دليلَين أو أكثر من أدلة مجموعات رموز المصدر التي حدّدت فئة Kotlin أو Java نفسها. على سبيل المثال، عند إنشاء تطبيق لتصحيح الأخطاء، لا يمكنك تحديد كل من
src/debug/Utility.ktوsrc/main/Utility.kt، لأنّ Gradle يبحث في كلا الدليلَين أثناء عملية الإنشاء ويعرض خطأ "فئة مكرّرة". إذا أردت استخدام إصدارات مختلفة منUtility.ktلأنواع إصدارات مختلفة، يجب أن يحدّد كل نوع إصدار نسخته الخاصة من الملف وألا يضمّنها في مجموعة رموز المصدرmain/. - يتم دمج ملفات البيان معًا في ملف بيان واحد. يتم منح الأولوية بالترتيب نفسه الموضّح في القائمة في المثال السابق. على سبيل المثال، تلغي إعدادات البيان لنوع الإصدار إعدادات البيان لصيغة المنتج. لمزيد من المعلومات، يمكنك الاطّلاع على دمج ملفات البيان.
- يتم دمج الملفات في أدلة
values/معًا. إذا كان هناك ملفان يحملان الاسم نفسه، مثل ملفَّيstrings.xml، يتم منح الأولوية بالترتيب نفسه الموضّح في القائمة في المثال السابق. على سبيل المثال، القيم المحدّدة في ملف ضمن مجموعة رموز المصدر لنوع الإصدار تلغي القيم المحدّدة في الملف نفسه ضمن صيغة المنتج. - يتم تجميع الموارد في الدليلَين
res/وasset/معًا. إذا كانت هناك موارد تحمل الاسم نفسه ومحدّدة في مجموعتَي رموز مصدر أو أكثر، يتم منح الأولوية بالترتيب نفسه الموضّح في القائمة في المثال السابق. - يمنح Gradle الموارد وملفات البيان المضمّنة في تبعيات وحدة المكتبة الأولوية الأدنى عند إنشاء التطبيق.
تحديد الاعتماديات
لضبط تبعية لتنويعة تصميم معيّنة أو
مجموعة رموز مصدر اختبار،
أضِف اسم تنويعة التصميم أو مجموعة رموز مصدر الاختبار قبل
الكلمة الرئيسية Implementation، كما هو موضّح في المثال التالي:
Kotlin
dependencies { // Adds the local "mylibrary" module as a dependency to the "free" flavor. "freeImplementation"(project(":mylibrary")) // Adds a remote binary dependency only for local tests. testImplementation("junit:junit:4.12") // Adds a remote binary dependency only for the instrumented test APK. androidTestImplementation("com.android.support.test.espresso:espresso-core:3.6.1") }
أنيق
dependencies { // Adds the local "mylibrary" module as a dependency to the "free" flavor. freeImplementation project(":mylibrary") // Adds a remote binary dependency only for local tests. testImplementation 'junit:junit:4.12' // Adds a remote binary dependency only for the instrumented test APK. androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.6.1' }
لمزيد من المعلومات حول ضبط التبعيات، يُرجى الاطّلاع على إضافة تبعيات الإصدار.
استخدام إدارة الاعتماديات التي تتضمّن صيغًا مختلفة
يتضمّن الإصدار 3.0.0 من المكوّن الإضافي لنظام Gradle المتوافق مع Android والإصدارات الأحدث آلية جديدة للتبعية تعمل تلقائيًا على مطابقة التنويعات عند استخدام مكتبة. على سبيل المثال، تستهلك صيغة debug للتطبيق تلقائيًا صيغة debug للمكتبة. وتعمل أيضًا عند استخدام الصيغ: سيستخدم الإصدار freeDebug من التطبيق الإصدار freeDebug من المكتبة.
لكي يطابق المكوّن الإضافي الصيغ بدقة، عليك توفير خيارات احتياطية للمطابقة كما هو موضّح في القسم التالي، للحالات التي لا يمكن فيها إجراء مطابقة مباشرة.
على سبيل المثال، لنفترض أنّ تطبيقك يضبط نوع إصدار باسم "staging"، ولكن إحدى تبعيات المكتبة لا تفعل ذلك. عندما يحاول المكوّن الإضافي إنشاء إصدار "staging" من تطبيقك، لن يعرف إصدار المكتبة الذي يجب استخدامه، وستظهر لك رسالة خطأ مشابهة لما يلي:
Error:Failed to resolve: Could not resolve project :mylibrary.
Required by:
project :app
حلّ أخطاء الإصدار المتعلّقة بمطابقة الصيغ
يتضمّن المكوّن الإضافي عناصر DSL لمساعدتك في التحكّم في كيفية حلّ Gradle للحالات التي لا يمكن فيها مطابقة الصيغة المباشرة بين التطبيق والتبعية.
في ما يلي قائمة بالمشاكل المتعلّقة بمطابقة التبعيات المستندة إلى الصيغ وكيفية حلّها باستخدام خصائص DSL:
يتضمّن تطبيقك نوع إصدار لا تتضمّنه تبعية المكتبة.
على سبيل المثال، يتضمّن تطبيقك نوع الإصدار "staging"، ولكن تتضمّن التبعية نوعَي الإصدار "debug" و "release" فقط.
يُرجى العِلم أنّه لا توجد مشكلة عندما تتضمّن تبعية المكتبة نوع إصدار لا يتضمّنه تطبيقك. ويرجع ذلك إلى أنّ المكوّن الإضافي لا يطلب مطلقًا نوع الإصدار هذا من التبعية.
استخدِم
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'] } } }
بالنسبة إلى سمة صيغ معيّنة متوفّرة في كل من التطبيق والمكتبة التي يعتمد عليها، يتضمّن تطبيقك صيغًا لا تتضمّنها المكتبة.
على سبيل المثال، يتضمّن كل من تطبيقك وبرامج المكتبة الاعتمادية سمة الصيغ "tier". ومع ذلك، يتضمّن سمة "tier" في التطبيق نكهتَي "free" و "paid"، ولكنّ التبعية تتضمّن نكهتَي "demo" و "paid" فقط للسمة نفسها.
يُرجى العِلم أنّه بالنسبة إلى سمة صيغ معيّنة متوفّرة في كل من التطبيق وتبعيات المكتبة، لا تحدث مشكلة عندما تتضمّن المكتبة صيغة منتج لا يتضمّنها تطبيقك. ويعود السبب في ذلك إلى أنّ المكوّن الإضافي لا يطلب أبدًا هذا الإصدار من التبعية.
استخدِم
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"، ولكن تطبيقك يتضمّن نكهات لسمة "tier" فقط. عندما تريد إنشاء الإصدار "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:
- أنشئ مخزن مفاتيح. مخزن المفاتيح هو ملف ثنائي يحتوي على مجموعة من المفاتيح الخاصة. يجب الاحتفاظ بمخزن المفاتيح في مكان آمن.
- أنشئ مفتاحًا خاصًا. يُستخدَم المفتاح الخاص لتوقيع تطبيقك من أجل توزيعه، ولا يتم تضمينه مطلقًا في التطبيق أو الإفصاح عنه لجهات خارجية غير مصرَّح لها.
-
أضِف إعدادات التحقق إلى ملف
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 وتوزيعها.