[UIKit] CallKit

Junyoung Park·2022년 12월 24일
0

UIKit

목록 보기
127/142
post-thumbnail
post-custom-banner

Intro to CallKit on iOS (Swift) – 2023

CallKit

구현 목표

  • 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
    }
}
  • 뷰 컨트롤러의 버튼을 통해 전화 서비스 클래스의 함수 사용

구현 화면

profile
JUST DO IT
post-custom-banner

0개의 댓글