iOS 개발 노트
🪴CallKit과 Intents 연동으로 iPhone 통화 기록에서 자동 발신 처리 구현 본문
iPhone 기본 통화 앱에 수신/발신 통화 기록이 남게되는데, 해당 기록을 선택했을 때 전화를 자동 발신하는 기능을 구현하는 방법이다.
먼저 IntentHandler 클래스를 구현한다.
해당 클래스는 INExtension & INStartCallIntentHandling 프로토콜을 준수함으로써, 전화 걸기 요청에 대한 핸들링을 수행하는 책임을 갖게 된다.
import Intents
final class IntentHandler: INExtension, INStartCallIntentHandling {
}handle 메서드 내부에서는 INStartCallIntentResponse 객체를 클로저로 전달하는 처리를 해주면 된다.
intent.contacts?.first?.personHandle에는 실제 전화번호 혹은 이메일 주소 정보가 포함된 전화를 발신할 상대방에 대한 정보가 담겨 있는데, 이 값이 없을 경우에는 failure에 대한 INStartCallIntentResponse를 반환하여 에러 핸들링을 해준다.
import Intents
final class IntentHandler: INExtension, INStartCallIntentHandling {
// If your app targets to iOS 13.0, you can remove above method and `INStartAudioCallIntentHandling` protocol
func handle(intent: INStartCallIntent, completion: @escaping (INStartCallIntentResponse) -> Void) {
let response: INStartCallIntentResponse
guard intent.contacts?.first?.personHandle != nil else {
response = INStartCallIntentResponse(code: .failure, userActivity: nil)
completion(response)
return
}
let userActivity = NSUserActivity(activityType: String(describing: INStartCallIntent.self))
response = INStartCallIntentResponse(code: .continueInApp, userActivity: userActivity)
completion(response)
}
}그럼 이제 앞서 IntentHandler 클래스에서 handle 처리에 대한 응답값은 어디서 받을 수 있을까?
그건 바로 SceneDelegate의 scene(\_: willConnectTo: options:) 메서드 내부에서 받을 수 있다.
import UIKit
import Intents
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let userActivity = connectionOptions.userActivities.first {
}
}
}userActivity.interaction.intent를 INStartCallIntent 타입으로 캐스팅한다.
intent에서는 calleeID와 음성 통화인지 영상 통화인지에 대한 여부 값을 추출할 수 있다.
그러면 이제 추출한 값과 CallKit을 통해 상대방한테 전화 발신을 할 수 있다.
if let userActivity = connectionOptions.userActivities.first,
let interaction = userActivity.interaction,
let intent = interaction.intent as? INStartCallIntent {
// 1. 연락 대상자 추출
if let person = intent.contacts?.first {
let calleeID = person.personHandle?.value ?? "" // ex. 전화번호 또는 이메일
let displayName = person.displayName // ex. Siri에서 인식한 이름
print("calleeID:", calleeID ?? "nil")
print("displayName:", displayName ?? "nil")
// 2. 영상 통화 여부
let hasVideo: Bool = intent.callCapability == .videoCall
print("hasVideo:", hasVideo)
// 3. CallKit을 통해 전화 발신하기
CXCallManager.shared.startCall(calleeID: calleeID, hasVideo: hasVideo)
}
}CallKit을 이용해 전화 발신에 대한 참고 코드:
import CallKit
class CXCallManager: NSObject {
static let shared = CXCallManager()
private override init() { }
private let callController = CXCallController()
func startCall(calleeID: String, hasVideo: Bool) {
let uuid = UUID()
let handle = CXHandle(type: .generic, value: calleeID)
let startCallAction = CXStartCallAction(call: uuid, handle: handle)
startCallAction.isVideo = hasVideo
let transaction = CXTransaction(action: startCallAction)
callController.request(transaction) { error in
if let error = error {
print("❌ 통화 요청 실패:", error.localizedDescription)
} else {
print("✅ 통화 요청 성공")
}
}
}
}'iOS' 카테고리의 다른 글
| 🪴AppStoreConnect ITMS-90725: SDK version issue (0) | 2026.01.31 |
|---|---|
| 🪴클로저를 사용해 이전 화면에 데이터 전달하기 (0) | 2023.09.19 |
| 🪴ImageView의 ContentMode (0) | 2023.06.14 |
| 🪴StackView의 Alignment/Distribution/Spacing (0) | 2023.06.08 |