CallKit เป็นเฟรมเวิร์กของ Apple ที่ช่วยให้แอปพลิเคชัน VoIP สามารถแสดงสายเรียกเข้าและสายออกในอินเทอร์เฟซโทรศัพท์ของระบบ iOS รวมถึงหน้าจอล็อก นักพัฒนาได้รับการควบคุมมาตรฐาน — การรับสาย การปฏิเสธ การวางสายรอ — โดยไม่ต้องสร้างอินเทอร์เฟซผู้ใช้ของตนเอง ตาม Apple Developer Documentation, 2026 เฟรมเวิร์กประมวลผลการโทร VoIP ได้ถึง 98% ผ่านอินเทอร์เฟซระบบเดียว ซึ่งช่วยขจัดการกระจายตัวของประสบการณ์ผู้ใช้ระหว่างแอปส่งข้อความและการสื่อสารต่างๆ
ประเด็นสำคัญ
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 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ