مقدمة
من بعيد 2012 ، في الأماكن المفتوحة في هبر ، أتذكر التعليق:
... إذا لم يكن هناك أي حالة من البداية ، فسيبقى الجهاز
لم تنته ، سوف تسقط الغبار على الرف ...
الموضوع بعيد عن مكون الأجهزة. تحليلًا لمشكلتي ، أصبحت مقتنعًا بصحة هذا الحكم وحاولت وضع الأمور على رفوف المتربة.
تم الاتصال بي مؤخرًا بواسطة عميل طلب مني إضافة دعم للعديد من الخدمات لمشروعه. كانت المهمة أنني كنت بحاجة لتوصيل خدمة "A" وقبل تشغيل التطبيق ، قم بتشغيل هذه الخدمة في بيئة اختبار. قررت تحليل قراراتي السابقة و ... شعرت بالرعب.
بالنسبة لأنواع مختلفة من التجميعات ، استخدمت ملفات التكوين المختلفة مع وصف متغيرات البيئة. ولكن المشكلة هي أنه فقط لإعادة توجيه القيمة إلى الكود الحقيقي ، كان من الضروري كتابة نفس الكود لكل نوع.
المشكلة
يمنحنا Google القدرة على إعادة توجيه القيم المخصصة لكل منها
التجمع .
android { //... buildTypes { release { buildConfigField("String", "HOST_URL", "\"prod.com\"") } debug { buildConfigField("String", "HOST_URL", "\"debug.com\"") } } }
بعد تحليل البرنامج النصي build.gradle ، ستأخذ أدوات android جميع قيم buildConfigFileds من buildTypes و productFlavors وإنشاء ملفات BuildConfig لكل نوع من أنواع التجميع:
public final class BuildConfig {
لا مشكلة للوهلة الأولى. خاصة عندما لا يكون هناك الكثير من النكهات والقيم المخصصة في التطبيق الخاص بك. في مشروعي كان هناك> 20 و 3 بيئات (داخلي / ألفا / إنتاج). من الواضح ، كان هناك مشكلة واحدة فقط بالنسبة لي - للتخلص من الغليان.
مشكلة لا تقل أهمية هي أن قيم متغيرات البيئة يجب ألا تنعكس في مشروعك. حتى في ملف التكوين. يجب عليك التحقق من تكوين build.gradle عبر VCS. لكن لا ينبغي عليك تسجيل المفاتيح الخاصة بك مباشرةً ، ولهذا ، فأنت بحاجة إلى آلية تابعة لجهة خارجية (على سبيل المثال ، ملف ، وخدمات CI). في ممارستي ، كان هناك العديد من المشاريع حيث لم يكن بإمكاني الوصول إلى قيم بعض المكتبات لتجميع إنتاج الإصدار. هذه بالفعل مشكلة في العمل وفي مصلحتها عدم تكبد تكاليف غير ضرورية. يجب عدم استخدام المفاتيح المخصصة للإنتاج أثناء تصحيح الأخطاء أو الاختبار الداخلي.
طريقة حل المشكلة
في أحد المشاريع القديمة ، لتخزين قيم متغيرات البيئة ، استخدمنا ملفات .properties البسيطة التي وفرت الوصول إلى الحقول من خلال المفتاح الكلاسيكي: خريطة القيمة. هذا النهج لا يحل مشكلة ملزمة. لكنه يحل مشكلة تسليم البيانات ، والتي ينبغي تطبيقها. بالإضافة إلى ذلك ، يمكننا أخذ ملفات .properties كأساس لنوع معين من عقد توفير البيانات.
إذا عدنا قليلاً ، فلدينا خطوة وسيطة: من buildConfigField إلى حقل فئة BuildConfig . لكن من يفعل هذا؟ كل شيء جميل ، والمكون الإضافي الذي تتصل به تمامًا في جميع مشاريع Android مسؤول عن ذلك.
apply plugin: "com.android.application"
هو المسؤول عن حقيقة أنه بعد تحليل ملف build.gradle الخاص بك ، سيتم إنشاء فئة BuildConfig لكل نكهة بمجموعة من الحقول الخاصة بها. وبهذه الطريقة ، أستطيع أن أكتب دوائي الخاص الذي سيزيد من قدرات com.android.application والحفظ
لي من هذا الصداع.
حل المشكلة كما يلي: تقديم عقد ،
والتي سوف تصف جميع المفاتيح والقيم لجميع الجمعيات.
قم بتوسيع ملفات التكوين إلى أنواع فرعية. إعطاء كل شيء إلى البرنامج المساعد.

قرار
أعلاه اكتشفنا بنية الحل ، الشيء الوحيد المتبقي هو أن نعيد الحياة إلى كل شيء. يبدو أنه يمكن حل حل تافه ومشكلة عن طريق ملحق ملف بناء بسيط. في البداية ، لقد فعلت ذلك.
كشف الحل ```groovy class Constants { // Environments properties path pattern, store your config files in each folders of pattern static final CONFIG_PROPERTY_PATTERN = "config/%s/config.properties" } android.buildTypes.all { buildType -> buildConfigFields(buildType, buildType.name) } android.applicationVariants.all { appVariant -> buildConfigFields(appVariant, appVariant.flavorName) } private def buildConfigFields(Object variant, String variantName) { def properties = getProperties(variantName) properties.each { key, value -> variant.buildConfigField( parseValueType(value), toConfigKey(key), value ) } } // Convert config property key to java constant style private def toConfigKey(String key) { return key.replaceAll("(\\.)|(-)", "_") .toUpperCase() } // Parse configuration value type private def parseValueType(String value) { if (value == null) { throw new NullPointerException("Missing configuration value") } if (value =~ "[0-9]*L" ) { return "Long" } if (value.isInteger()) { return "Integer" } if (value.isFloat()) { return "Float" } if ("true" == value.toLowerCase() || "false" == value.toLowerCase()) { return "Boolean" } return "String" } private def getProperties(String variantName) { def propertiesPath = String.format( Constants.CONFIG_PROPERTY_PATTERN, variantName ) def propertiesFile = rootProject.file(propertiesPath) def properties = new Properties() // Do nothing, when configuration file doesn't exists if (propertiesFile.exists()) { properties.load(new FileInputStream(propertiesFile)) } return properties } ```
وهنا في الحال نشأت تلك الصعوبات التي لم أفكر فيها - فوجًا متربًا - قررت "بيع" قراري لزملائي. أعددت رصيفًا ، ورفعت الأمر للمناقشة ، و ... أدركت أننا جميعًا أناس ، والمبرمجون أناس كسالى. لا أحد يريد تضمين قطعة من الشفرة غير معروفة له في المشروع ، فهل هناك حاجة لدراستها ، وقراءتها من أجل الخير؟ ماذا لو كان لا يعمل؟ ماذا لو كان يفعل شيئا خطأ آخر؟ هذا رائع ، لكنني لا أعرفه وليس من الواضح كيفية العمل معه. وقد انتقل بالفعل سيناريو إلى Kotlin لفترة طويلة ، وأنا لا أستطيع ميناء من الأخاديد ، وهلم جرا.
الشيء الأكثر إثارة للاهتمام هو أن كل هذه الأحكام جاءت بالفعل مني ، لأنه أدركت أن هذا التكامل للحل لا يناسبني. بالإضافة إلى ذلك ، لاحظت بعض النقاط التي أود حقًا تحسينها. بعد تنفيذ الحل في المشروع أ ، أود دعمه في المشروع ب. هناك طريقة واحدة فقط للخروج - تحتاج إلى كتابة مكون إضافي.
وما هي المشاكل التي يحلها المكوّن الإضافي وتسليمه عن بُعد للمستخدم؟
- مشكلة مبرمج كسول. نحن كسولون للغاية بحيث لا يمكن الخوض في جذر المشكلة والطرق الممكنة لحلها. من الأسهل بالنسبة لنا أن نأخذ شيئًا تم تنفيذه بالفعل قبل استخدامه.
- دعم. ويشمل دعم الكود وتطويره وتوسيع الفرص. عند حل مشكلتي ، قمت بحل بيئات probrosvarivnyh فقط في الكود فقط ، متناسين تمامًا عن إمكانية إعادة التوجيه إلى الموارد.
- جودة الرمز. هناك رأي مفاده أن بعض المطورين لا ينظرون حتى إلى شفرة مفتوحة المصدر لا تغطيها الاختبارات. إنه عام 2019 ، ويمكننا توصيل الخدمات بسهولة لتتبع جودة الكود https://sonarcloud.io أو https://codecov.io/
- التكوين. يفرض امتداد ملف البناء على فحص هذا الرمز وإجراء التغييرات يدويًا. في حالتي ، لا أحتاج دائمًا إلى استخدام التكوين لأنواع buildTypes أو productFlavors ، فأنا أريد شيئًا واحدًا أو الكل مرة واحدة.
- تنظيف الجرف المتربة. وأخيراً قمت بتنظيف أحدهم وتمكنت من مواصلة هذا القرار في غرفتي الصغيرة.
لن أخوض في التفاصيل والمشاكل عند كتابة المكوّن الإضافي ، فهو يدور حول موضوع جديد. يمكنك اتخاذ قرار بتكامله أو اقتراح فكرتك أو تقديم مساهمتك
هنا