.xcconfig هو ملف تكوين Xcode بتنسيق "مفتاح=قيمة" يدير بشكل مركزي Build Settings للمشروع. بدلاً من تغيير المعلمات يدوياً في واجهة Xcode لكل تكوين، يصفها المطورون في ملف نصي يمكن إصداره وإعادة استخدامه بين المشاريع. وفقاً Apple Developer Documentation, 2025، فإن استخدام .xcconfig يقلل وقت إعداد المشروع بنسبة 70% ويزيل التناقضات في التكوين بين المطورين. يمكن لملفات .xcconfig أن ترث بعضها البعض، مكونة سلسلة من التكوينات.
النقاط الرئيسية
.xcconfig (ملف تكوين Xcode) هو ملف نصي عادي يحتوي على Build Settings بتنسيق PARAMETER_NAME = value. تستخدم ملفات .xcconfig للإدارة المركزية لتكوينات بناء Xcode: فهي تحل محل التحرير اليدوي للحقول في واجهة Build Settings. كل .xcconfig مرتبط بـ Build Configuration (Debug، Release) أو بالمشروع ككل ويمكنه تجاوز أي build setting: SWIFT_VERSION، IPHONEOS_DEPLOYMENT_TARGET، PRODUCT_BUNDLE_IDENTIFIER، CODE_SIGN_STYLE، PROVISIONING_PROFILE_SPECIFIER.
قبل ظهور .xcconfig، كانت إعدادات البناء تُخزن فقط في project.pbxproj — ملف ثنائي/plist يصعب قراءته في الفروقات (diff) ولا يمكن التعليق عليه. حل .xcconfig هذه المشكلة: يمكن للمطورين التعليق على المعلمات، وتجميعها حسب المعنى، وإنشاء ملفات قابلة للإصدار لبيئات مختلفة، وتوريث المعلمات بين الملفات. جعل هذا .xcconfig المعيار الفعلي لإدارة التكوينات في مشاريع iOS.
توجد ملفات .xcconfig داخل المشروع، عادة في مجلد Configurations/ أو BuildConfig/. كل ملف يتوافق مع Build Configuration واحدة: Debug.xcconfig، Release.xcconfig، Staging.xcconfig. بالإضافة إلى ذلك، يتم إنشاء ملف Shared.xcconfig مشترك، يتم تضمينه في جميع التكوينات عبر #include. يتيح ذلك تعريف المعلمات المشتركة مرة واحدة وتجاوز المعلمات المحددة في ملفات التكوين.
سهولة قراءة الفروقات: تظهر التغييرات في .xcconfig في Git diff كأسطر عادية. على عكس project.pbxproj، حيث يؤدي تغيير ترتيب الحقول إلى إظهار 50 سطراً من التغييرات عند تعديل معلمة واحدة. التعليقات: في .xcconfig يمكنك شرح سبب الحاجة إلى كل معلمة. التوريث: يمكنك إنشاء تكوين أساسي بإعدادات مشتركة وتجاوز فقط المعلمات الضرورية لـ Debug وRelease.
بناء جملة .xcconfig بسيط قدر الإمكان: كل سطر هو معلمة، اسم وقيمة مفصولة بعلامة يساوي. يتم تجاهل المسافات حول =. يمكن أن تحتوي القيم على متغيرات بتنسيق $(VARIABLE_NAME) أو ${VARIABLE_NAME}. تبدأ التعليقات بـ // أو # وتستمر حتى نهاية السطر. تستمر الأسطر في السطر التالي باستخدام شرطة مائلة عكسية \. يتم تجاهل الأسطر الفارغة.
يمكن للمتغيرات في .xcconfig أن تشير إلى متغيرات أخرى، مما ينشئ قيمًا مركبة. على سبيل المثال: PRODUCT_NAME = MyApp، PRODUCT_BUNDLE_IDENTIFIER = com.example.$(PRODUCT_NAME). يقوم Xcode بتقييم القيمة في وقت البناء، باستبدال القيم الفعلية للمتغيرات. يدعم AGP أيضاً متغيرات النظام: ARCHS، SDK_NAME، CONFIGURATION، PLATFORM_NAME، التي يتم تعيينها بواسطة بيئة البناء.
للتكوين الشرطي، تُستخدم توجيهات المنصة بين قوسين مربعين: PARAMETER[sdk=iphoneos*] = value. على سبيل المثال، SUPPORTED_PLATFORMS[sdk=iphoneos*] = iphoneos يحدد المعلمة فقط لبناءات iOS. يتم دعم أحرف البدل: * (أي أحرف)، ? (حرف واحد). تسمح التوجيهات الشرطية بوجود .xcconfig واحد لمنصات متعددة وتعيين قيم مختلفة لـ iOS وmacOS في ملف واحد.
// Shared.xcconfig — إعدادات المشروع المشتركة
SWIFT_VERSION = 5.0
IPHONEOS_DEPLOYMENT_TARGET = 16.0
SDKROOT = iphoneos
TARGETED_DEVICE_FAMILY = 1,2
// معرف الحزمة — يتم تجميعه من البادئة والاسم
BUNDLE_ID_PREFIX = com.example
PRODUCT_NAME = MyApp
PRODUCT_BUNDLE_IDENTIFIER = $(BUNDLE_ID_PREFIX).$(PRODUCT_NAME)
// إعداد شرطي لـ macOS
SUPPORTED_PLATFORMS[sdk=macosx*] = macosx
PRODUCT_BUNDLE_IDENTIFIER[sdk=macosx*] = $(BUNDLE_ID_PREFIX).$(PRODUCT_NAME).mac
// إصدار
MARKETING_VERSION = 2.4.1
CURRENT_PROJECT_VERSION = 37
#include هو توجيه معالج مسبق لـ .xcconfig يقوم بتضمين محتويات ملف .xcconfig آخر. يمكن تداخل التوجيهات: يمكن لـ Shared.xcconfig أن #include "Base.xcconfig"، ويمكن لـ Debug.xcconfig أن #include "Shared.xcconfig". تسمح سلسلة التوريث ببناء تسلسل هرمي للتكوينات، حيث يتجاوز كل مستوى معلمات المستوى السابق. يعمل #include على مبدأ آخر كتابة: إذا تم تعريف نفس المعلمة في كل من الملف المضمن والملف الرئيسي، فإن القيمة من الملف الرئيسي لها الأولوية.
التسلسل الهرمي الصحيح لمشروع iOS نموذجي: Base.xcconfig (المعلمات الأكثر شيوعاً) ← Shared.xcconfig (إعدادات المشروع) ← Debug.xcconfig أو Release.xcconfig. يحدد Base.xcconfig المعايير (SWIFT_VERSION، DEPLOYMENT_TARGET)، Shared.xcconfig — خصائص المشروع (PRODUCT_NAME، PREPROCESSOR_DEFINITIONS)، Debug/Release — البيئة (DEBUG_INFORMATION_FORMAT، OPTIMIZATION_CFLAGS). لا يسمح #include بالدورات — سيقوم Xcode بإظهار خطأ عند اكتشاف تبعية دائرية.
مثال: Config/Base.xcconfig ← Config/iOS/Shared.xcconfig ← Config/iOS/Debug.xcconfig. يسمح هذا الهيكل بإعادة استخدام Base لمشاريع iOS وmacOS وtvOS، وShared فقط لـ iOS. ملاحظة: يستخدم #include اسم ملف أو مسار نسبي من موقع .xcconfig الجذر. لا يُنصح باستخدام المسارات المطلقة — فهي تكسر البناء على الأجهزة الأخرى وفي CI/CD.
// --- Config/Base.xcconfig ---
SWIFT_VERSION = 5.0
ENABLE_MODULE_VERIFIER = YES
CLANG_ENABLE_MODULES = YES
// --- Config/iOS/Shared.xcconfig ---
#include "../Base.xcconfig"
IPHONEOS_DEPLOYMENT_TARGET = 16.0
PRODUCT_BUNDLE_IDENTIFIER = com.example.myapp
// --- Config/iOS/Debug.xcconfig ---
#include "Shared.xcconfig"
OPTIMIZATION_CFLAGS = -O0
DEBUG_INFORMATION_FORMAT = dwarf
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG
ENABLE_TESTABILITY = YES
// --- Config/iOS/Release.xcconfig ---
#include "Shared.xcconfig"
OPTIMIZATION_CFLAGS = -Osize
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
SWIFT_COMPILATION_MODE = wholemodule
يتم ربط .xcconfig بالمشروع في Project Info ← Configurations. لكل Build Configuration (Debug، Release، AdHoc)، يتم اختيار .xcconfig المقابل من القائمة المنسدلة "Based on Configuration File". إذا كان التكوين غير مرتبط بملف، يستخدم Xcode القيم من project.pbxproj. بعد اختيار .xcconfig، تصبح جميع المعلمات من الملف نشطة لذلك التكوين.
من المهم التمييز بين التكوينات على مستوى المشروع وعلى مستوى الهدف. يحدد .xcconfig على مستوى المشروع المعلمات الافتراضية لجميع الأهداف. يقوم .xcconfig على مستوى الهدف بتجاوزها لهدف معين. إذا لم يتم تعيين معلمة في .xcconfig على مستوى الهدف، يتم استخدام القيمة من مستوى المشروع. إذا لم يتم تعيينها هناك أيضاً، يتم استخدام القيمة من project.pbxproj. قاعدة عملية: ضع المعلمات المشتركة (البناء، الإصدارات) في مستوى المشروع، وخصائص الهدف (معرف الحزمة، التزويد) في مستوى الهدف.
في حالة التعارض بين .xcconfig و UI Build Settings، تكون الأولوية للقيمة من الواجهة (تتجاوز .xcconfig). قد يؤدي هذا إلى ارتباك: يغير المطور Build Setting في الواجهة دون أن يدرك أن .xcconfig يحدد قيمة مختلفة. يُنصح بالانتقال الكامل إلى .xcconfig وعدم لمس UI Build Settings. للتحقق من المعلمة المطبقة، استخدم xcrun xcodebuild -showBuildSettings — سيعرض الأمر القيم النهائية لجميع المعلمات بعد حل جميع المستويات.
تأمل تكويناً ثلاثي المستويات: Dev (تطوير محلي)، Staging (خادم اختبار)، Production (إصدار). يتم إنشاء .xcconfig منفصل لكل بيئة، يحدد قيماً مختلفة لـ API_URL والتسجيل والشهادات. يستخدم Dev localhost، ويستخدم Staging staging.api.example.com، ويستخدم Production api.example.com. جميعها ترث Shared.xcconfig المشترك عبر #include.
المعلمة الرئيسية التي تختلف بين البيئات هي PRODUCT_BUNDLE_IDENTIFIER. لـ Dev: com.example.myapp.dev، لـ Staging: com.example.myapp.staging، لـ Production: com.example.myapp. تسمح معرفات الحزم المختلفة بتثبيت الإصدارات الثلاثة على جهاز واحد في وقت واحد. تختلف أيضاً CODE_SIGN_IDENTITY (Apple Development لـ Dev، Apple Distribution لـ Production) وPROVISIONING_PROFILE_SPECIFIER.
لنقل القيم إلى الكود، يُستخدم INFOPLIST_PREFIX_HEADER أو OTHER_SWIFT_FLAGS مع معالج -D. لا يحتوي Swift على معالج مسبق، لذلك تُستخدم Active Compilation Conditions: SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEV. في الكود: #if DEV; #elseif STAGING; #else; #endif. لـ Objective-C يُستخدم GCC_PREPROCESSOR_DEFINITIONS. يتيح ذلك تجميع كود مختلف لبيئات مختلفة دون تغيير الملفات المصدر.
// --- Config/Dev.xcconfig ---
#include "Shared.xcconfig"
PRODUCT_BUNDLE_IDENTIFIER = $(BUNDLE_ID_PREFIX).$(PRODUCT_NAME).dev
CODE_SIGN_IDENTITY = Apple Development
PROVISIONING_PROFILE_SPECIFIER = Dev Profile
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG DEV
OTHER_SWIFT_FLAGS = -D DEV
// عنوان API عبر Info.plist — يتم استبدال القيمة
API_BASE_URL = http://localhost:3000/api
// --- Config/Staging.xcconfig ---
#include "Shared.xcconfig"
PRODUCT_BUNDLE_IDENTIFIER = $(BUNDLE_ID_PREFIX).$(PRODUCT_NAME).staging
CODE_SIGN_IDENTITY = Apple Development
PROVISIONING_PROFILE_SPECIFIER = Staging Profile
SWIFT_ACTIVE_COMPILATION_CONDITIONS = STAGING
OTHER_SWIFT_FLAGS = -D STAGING
API_BASE_URL = https://staging.api.example.com/v2
// --- Config/Production.xcconfig ---
#include "Shared.xcconfig"
PRODUCT_BUNDLE_IDENTIFIER = $(BUNDLE_ID_PREFIX).$(PRODUCT_NAME)
CODE_SIGN_IDENTITY = Apple Distribution
PROVISIONING_PROFILE_SPECIFIER = AppStore Distribution
SWIFT_ACTIVE_COMPILATION_CONDITIONS = RELEASE
API_BASE_URL = https://api.example.com/v3
يمكن نقل القيم من .xcconfig إلى Info.plist عبر المتغيرات $(PARAMETER_NAME). إذا تم تعريف معلمة في .xcconfig (مثلاً API_BASE_URL)، يمكن استخدامها في Info.plist: <key>ApiBaseUrl</key><string>$(API_BASE_URL)</string>. في وقت البناء، يستبدل Xcode $(API_BASE_URL) بالقيمة من .xcconfig. يتيح ذلك تكوين التطبيق دون تغيير الكود —只需 تبديل المخطط.
يجب أن تكون معلمات .xcconfig المستخدمة في Info.plist عامة — فهي تنتهي في الملف الثنائي وتكون مرئية في التطبيق المفكك. لا تستخدم .xcconfig للقيم السرية (الرموز، كلمات المرور) — استخدم خدمات مثل Firebase Remote Config التي تعمل على الخادم. .xcconfig لـ Info.plist مناسب لـ: URLs الخوادم، أسماء الكيانات، معرفات المتتبعات، feature flags.
الوصول إلى قيم Info.plist في الكود: Bundle.main.object(forInfoDictionaryKey: "ApiBaseUrl") لـ Objective-C/Swift. إذا تم تعيين القيمة عبر .xcconfig، سيتم استبدالها وستكون متاحة في Bundle main.infoDictionary. هذه الطريقة أفضل من BuildConfigField (كما في Android)، لأن Info.plist هي آلية iOS قياسية وقيمها متاحة لجميع مكونات النظام، بما في ذلك extensions وwidgets وSiri Intents.
الأسئلة الشائعة
User-Defined Setting هو معلمة مخصصة تمت إضافتها عبر UI Build Settings. تعمل بنفس طريقة .xcconfig، لكن لا يمكن إصدارها أو التعليق عليها أو إعادة استخدامها بين المشاريع. .xcconfig هو ملف على القرص، User-Defined Setting هو إدخال في project.pbxproj.
نعم، يقوم CocoaPods بإنشاء ملفات Pods-*.xcconfig لكل تكوين. تحتوي هذه الملفات على إعدادات لتوصيل البودات. يتم ربط Pods.xcconfig تلقائياً بـ .xcconfig الخاص بك عبر #include في ملف المولد. لا تقم بتحرير Pods.xcconfig يدوياً — يتم استبداله أثناء pod install.
عبر Info.plist: حدد معلمة في .xcconfig واستخدم $(PARAM) في Info.plist. في الكود: Bundle.main.infoDictionary["PARAM"]. للأعلام المعالجة مسبقاً، استخدم SWIFT_ACTIVE_COMPILATION_CONDITIONS و #if CONDITION.
الأسباب: قمت بتغيير القيمة في UI Build Settings (الواجهة تتجاوز .xcconfig)؛ الملف غير مرتبط بالتكوين (تحقق من Project ← Info ← Configurations)؛ مسار #include غير صحيح؛ خطأ إملائي في اسم المعلمة. التشخيص: xcodebuild -showBuildSettings سيعرض جميع المعلمات النشطة.
نعم، .xcconfig لا يعتمد على إطار عمل الواجهة. لمشاريع SwiftUI، .xcconfig مفيد بنفس القدر: إدارة معرف الحزمة، الإصدارات، تكوينات البيئة، SWIFT_ACTIVE_COMPILATION_CONDITIONS لأعلام الميزات. لا يوفر SwiftUI بديلاً لـ .xcconfig، لذلك يُنصح باستخدامه مع أي مشروع.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.