Intro to CallKit on iOS (Swift) – 2023
CallKit
구현 목표
구현 태스크
- 전화 걸기 함수 구현
- 전화 받기 함수 구현
- 버튼 UI 전화 로직 연결
핵심 코드
private let provider = CXProvider(configuration: CXProviderConfiguration())
private let callController = CXCallController()
- 싱글턴 함수에서 프라이빗으로 선언된 프로바이더 및 컨트롤러
- 전화 서비스를 주관
public func reportIncomingCall(id: UUID, handle: String) {
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .generic, value: handle)
provider.reportNewIncomingCall(with: id, update: update) { error in
guard error == nil else { return }
print("Call")
}
}
UUID
, hanldle
을 파라마티로 받아 CXCallUpdate
값을 구성
- 프로바디어에게 새로운 전화가 걸려 왔음을
id
, update
를 통해 reportNewIncomingCall
로 넘겨주면 해당 클로저에서 전화가 왔음을 캐치
public func startCall(id: UUID, handle: String) {
let handle = CXHandle(type: .generic, value: handle)
let startCallAction = CXStartCallAction(call: id, handle: handle)
let transaction = CXTransaction(action: startCallAction)
callController.request(transaction) { error in
guard error == nil else { return }
print("Start Call")
}
}
- 전화 연결을 시작하는 함수
- 전화 수신과 마찬가지로
UUID
, handle
을 통해 형성한 변수를 통해 트랜젝션 구성
callController
에게 해당 트랜젝션을 던져준 뒤 나오는 클로저를 통해 전화 송신에 성공했음을 캐치
소스 코드
import CallKit
final class CallManager: NSObject {
static let shared = CallManager()
private let provider = CXProvider(configuration: CXProviderConfiguration())
private let callController = CXCallController()
private override init() {
super.init()
provider.setDelegate(self, queue: nil)
}
public func reportIncomingCall(id: UUID, handle: String) {
let update = CXCallUpdate()
update.remoteHandle = CXHandle(type: .generic, value: handle)
provider.reportNewIncomingCall(with: id, update: update) { error in
guard error == nil else { return }
print("Call")
}
}
public func startCall(id: UUID, handle: String) {
let handle = CXHandle(type: .generic, value: handle)
let startCallAction = CXStartCallAction(call: id, handle: handle)
let transaction = CXTransaction(action: startCallAction)
callController.request(transaction) { error in
guard error == nil else { return }
print("Start Call")
}
}
}
extension CallManager: CXProviderDelegate {
func providerDidReset(_ provider: CXProvider) {
}
}
CallKit
을 임포트한 뒤 해당 CXProvider
, CXCallController
를 통해 전화 연결 기능 구현
- UUID, 표현할 이름을 담을 문자열을 통해
CXHandle
을 생성, 해당 핸들을 통해 새로운 전화를 받거나 연결
final class CallKitViewController: UIViewController {
private let callManager = CallManager.shared
private lazy var callButon: UIButton = {
let button = UIButton()
var config = UIButton.Configuration.filled()
config.title = "Call"
config.image = UIImage(systemName: "phone.arrow.up.right")
config.imagePlacement = .top
config.baseBackgroundColor = .systemGreen
config.baseForegroundColor = .white
button.configuration = config
button.addTarget(self, action: #selector(didTapCall), for: .touchUpInside)
return button
}()
private lazy var receiveButton: UIButton = {
let button = UIButton()
var config = UIButton.Configuration.filled()
config.title = "Receive"
config.image = UIImage(systemName: "phone.arrow.down.left")
config.imagePlacement = .top
config.baseBackgroundColor = .systemGreen
config.baseForegroundColor = .white
button.configuration = config
button.addTarget(self, action: #selector(didTapCall), for: .touchUpInside)
return button
}()
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
callButon.frame = CGRect(x: 0, y: 0, width: 100, height: 50)
callButon.center = view.center
receiveButton.frame = CGRect(x: callButon.frame.origin.x, y: callButon.frame.origin.y + 70, width: 100, height: 50)
}
override func viewDidLoad() {
super.viewDidLoad()
setUI()
}
@objc private func didTapCall() {
let id = UUID()
let handle = "Pikachu"
callManager.startCall(id: id, handle: handle)
}
@objc private func didTapReceive() {
let id = UUID()
let handle = "Pikachu"
callManager.reportIncomingCall(id: id, handle: handle)
}
private func setUI() {
view.backgroundColor = .systemBackground
view.addSubview(callButon)
view.addSubview(receiveButton)
title = "CallKit"
navigationItem.largeTitleDisplayMode = .always
navigationController?.navigationBar.prefersLargeTitles = true
}
}
- 뷰 컨트롤러의 버튼을 통해 전화 서비스 클래스의 함수 사용
구현 화면