Firebase Remote Config هي خدمة سحابية لإدارة معلمات تطبيقات الجوال، تتيح تغيير سلوكها ومظهرها ومحتواها دون نشر نسخة جديدة في متجر التطبيقات. على عكس النهج التقليدي بدورات الإصدار، تتيح Remote Config تغيير أي معلمات قابلة للتخصيص في الوقت الفعلي عبر وحدة تحكم Firebase أو REST API. وفقًا لـ Google Firebase (2026)، تُستخدم الخدمة في 65% من التطبيقات على منصة Firebase لاختبارات A/B والتخصيص والإدارة التشغيلية للميزات على جانب العميل.
الرئيسية
Firebase Remote Config هي خدمة تخزن أزواج مفتاح-قيمة على جانب خادم Firebase وتوصلها إلى أجهزة العميل عند الطلب أو وفقًا لجدول زمني. لكل معلمة اسم (سلسلة نصية)، وقيمة (سلسلة نصية، رقم، منطقي أو JSON) ويمكن ربطها بشروط — قواعد تحدد القيمة التي يحصل عليها مستخدم معين. يمكن للشروط التحقق من إصدار التطبيق، ولغة الجهاز، والمنطقة، والنسبة المئوية العشوائية والعديد من السمات الأخرى.
بنية Remote Config مبنية على نموذج دفع-سحب مع أولوية السحب. يطلب العميل بشكل دوري القيم الحالية من الخادم (افتراضيًا كل 12 ساعة). ومع ذلك، يمكن للمطور بدء مزامنة فورية في الكود أو عبر وحدة تحكم Firebase (زر “Publish changes”). بعد نشر التغييرات، يرسل الخادم إشعار دفع عبر Firebase Cloud Messaging، ويمكن للتطبيق عند استلامه إعادة طلب المعلمات.
الباقة المجانية لـ Firebase Remote Config ليس لها حدود على عدد المعلمات أو الطلبات، مما يميزها عن خدمات Firebase الأخرى. القيد الوحيد هو أن حجم الاستجابة يجب ألا يتجاوز 800 كيلوبايت (إجمالاً لجميع المعلمات). هذا أكثر من كافٍ للسيناريو النموذجي: معظم المشاريع تستخدم 10–50 معلمة، ونادرًا ما يتجاوز حجمها الإجمالي 100 كيلوبايت.
آلية اختيار القيمة تعتمد على أولوية الشروط. كل شرط يمثل قاعدة (مثل “إصدار iOS > 15.0”). تتحقق Remote Config من الشروط بترتيب أولوياتها وتعيد قيمة أول شرط مطابق. إذا لم ينطبق أي شرط، يتم استخدام القيمة الافتراضية. تتيح هذه الآلية إنشاء تسلسل هرمي للقواعد: من الأكثر تحديدًا إلى الأكثر عمومية.
مهم: ترتيب الشروط في وحدة تحكم Firebase مهم. إذا كان شرطان يمكن أن ينطبقا على مستخدم واحد في الوقت نفسه، يفوز الشرط الأعلى في القائمة. يُنصح بوضع الشروط الأكثر تحديدًا (مثل لإصدار معين من التطبيق) فوق الشروط العامة (مثل “جميع مستخدمي iOS”). الترتيب غير الصحيح قد يؤدي إلى عدم تطبيق تغيير مستهدف أبدًا.
افتراضيًا، Remote Config تخزن مؤقتًا القيم المستلمة من الخادم لمدة 12 ساعة. هذا يعني أنه بعد نشر التغييرات في وحدة التحكم، سيرى التطبيق التغييرات في موعد لا يتجاوز 12 ساعة (أو بعد استدعاء fetch صريح تالي). يمكن تعيين الحد الأدنى لوقت التخزين المؤقت عبر FirebaseRemoteConfigSettings(minimumFetchIntervalInSeconds: 3600) — للإنتاج يُنصح بساعة واحدة على الأقل لتجنب الطلبات المفرطة للخادم واستهلاك بيانات المستخدم.
لـ اختبار التغييرات أثناء التطوير، استخدم الحد الأدنى للفاصل الزمني 0 ثانية: FirebaseRemoteConfigSettings(minimumFetchIntervalInSeconds: 0). في هذا الوضع، كل استدعاء fetch سيقوم بتحميل القيم الحالية من الخادم. من المهم عدم نسيان العودة إلى فاصل الإنتاج قبل الإصدار، وإلا فإن كل تشغيل للتطبيق سيتصل بالخادم، مما يزيد التكاليف واستهلاك البطارية.
معلمة Remote Config هي متغير مسمى يمكن أن يأخذ قيمة من عدة قيم حسب الشروط. أنواع القيم: سلسلة نصية، رقم (double)، منطقي، كائن JSON (سلسلة مسلسلة). معلمات JSON مناسبة لنقل البيانات المهيكلة دون إنشاء العديد من المعلمات المنفصلة: على سبيل المثال، كائن بإعدادات سمة التطبيق (primaryColor، backgroundColor، fontSize).
الشروط هي قواعد منطقية تتحقق من سمات المستخدم أو الجهاز: إصدار نظام التشغيل (iOS، Android)، إصدار التطبيق، البلد، اللغة، جمهور المستخدم (خاصية محددة في الكود)، النسبة المئوية العشوائية (لاختبارات A/B). يمكن دمج الشروط عبر AND المنطقي: على سبيل المثال، “إصدار التطبيق >= 5.0” AND “البلد = روسيا”. يمكن أن تحتوي كل معلمة على عدد غير محدود من الشروط، لكن عمليًا يُستخدم 2–5.
لـ التخصيص، استخدم خصائص المستخدم (user properties) — سمات تُعين في كود التطبيق عبر Firebase Analytics. على سبيل المثال، analytics.setUserProperty(“subscription_tier”, “premium”). يمكن لـ Remote Config التحقق من هذه الخاصية وإرجاع قيم خاصة لمستخدمي premium. التخصيص عبر Remote Config لا يتطلب إنشاء شروط على جانب العميل — كل المنطق يتركز في وحدة التحكم السحابية.
| نوع الشرط | مثال | السيناريو |
|---|---|---|
| إصدار نظام التشغيل | iOS >= 16.0 | تفعيل ميزة جديدة فقط لإصدارات iOS الجديدة |
| إصدار التطبيق | app_version >= 3.2 | إظهار لافتة تحديث للإصدارات القديمة |
| البلد | country == “JP” | تخصيص المحتوى لليابان |
| النسبة المئوية العشوائية | 10% من المستخدمين | اختبار A/B لـ 10% من الجمهور |
| خاصية المستخدم | tier == “premium” | تفعيل الميزات المميزة |
Remote Config تدعم نموذجين للتقسيم: استنادًا إلى السمات (الشروط) واستنادًا إلى خصائص Firebase Analytics (خصائص المستخدم). النموذج الأول ثابت: يتحقق الشرط من سمة ثابتة لا تتغير خلال جلسة أو إصدار التطبيق. النموذج الثاني ديناميكي: يمكن تعيين خاصية في أي وقت أثناء تشغيل التطبيق، مما يسمح بتقسيم مرن للمستخدمين في وقت التشغيل.
مهم: لاستخدام خصائص المستخدم في Remote Config، يجب دمج Firebase Analytics. يرجع هذا المطلب إلى أن Remote Config تتلقى بيانات المستخدم من Analytics SDK. بدون Analytics، تعمل Remote Config فقط مع سمات الجهاز (إصدار نظام التشغيل، إصدار التطبيق، البلد من IP). التخصيص استنادًا إلى سلوك المستخدم (مثل “أجرى 5 عمليات شراء”) متاح فقط عبر Analytics.
قالب Remote Config هو المجموعة الكاملة لجميع المعلمات والشروط وقيمها. تخزن Firebase سجل تغييرات القالب وتسمح بالعودة إلى أي إصدار سابق خلال 90 يومًا. إصدار القالب مهم بشكل حاسم: إذا تم اكتشاف خطأ بعد نشر التغييرات (مثل قيمة معلمة غير صحيحة تعطل واجهة المستخدم)، يمكن العودة فورًا إلى إصدار سابق عامل عبر وحدة تحكم Firebase.
كل تغيير في القالب (نشر) ينشئ إصدارًا جديدًا برقم فريد. توفر وحدة تحكم Firebase سجل تغييرات مع الوقت والمستخدم والوصف (إذا تم ملؤه). يُنصح دائمًا بإضافة وصف للنشر: “تفعيل الخلاصة الجديدة لنظام iOS مجموعة اختبار 10%”. بدون وصف، بعد شهر سيكون من المستحيل تذكر ما تم تغييره بالضبط في الإصدار 42.
دمج Remote Config يتكون من ثلاث خطوات: تهيئة SDK مع الإعدادات (وقت التخزين المؤقت)، تعريف المعلمات الافتراضية (قيم في حالة عدم توفر الخادم)، ومنطق تطبيق القيم المستلمة. المعلمات الافتراضية هي شبكة أمان في حالة عدم تمكن الجهاز من الاتصال بـ Firebase (لا يوجد إنترنت، الخادم غير متاح). بدون قيم افتراضية، سيستخدم التطبيق null، مما قد يؤدي إلى أعطال.
تعريف القيم الافتراضية يتم بطريقتين: برمجيًا عبر setDefaultsAsync أو من خلال ملف XML. الطريقة البرمجية مناسبة للمشاريع الصغيرة: يتم تعيين جميع القيم مباشرة في الكود مرة واحدة عند بدء التطبيق. الطريقة الملفية مفضلة للمشاريع ذات العشرات من المعلمات: يتم تخزين القيم في الموارد ويمكن تحريرها بسهولة دون إعادة ترجمة. يُنصح بالجمع: الإعدادات الأساسية في XML، والإعدادات المحددة برمجيًا.
عدم التزامن هو ميزة رئيسية لـ SDK Remote Config. تقوم طريقة fetchAndActivate() بتنفيذ طلب إلى الخادم في خلفية دون حظر واجهة المستخدم. بعد اكتمال التحميل، يحدث التنشيط — يتم تحديث قيم المعلمات في ذاكرة التطبيق. استخدم المستمعين أو coroutines (في Android/Kotlin) لتتبع الاكتمال. يجب ألا يرى المستخدم “قفزات” في واجهة المستخدم عند تحديث المعلمات — يجب تطبيق جميع التغييرات بسلاسة.
عند التشغيل الأول، SDK Remote Config لا يمنع تهيئة التطبيق. أثناء حدوث المزامنة، يستخدم التطبيق القيم الافتراضية. هذا يعني أن المستخدم قد يرى إصدار الواجهة القديم عند التشغيل الأول، وبعد اكتمال fetch — الجديد. للمعلمات الحرجة (مثل serverUrl، التي تعتمد عليها قابلية التشغيل)، استخدم التنشيط المتزامن مع انتظار النتيجة.
ممارسة موصى بها: عرض شاشة تحميل مع تأخير بسيط إذا كان التطبيق بحاجة حرجة للحصول على المعلمات الحالية قبل عرض الشاشة الأولى. على شاشة التحميل، قم بتشغيل fetchAndActivate مع مهلة 5 ثوانٍ. إذا لم يتم تحميل المعلمات خلال 5 ثوانٍ، يبدأ التطبيق بالقيم الافتراضية. هذا يمنع الانتظار اللانهائي عند عدم وجود إنترنت.
معلمات JSON في Remote Config تسمح بنقل البيانات المهيكلة كقيمة واحدة. على سبيل المثال، كائن بأنماط السمة: {“primaryColor”: “#6200EE”, “borderRadius”: 8, “fontFamily”: “Roboto”}. على جانب العميل، يتم تحليل JSON وتطبيقه على واجهة المستخدم. المزايا: معلمة واحدة بدلاً من ثلاث، تحديث ذري (يتم تحديث الحقول الثلاثة في وقت واحد)، وحدة تحكم نظيفة. العيب: صعوبة القراءة في وحدة تحكم Firebase (يتم عرض JSON كسلسلة نصية).
توصية: استخدم معلمات JSON لمجموعات القيم المترابطة منطقيًا التي يتم تحديثها معًا (السمات، تكوين الشاشة، إعدادات الشبكة). للمعلمات المستقلة (feature toggle، serverUrl)، استخدم معلمات سلسلة نصية أو منطقية منفصلة — فهي أسهل في القراءة في وحدة التحكم وأسهل لتتبع التغييرات في سجل إصدارات القالب.
اختبارات A/B هي ميزة مدمجة في Firebase Remote Config تتيح تقسيم المستخدمين إلى مجموعات، وتعيين قيم معلمات مختلفة لكل مجموعة، وقياس تأثير التغييرات على المقاييس المختارة. على عكس التقسيم اليدوي عبر الشروط مع random_percent، فإن التكامل مع Firebase Analytics يجمع تلقائيًا إحصائيات لكل مجموعة تجريبية ويظهر الأهمية الإحصائية للاختلافات.
عملية اختبار A/B: ينشئ المطور تجربة في وحدة تحكم Firebase (قسم A/B Testing)، ويختار معلمة Remote Config، ويحدد قيمًا للمجموعتين الضابطة والتجريبية، ويحدد المقياس المستهدف (مثل معدل التحويل أو الإيرادات). توزع Firebase المستخدمين تلقائيًا على المجموعات، وتجمع البيانات، وبعد 2–4 أسابيع تظهر النتيجة مع القيمة p. يمكن إيقاف التجربة مبكرًا إذا كانت النتيجة حاسمة.
الأهمية الإحصائية هي المعيار الرئيسي لإيقاف التجربة. يستخدم Firebase A/B Testing نهج التكرار ويظهر القيمة p لكل مقياس. العتبة القياسية للأهمية هي 0.05 (احتمال ثقة 95%). عند الوصول إلى هذه العتبة لصالح إحدى المجموعات، توصي Firebase بإيقاف التجربة وتطبيق التغييرات على جميع المستخدمين. إذا لم يتم الوصول إلى الأهمية بعد 4 أسابيع، تعتبر التجربة غير حاسمة.
Firebase A/B Testing يدعم نوعين من التجارب: A/B الكلاسيكي (مقارنة قيمتين لمعلمة واحدة) و A/B/n متعدد المتغيرات (مقارنة ثلاث قيم أو أكثر). تتطلب الاختبارات متعددة المتغيرات عددًا أكبر من المستخدمين لتحقيق الأهمية الإحصائية. يُنصح باستخدام A/B/n فقط للمعلمات ذات 3–5 متغيرات، حيث يختلف كل متغير جوهريًا عن الآخرين.
مدة التجربة تعتمد على حجم حركة المرور: للتطبيقات ذات 1000 مستخدم نشط يوميًا، الحد الأدنى للمدة هو أسبوعان؛ للتطبيقات ذات 100,000 مستخدم، 3–5 أيام. تحسب Firebase تلقائيًا الوقت اللازم وتحذر إذا كانت حركة المرور الحالية غير كافية لاكتشاف الاختلافات المهمة. مهم: لا توقف التجربة قبل الوقت المقدر، حتى لو بدت النتيجة واضحة — هذا هو خطأ “peeking” الكلاسيكي.
المقاييس المستهدفة في Firebase A/B Testing تُعين بناءً على أحداث Firebase Analytics. المقاييس القياسية متاحة: المستخدمون النشطون يوميًا، الإيرادات، معدل التحويل، الاحتفاظ، تفاعل المستخدم. يمكن أيضًا إنشاء مقياس مخصص بناءً على أي حدث Analytics مع معلمات إضافية. على سبيل المثال، مقياس “نسبة المستخدمين الذين وصلوا إلى شاشة الدفع” يُنشأ من حدث screen_view مع المعلمة screen_name = “payment”.
يُنصح باختيار مقياس أساسي واحد يُتخذ بناءً عليه قرار نجاح التجربة، و 2–3 مقاييس ثانوية للتحليل الإضافي. اختيار عدة مقاييس أساسية يزيد من خطر النتيجة الإيجابية الكاذبة (مشكلة المقارنات المتعددة). إذا كان المقياس الأساسي المختار لا يُظهر تحسنًا ذا دلالة إحصائية، تعتبر التجربة غير ناجحة، حتى لو تحسنت المقاييس الثانوية.
دعونا نلقي نظرة على دمج Remote Config في تطبيق Android بلغة Kotlin. تتضمن الأمثلة تهيئة SDK مع وقت تخزين مؤقت مخصص، والحصول على معلمات من أنواع مختلفة، وتنفيذ شرط A/B على جانب العميل، ومعالجة الأخطاء عند عدم توفر الخادم. يتم تشغيل كل الكود في النشاط الرئيسي أو فئة Application بحيث تكون المعلمات متاحة من بداية التطبيق.
قبل الاستخدام، أضف التبعية: implementation(“com.google.firebase:firebase-config”) عبر Firebase BOM. تأكد من أن Firebase Analytics متصل أيضًا، حيث تستخدم Remote Config Analytics لتمرير خصائص المستخدم.
المثال الأول هو الإعداد الأساسي لـ Remote Config مع حد أدنى لفاصل fetch قدره ساعة واحدة للإنتاج. تتم تهيئة SDK في طريقة onCreate لفئة Application. بعد fetchAndActivate، يتم التحقق من قيمة المعلمة welcome_message، التي يمكن تغييرها عن بُعد لشاشة الترحيب.
class MainApp : Application() {
override fun onCreate() {
super.onCreate()
val remoteConfig = Firebase.remoteConfig
val settings = FirebaseRemoteConfigSettings.Builder()
.setMinimumFetchIntervalInSeconds(3600)
.build()
remoteConfig.setConfigSettingsAsync(settings)
remoteConfig.setDefaultsAsync(
R.xml.remote_config_defaults
)
remoteConfig.fetchAndActivate()
.addOnCompleteListener { task ->
if (task.isSuccessful) {
val welcomeMsg = remoteConfig
.getString("welcome_message")
Log.d("RemoteConfig", welcomeMsg)
}
}
}
}
في المثال، setDefaultsAsync يقوم بتحميل القيم الافتراضية من ملف XML res/xml/remote_config_defaults.xml. إذا فشل fetch (لا توجد شبكة، الخادم غير متاح)، سيستخدم التطبيق هذه القيم. يحتوي ملف XML على نفس أسماء المعلمات الموجودة في وحدة تحكم Firebase: <entry key=“welcome_message”>مرحبًا بك!</entry>. يُنصح دائمًا بوجود قيم افتراضية لجميع معلمات Remote Config.
المثال الثاني هو feature toggle (علامة ميزة). المعلمة new_checkout_enabled من نوع منطقي. إذا كانت true، يعرض التطبيق شاشة الدفع الجديدة؛ إذا كانت false، القديمة. Feature toggle هو السيناريو الأكثر شيوعًا لـ Remote Config: التغيير يؤثر فقط على معلمة واحدة، لا يتطلب تعديل المنطق ويمكن التراجع عنه فورًا.
fun isFeatureEnabled(paramName: String): Boolean {
return Firebase.remoteConfig
.getBoolean(paramName)
}
// الاستخدام في activity
if (isFeatureEnabled("new_checkout_enabled")) {
navigateToNewCheckout()
} else {
navigateToLegacyCheckout()
}
الدالة isFeatureEnabled تغلف الوصول إلى Remote Config ويمكن اختبارها بسهولة عبر mock. لـ feature toggles، يُنصح باستخدام اصطلاح تسمية: البادئة feature_ أو ff_ أو flag_ بحيث يكون الغرض من المعلمة واضحًا فورًا في وحدة تحكم Firebase. مثال: feature_new_onboarding، ff_dark_mode، flag_v3_api. لا تستخدم معلمات العلامات للتفعيل/التعطيل لأكثر من 3 أشهر — تراكم العلامات الميتة يعقد الصيانة.
المثال الثالث هو الحصول على معلمة JSON مع إعدادات سمة التطبيق. تحتوي المعلمة app_theme على كائن JSON مع primaryColor و borderRadius و fontFamily. على جانب العميل، يتم تحليل JSON باستخدام Gson أو kotlinx.serialization، ويتم تطبيق القيم على واجهة المستخدم. هذا النهج يسمح للمصممين بتغيير سمة التطبيق دون مشاركة المطور وبدون إصدار.
data class AppTheme(
val primaryColor: String = "#6200EE",
val borderRadius: Int = 8,
val fontFamily: String = "Roboto"
)
fun getAppTheme(): AppTheme {
val json = Firebase.remoteConfig
.getString("app_theme")
return Gson().fromJson(json, AppTheme::class.java)
}
العمل مع JSON يتطلب عناية: إذا كان JSON في وحدة تحكم Firebase غير صحيح (مثل فقدان فاصلة)، سيفشل التحليل وسيتلقى التطبيق قيمًا افتراضية بدلاً من السمة الحالية. يُنصح بالتحقق من صحة سلاسل JSON قبل النشر عبر مدقق JSON. للإنتاج، أضف try-catch أثناء التحليل وسجل الأخطاء عبر Firebase Crashlytics.
Firebase Remote Config أداة قوية، لكن عند استخدامها بشكل غير صحيح قد تؤدي إلى مشاكل في الأداء وقابلية توقع السلوك والأمان. دعنا نستعرض الممارسات الرئيسية التي ستساعد في تجنب الأخطاء الشائعة عند العمل مع الخدمة، والقيود التي يجب مراعاتها عند تصميم بنية التطبيق.
تجنب البيانات الحساسة — Remote Config غير مصممة لتخزين الأسرار (مفاتيح API، الرموز المميزة، كلمات المرور). جميع قيم المعلمات متاحة لكود العميل ويمكن استخراجها من ذاكرة التطبيق. للبيانات السرية، استخدم Cloud Functions مع التحقق من جانب الخادم أو Secret Manager. قم بتخزين المعلمات العامة فقط في Remote Config: النصوص، العلامات، إعدادات واجهة المستخدم، URLs لنقاط النهاية العامة.
اختبر كل تغيير قبل النشر على الجمهور بأكمله. استخدم اختبار A/B أو النشر على نسبة مئوية صغيرة (1–5% من المستخدمين) للتحقق من أن القيمة الجديدة لا تسبب أعطالًا أو لا تكسر العرض. Remote Config ليس لديها بيئة اختبارية — يتم نشر جميع التغييرات في الإنتاج فورًا. الطريقة الوحيدة للنشر الآمن هي الطرح التدريجي.
قيود المنصة: الحد الأقصى لعدد المعلمات — 2000 (لجميع الأنواع)، الحد الأقصى لحجم القيمة الواحدة — 256 كيلوبايت، الحجم الإجمالي لاستجابة الخادم — 800 كيلوبايت. عدد خصائص المستخدم التي يمكن استخدامها في Remote Config محدود بـ 25. الحد الأدنى لفاصل fetch هو 0 ثانية (لتصحيح الأخطاء)، لكن الإفراط في الاستخدام قد يؤدي إلى تجاوز حصة Cloud Functions (30,000 طلب في الدقيقة لكل مشروع).
الأسئلة الشائعة
نعم، عند عدم وجود شبكة، يستخدم Remote Config القيم الافتراضية المحددة في الكود أو في ملف XML. بعد استعادة الاتصال، سيقوم SDK تلقائيًا بتنفيذ fetch عند الاستدعاء التالي أو عند انتهاء فترة التخزين المؤقت. لن يتعطل التطبيق أبدًا بسبب غياب Remote Config إذا تم تعيين القيم الافتراضية بشكل صحيح.
افتراضيًا — حتى 12 ساعة (فترة التخزين المؤقت). للتسريع، استخدم إشعار FCM عبر زر “Publish changes” في وحدة التحكم: يتلقى التطبيق رسالة وينفذ fetch فورًا. يمكن تعيين الحد الأدنى لفاصل fetch للتسريع عبر minimumFetchIntervalInSeconds.
مجانًا — حتى 2000 معلمة لكل مشروع، طلبات غير محدودة على خطة Spark. حد 2000 معلمة مرن: Firebase لا تمنع إنشاء معلمات جديدة، لكن الأداء قد ينخفض. للمشاريع ذات آلاف المعلمات، يُنصح باستخدام معلمات JSON المهيكلة.
نعم، Firebase Remote Config لديها إضافة رسمية لـ Flutter: firebase_remote_config. API يطابق تمامًا SDKs الأصلية لنظامي Android و iOS. تدعم الإضافة جميع أنواع المعلمات، fetchAndActivate، مستمعي التغييرات والتكامل مع Firebase Analytics لاختبارات A/B.
Firebase Feature Flags هي خدمة منفصلة لإدارة الميزات مع دعم الجماهير المستهدفة والتجارب. Remote Config هي خدمة أكثر عمومية لأي معلمات، بما في ذلك feature toggles. توفر Feature Flags واجهة مستخدم مخصصة وتكامل مع Cloud Run، لكن Remote Config تبقى الأداة الرئيسية لمعظم السيناريوهات.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا