CallKit هو إطار عمل من Apple يسمح لتطبيقات VoIP بعرض المكالمات الواردة والصادرة في واجهة هاتف النظام في iOS، بما في ذلك شاشة القفل. يحصل المطور على عناصر تحكم قياسية — الرد، الرفض، تعليق المكالمة — دون الحاجة إلى إنشاء واجهة مستخدم خاصة به. وفقًا لوثائق Apple Developer، 2026، يعالج الإطار 98% من مكالمات VoIP من خلال واجهة نظام واحدة، مما يلغي تجزئة تجربة المستخدم بين مختلف تطبيقات المراسلة والاتصالات.
النقاط الرئيسية
CallKit هو إطار عمل من Apple تم تقديمه في iOS 10 يوفر واجهة برمجية لدمج تطبيقات VoIP مع تطبيق الهاتف النظامي. قبل CallKit، كان كل تطبيق VoIP يعرض المكالمات الواردة في واجهة المستخدم الخاصة به — كان المستخدم يرى إشعارًا من التطبيق ولكنه لم يستطع الرد بطريقة نظامية. CallKit يوحد هذه التجربة: تظهر المكالمة VoIP الواردة كمكالمة هاتفية عادية مع نفس عناصر التحكم.
الهدف الرئيسي لـ CallKit هو إزالة تجزئة تجربة المستخدم. عندما يستخدم التطبيق CallKit، تظهر المكالمة على شاشة القفل، في سجل المكالمات، وفي قائمة المكالمات الأخيرة لتطبيق الهاتف النظامي. يمكن للمستخدم الرد أو الرفض أو إرسال المكالمة إلى البريد الصوتي بإيماءات مألوفة — دون التفكير في أي تطبيق يعالج المكالمة.
وفقًا لجلسة Apple WWDC 2023 «What’s new in CallKit»، أكثر من 85% من المستخدمين يفضلون التطبيقات مع دمج CallKit على تلك التي تستخدم واجهة المستخدم الخاصة بها للمكالمات. السبب هو الاتساق والقدرة على التنبؤ بعناصر التحكم النظامية التي لا تتطلب تعلمًا.
بدون CallKit، يتم تسليم مكالمة VoIP الواردة عبر إشعار push قياسي. يرى المستخدم لافتة، ينقر عليها، ينتظر فتح التطبيق، وعندها فقط يرى شاشة المكالمة. CallKit مع PushKit يقلص هذا المسار إلى الصفر: تظهر المكالمة فوريًا، حتى إذا كان التطبيق لا يعمل، وتكون واجهة النظام جاهزة للرد في أجزاء من الثانية.
هندسة CallKit مبنية حول فئتين رئيسيتين — CXProvider وCXCallController، اللتان تنفذان نمط المزود-العميل. يقوم المزود بإدارة المكالمة من جانب النظام، بينما يبدأ العميل الإجراءات نيابة عن المستخدم أو التطبيق. يضمن هذا الفصل أن واجهة النظام تظل دائمًا متسقة، حتى إذا كان التطبيق غير متاح مؤقتًا.
CXProvider هو الكائن المركزي الذي يسجل التطبيق في CallKit كمزود مكالمات. يتم تكوينه عبر CXProviderConfiguration، حيث يتم تحديد أيقونة التطبيق، أنواع المكالمات المدعومة (صوت، فيديو)، والحد الأقصى للمجموعات المتزامنة. يتلقى المزود طلبات الإجراءات من النظام ويرسلها إلى التطبيق عبر CXProviderDelegate.
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 هو كائن العميل الذي يطلب من خلاله التطبيق إجراءات على المكالمات: بدء، إنهاء، تعليق، تبديل. يتم إرسال الطلبات إلى CallKit عبر CXTransaction، الذي يحتوي على مصفوفة من كائنات CXAction. يتحقق CallKit من صحة كل إجراء وينفذه إذا كان مسموحًا به في الحالة الحالية.
let controller = CXCallController()
let startCallAction = CXStartCallAction(
callUUID: UUID(),
handle: CXHandle(type: .phoneNumber, value: "+15551234567")
)
startCallAction.isVideo = true
controller.request(CXTransaction(action: startCallAction))
يتلقى مفوض المزود جميع الأحداث من CallKit. الطريقة الحرجة هي providerDidBegin، التي تشير إلى بدء المكالمة. في provider:performAnswerCallAction، يجب على التطبيق بدء جلسة صوتية: تنشيط AVAudioSession وبدء نقل الوسائط. إذا لم ينشط التطبيق جلسة الصوت خلال وقت محدود، سينهي CallKit المكالمة.
PushKit هو مكون إلزامي لتسليم مكالمات VoIP الواردة إلى CallKit. إشعارات push العادية (APNs) لها زمن وصول غير متوقع ولا تضمن التسليم إذا كان التطبيق في الخلفية. يستخدم PushKit اتصال TCP مستمر مع خوادم Apple للتسليم الفوري لإشعارات VoIP، وهو أمر بالغ الأهمية للمكالمات في الوقت الفعلي.
سير العمل: يرسل الخادم إشعار VoIP عبر PushKit → يتلقاه التطبيق في pushRegistry:didReceiveIncomingPushWithPayload → يعرض التطبيق فورًا المكالمة الواردة عبر CXProvider → يعرض CallKit شاشة المكالمة النظامية. كل شيء يحدث في أجزاء من الثانية، ويرى المستخدم المكالمة في نفس وقت وصولها إلى الخادم.
بدءًا من iOS 13، فرضت Apple قيدًا: يجب استخدام إشعارات VoIP فقط للإشارة إلى المكالمات الواردة. استخدام PushKit لتحميل البيانات في الخلفية أو تحديث المحتوى محظور — قد يتم رفض هذه التطبيقات أثناء المراجعة. هذا التغيير جعل نظام VoIP أكثر قابلية للتنبؤ، حيث أن جميع إشعارات PushKit مضمونة الآن لتكون مرتبطة بالمكالمات.
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 هو امتداد تطبيق يسمح للتطبيق بتزويد النظام بقوائم الأرقام للتحديد (عرض اسم المتصل) والحظر. يعمل الامتداد بشكل مستقل عن التطبيق الرئيسي: يقوم النظام بتحميل البيانات من الامتداد عند التنشيط، ويتم تنفيذ جميع العمليات اللاحقة دون مشاركة التطبيق، مما يوفر الموارد ويعزز الأمان.
يستخدم الامتداد CXCallDirectoryManager لإدارة البيانات. يضيف التطبيق عبر العملية الرئيسية الأرقام إلى قاعدة بيانات الامتداد، ثم يستدعي reloadExtension لتحديث ذاكرة التخزين المؤقت للنظام. توصي Apple بتحديث البيانات ليس أكثر من مرة واحدة في الساعة لتجنب التحميل غير الضروري على النظام.
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 إعداد ثلاثة مكونات: تكوين المزود، معالجة المكالمات الواردة عبر PushKit، وإدارة جلسة الصوت. أدناه مثال عملي أدنى يعالج مكالمة VoIP واردة، ويعرضها عبر CallKit، وينشط الصوت.
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 متاح على 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 ممكن فقط على جهاز فعلي.
| الوظيفة | iOS | iPadOS | macOS |
|---|---|---|---|
| شاشة مكالمة النظام | ملء الشاشة | لافتة | لافتة |
| شاشة القفل | نعم | لا | لا |
| CarPlay | نعم | لا | لا |
| دليل المكالمات | نعم | نعم | لا |
| سجل الأخيرة | نعم | نعم | نعم |
الأسئلة الشائعة
نعم، للمكالمات الواردة PushKit إلزامي. فقط PushKit يضمن التسليم الفوري لإشعارات VoIP لتطبيق نائم أو مغلق، وهو أمر بالغ الأهمية لعرض المكالمة في الوقت المناسب عبر CallKit.
نعم، CallKit يدعم الصوت والفيديو. عند تكوين CXProvider، حدد supportsVideo = true، وفي CXStartCallAction عيّن isVideo = true. سيعرض النظام أيقونة كاميرا الفيديو بشكل صحيح في واجهة المكالمة.
بأي حال — CallKit لا يعمل على المحاكي. للاختبار، استخدم جهاز iOS أو iPadOS فعلي. على macOS، يمكن الاختبار على Mac حقيقي بميكروفون.
نعم، كل تطبيق يسجل CXProvider الخاص به. يعالج النظام بشكل صحيح المكالمات من تطبيقات مختلفة ويعرضها كمكالمات منفصلة في الأخيرة. يمكن للمستخدم رؤية من أي تطبيق جاءت المكالمة.
سينهي CallKit المكالمة تلقائيًا بعد وقت محدود إذا لم ينشط التطبيق جلسة الصوت. يعمل المؤقت لضمان عدم بقاء النظام في حالة مكالمة بدون تدفق صوتي حقيقي.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.