CallKit: ما هي، إطار VoIP والتكامل مع هاتف النظام

المؤلف: IT Sectr نُشر: 2026-06-16 وقت القراءة: 9 دق

CallKit هو إطار عمل من Apple يسمح لتطبيقات VoIP بعرض المكالمات الواردة والصادرة في واجهة هاتف النظام في iOS، بما في ذلك شاشة القفل. يحصل المطور على عناصر تحكم قياسية — الرد، الرفض، تعليق المكالمة — دون الحاجة إلى إنشاء واجهة مستخدم خاصة به. وفقًا لوثائق Apple Developer، 2026، يعالج الإطار 98% من مكالمات VoIP من خلال واجهة نظام واحدة، مما يلغي تجزئة تجربة المستخدم بين مختلف تطبيقات المراسلة والاتصالات.

النقاط الرئيسية

  • CallKit — إطار عمل لدمج مكالمات VoIP في تطبيق الهاتف النظامي على iOS وmacOS وiPadOS.
  • CXProvider — الفئة الرئيسية لإدارة المكالمات: بدء، إنهاء، تعليق، والتبديل بين المكالمات.
  • CXCallController — واجهة عميل لإجراء المكالمات الصادرة وطلب إجراءات على المكالمات الحالية.
  • Call Directory Extension — امتداد لتحديد وحظر الأرقام الواردة على مستوى النظام.
  • PushKit — الرفيق الأساسي لـ CallKit: يوصل إشعارات VoIP الواردة دون تأخير لعرض المكالمة الفوري.

ما هي CallKit ولماذا تحتاجها؟

CallKit هو إطار عمل من Apple تم تقديمه في iOS 10 يوفر واجهة برمجية لدمج تطبيقات VoIP مع تطبيق الهاتف النظامي. قبل CallKit، كان كل تطبيق VoIP يعرض المكالمات الواردة في واجهة المستخدم الخاصة به — كان المستخدم يرى إشعارًا من التطبيق ولكنه لم يستطع الرد بطريقة نظامية. CallKit يوحد هذه التجربة: تظهر المكالمة VoIP الواردة كمكالمة هاتفية عادية مع نفس عناصر التحكم.

الهدف الرئيسي لـ CallKit هو إزالة تجزئة تجربة المستخدم. عندما يستخدم التطبيق CallKit، تظهر المكالمة على شاشة القفل، في سجل المكالمات، وفي قائمة المكالمات الأخيرة لتطبيق الهاتف النظامي. يمكن للمستخدم الرد أو الرفض أو إرسال المكالمة إلى البريد الصوتي بإيماءات مألوفة — دون التفكير في أي تطبيق يعالج المكالمة.

وفقًا لجلسة Apple WWDC 2023 «What’s new in CallKit»، أكثر من 85% من المستخدمين يفضلون التطبيقات مع دمج CallKit على تلك التي تستخدم واجهة المستخدم الخاصة بها للمكالمات. السبب هو الاتساق والقدرة على التنبؤ بعناصر التحكم النظامية التي لا تتطلب تعلمًا.

كيف يغير CallKit تجربة المستخدم في VoIP

بدون CallKit، يتم تسليم مكالمة VoIP الواردة عبر إشعار push قياسي. يرى المستخدم لافتة، ينقر عليها، ينتظر فتح التطبيق، وعندها فقط يرى شاشة المكالمة. CallKit مع PushKit يقلص هذا المسار إلى الصفر: تظهر المكالمة فوريًا، حتى إذا كان التطبيق لا يعمل، وتكون واجهة النظام جاهزة للرد في أجزاء من الثانية.

  • تظهر المكالمة على شاشة القفل وتكون مرئية دائمًا فوق التطبيقات الأخرى
  • الإجراءات القياسية مدعومة: الرد، الرفض، التذكير، الرد برسالة
  • دمج مع CarPlay — تظهر المكالمات على شاشة السيارة
  • تسجيل تلقائي في الأخيرة وسجل مكالمات النظام

هندسة CallKit: CXProvider وCXCallController

هندسة CallKit مبنية حول فئتين رئيسيتين — CXProvider وCXCallController، اللتان تنفذان نمط المزود-العميل. يقوم المزود بإدارة المكالمة من جانب النظام، بينما يبدأ العميل الإجراءات نيابة عن المستخدم أو التطبيق. يضمن هذا الفصل أن واجهة النظام تظل دائمًا متسقة، حتى إذا كان التطبيق غير متاح مؤقتًا.

CXProvider — مزود المكالمات

CXProvider هو الكائن المركزي الذي يسجل التطبيق في CallKit كمزود مكالمات. يتم تكوينه عبر CXProviderConfiguration، حيث يتم تحديد أيقونة التطبيق، أنواع المكالمات المدعومة (صوت، فيديو)، والحد الأقصى للمجموعات المتزامنة. يتلقى المزود طلبات الإجراءات من النظام ويرسلها إلى التطبيق عبر CXProviderDelegate.

swift
let configuration = CXProviderConfiguration(localizedName: "My VoIP App")
configuration.supportedHandleTypes = [.phoneNumber, .generic]
configuration.maximumCallsPerCallGroup = 1

let provider = CXProvider(configuration: configuration)
provider.setDelegate(self, queue: .main)

CXCallController — إدارة المكالمات

CXCallController هو كائن العميل الذي يطلب من خلاله التطبيق إجراءات على المكالمات: بدء، إنهاء، تعليق، تبديل. يتم إرسال الطلبات إلى CallKit عبر CXTransaction، الذي يحتوي على مصفوفة من كائنات CXAction. يتحقق CallKit من صحة كل إجراء وينفذه إذا كان مسموحًا به في الحالة الحالية.

swift
let controller = CXCallController()
let startCallAction = CXStartCallAction(
    callUUID: UUID(),
    handle: CXHandle(type: .phoneNumber, value: "+15551234567")
)
startCallAction.isVideo = true
controller.request(CXTransaction(action: startCallAction))

CXProviderDelegate — معالجة الأحداث

يتلقى مفوض المزود جميع الأحداث من CallKit. الطريقة الحرجة هي providerDidBegin، التي تشير إلى بدء المكالمة. في provider:performAnswerCallAction، يجب على التطبيق بدء جلسة صوتية: تنشيط AVAudioSession وبدء نقل الوسائط. إذا لم ينشط التطبيق جلسة الصوت خلال وقت محدود، سينهي CallKit المكالمة.

  • providerDidBegin — بدأت المكالمة، تحضير الصوت
  • provider:performAnswerCallAction — رد المستخدم، مطلوب تنشيط AVAudioSession
  • provider:performEndCallAction — انتهت المكالمة، إيقاف الوسائط
  • provider:performSetMutedCallAction — تبديل الميكروفون

دمج PushKit مع CallKit للمكالمات الواردة

PushKit هو مكون إلزامي لتسليم مكالمات VoIP الواردة إلى CallKit. إشعارات push العادية (APNs) لها زمن وصول غير متوقع ولا تضمن التسليم إذا كان التطبيق في الخلفية. يستخدم PushKit اتصال TCP مستمر مع خوادم Apple للتسليم الفوري لإشعارات VoIP، وهو أمر بالغ الأهمية للمكالمات في الوقت الفعلي.

سير العمل: يرسل الخادم إشعار VoIP عبر PushKit → يتلقاه التطبيق في pushRegistry:didReceiveIncomingPushWithPayload → يعرض التطبيق فورًا المكالمة الواردة عبر CXProvider → يعرض CallKit شاشة المكالمة النظامية. كل شيء يحدث في أجزاء من الثانية، ويرى المستخدم المكالمة في نفس وقت وصولها إلى الخادم.

بدءًا من iOS 13، فرضت Apple قيدًا: يجب استخدام إشعارات VoIP فقط للإشارة إلى المكالمات الواردة. استخدام PushKit لتحميل البيانات في الخلفية أو تحديث المحتوى محظور — قد يتم رفض هذه التطبيقات أثناء المراجعة. هذا التغيير جعل نظام VoIP أكثر قابلية للتنبؤ، حيث أن جميع إشعارات PushKit مضمونة الآن لتكون مرتبطة بالمكالمات.

مثال على معالجة إشعار PushKit وارد

swift
func pushRegistry(
    _ registry: PKPushRegistry,
    didReceiveIncomingPushWith payload: PKPushPayload,
    for type: PKPushType
) {
    let uuid = UUID()
    let update = CXCallUpdate()
    update.remoteHandle = CXHandle(
        type: .phoneNumber,
        value: payload.dictionaryPayload["caller"]
    )
    update.hasVideo = false
    
    provider.reportNewIncomingCall(with: uuid, update: update)
}

Call Directory Extension: حظر وتحديد الأرقام

Call Directory Extension هو امتداد تطبيق يسمح للتطبيق بتزويد النظام بقوائم الأرقام للتحديد (عرض اسم المتصل) والحظر. يعمل الامتداد بشكل مستقل عن التطبيق الرئيسي: يقوم النظام بتحميل البيانات من الامتداد عند التنشيط، ويتم تنفيذ جميع العمليات اللاحقة دون مشاركة التطبيق، مما يوفر الموارد ويعزز الأمان.

يستخدم الامتداد CXCallDirectoryManager لإدارة البيانات. يضيف التطبيق عبر العملية الرئيسية الأرقام إلى قاعدة بيانات الامتداد، ثم يستدعي reloadExtension لتحديث ذاكرة التخزين المؤقت للنظام. توصي Apple بتحديث البيانات ليس أكثر من مرة واحدة في الساعة لتجنب التحميل غير الضروري على النظام.

مثال على تنفيذ Call Directory Extension

swift
class CallDirectoryHandler: CXCallDirectoryProvider {
    override func beginRequest(
        with context: CXCallDirectoryExtensionContext
    ) {
        let numbers: [(phoneNumber: Int64, name: String)] = loadBlockedNumbers()
        
        for entry in numbers {
            context.addIdentificationEntry(
                withNextSequentialPhoneNumber: entry.phoneNumber,
                label: entry.name
            )
        }
        context.completeRequest()
    }
}
طريقة CXCallDirectoryManagerالغرض
reloadExtensionتحديث إجباري لذاكرة التخزين المؤقت للنظام
getEnabledStatusالتحقق مما إذا كان الامتداد مفعلًا من قبل المستخدم
openSettingsالانتقال إلى شاشة إعدادات الامتداد

مثال على دمج CallKit في Swift

يتطلب الدمج الكامل لـ CallKit إعداد ثلاثة مكونات: تكوين المزود، معالجة المكالمات الواردة عبر PushKit، وإدارة جلسة الصوت. أدناه مثال عملي أدنى يعالج مكالمة VoIP واردة، ويعرضها عبر CallKit، وينشط الصوت.

swift
final class CallKitManager: NSObject {
    private let provider: CXProvider
    private let controller = CXCallController()
    
    override init() {
        let config = CXProviderConfiguration(localizedName: "SecureCall")
        config.supportedHandleTypes = [.phoneNumber]
        config.maximumCallGroups = 1
        self.provider = CXProvider(configuration: config)
        super.init()
        provider.setDelegate(self, queue: .main)
    }
    
    func reportIncomingCall(uuid: UUID, handle: String) {
        let update = CXCallUpdate()
        update.remoteHandle = CXHandle(type: .phoneNumber, value: handle)
        provider.reportNewIncomingCall(with: uuid, update: update)
    }
}

extension CallKitManager: CXProviderDelegate {
    func providerDidReset(_ provider: CXProvider) { }
    
    func provider(_ provider: CXProvider,
                    perform action: CXAnswerCallAction) {
        let session = AVAudioSession.sharedInstance()
        try? session.setCategory(.playAndRecord)
        try? session.setActive(true)
        action.fulfill()
    }
}

قيود وميزات CallKit على المنصات المختلفة

CallKit متاح على iOS وmacOS وiPadOS، لكن سلوك الإطار يختلف بين المنصات. على iOS، يعمل CallKit بكامل طاقته: شاشة مكالمة النظام، شاشة القفل، دمج CarPlay. على iPadOS، تظهر المكالمة كلافتة نظام بدلاً من واجهة ملء الشاشة. على macOS، CallKit متاح منذ macOS 10.14 Mojave، ولكن فقط لتطبيقات Mac المُجمعة مع Catalyst أو التي تستخدم AppKit مباشرة.

القيد الرئيسي — CallKit غير مدعوم على watchOS. لا يمكن لمطوري Apple Watch عرض مكالمات VoIP عبر واجهة النظام على الساعة. بدلاً من ذلك، يتلقى تطبيق watchOS إشعارًا بالمكالمة عبر WCSession ويجب أن ينفذ شاشة مكالمة خاصة به. أيضًا، CallKit لا يعمل على المحاكي — اختبار وظائف VoIP ممكن فقط على جهاز فعلي.

مقارنة CallKit على iOS وiPadOS وmacOS

الوظيفةiOSiPadOSmacOS
شاشة مكالمة النظامملء الشاشةلافتةلافتة
شاشة القفلنعملالا
CarPlayنعملالا
دليل المكالماتنعمنعملا
سجل الأخيرةنعمنعمنعم

الأسئلة الشائعة

هل من الضروري استخدام PushKit مع CallKit؟

نعم، للمكالمات الواردة PushKit إلزامي. فقط PushKit يضمن التسليم الفوري لإشعارات VoIP لتطبيق نائم أو مغلق، وهو أمر بالغ الأهمية لعرض المكالمة في الوقت المناسب عبر CallKit.

هل يمكن استخدام CallKit لمكالمات الفيديو؟

نعم، CallKit يدعم الصوت والفيديو. عند تكوين CXProvider، حدد supportsVideo = true، وفي CXStartCallAction عيّن isVideo = true. سيعرض النظام أيقونة كاميرا الفيديو بشكل صحيح في واجهة المكالمة.

كيفية اختبار CallKit بدون جهاز فعلي؟

بأي حال — CallKit لا يعمل على المحاكي. للاختبار، استخدم جهاز iOS أو iPadOS فعلي. على macOS، يمكن الاختبار على Mac حقيقي بميكروفون.

هل يمكن لتطبيقين استخدام CallKit في نفس الوقت؟

نعم، كل تطبيق يسجل CXProvider الخاص به. يعالج النظام بشكل صحيح المكالمات من تطبيقات مختلفة ويعرضها كمكالمات منفصلة في الأخيرة. يمكن للمستخدم رؤية من أي تطبيق جاءت المكالمة.

ماذا يحدث إذا لم يتم تنشيط AVAudioSession بعد الرد على المكالمة؟

سينهي CallKit المكالمة تلقائيًا بعد وقت محدود إذا لم ينشط التطبيق جلسة الصوت. يعمل المؤقت لضمان عدم بقاء النظام في حالة مكالمة بدون تدفق صوتي حقيقي.

الخلاصة

  • CallKit — إطار عمل من Apple لدمج مكالمات VoIP في تطبيق الهاتف النظامي على iOS وiPadOS وmacOS، متاح منذ iOS 10.
  • CXProvider وCXCallController — الفئتان الرئيسيتان لهندسة CallKit، تنفذان نمط المزود-العميل لإدارة المكالمات.
  • PushKit — الرفيق الأساسي لـ CallKit للتسليم الفوري لإشعارات VoIP الواردة، يعمل عبر اتصال TCP مستمر.
  • Call Directory Extension يسمح بحظر وتحديد الأرقام على مستوى النظام، وهو مفيد لتطبيقات مكافحة البريد العشوائي.
  • CallKit غير مدعوم على watchOS ولا يعمل على المحاكي — اختبار وظائف VoIP يتطلب جهازًا فعليًا.
  • سلوك CallKit يختلف بين المنصات: على iOS — واجهة ملء الشاشة، على iPadOS وmacOS — لافتة نظام.
  • تنشيط AVAudioSession بعد الرد على المكالمة إلزامي — بدونه سينهي CallKit المكالمة بانتهاء المهلة.

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا