º Pushkit
- PushKit 프레임워크 는 watchOS 합병증 업데이트, 파일 공급자 변경에 대한 응답, 들어오는 VoIP(Voice-over-IP) 호출 수신을 위한 특수 알림을 지원합니다. (https://developer.apple.com/documentation/pushkit)
- 이번글은 Callkit과 Pushkit을 이용한 예제로서 해당 예제에서는 Pushkit을 사용하여 알람을 받은경우 Callkit을 호출하지 않으면 오류가 발생
º Signing & Capabilities
- PROJECT > TARGETS안의 Signing & Capabilities에 Background Modes, Push Notifications 추가
- Background Modes > Voice over IP, Remote notification 활성화
º AppDelegate.swift
import UIKit
import CallKit
import PushKit
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
VoIPService.shared.initPushkit()
CallKitService.shared.initializeCallKit()
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
}
private func registerForRemoteNotifications() {
// 유저에게 권한 요청
let center = UNUserNotificationCenter.current()
center.delegate = self
let options: UNAuthorizationOptions = [.alert, .sound, .badge]
center.requestAuthorization(options: options) {
(granted, error) in
guard granted else {
return
}
DispatchQueue.main.async{
UIApplication.shared.registerForRemoteNotifications()
}
}
}
}
º VoIPService.swift
- Pushkit 설정 및 메시지 처리, Callkit 이벤트 처리
import Foundation
import PushKit
import CallKit
class VoIPService: NSObject, PKPushRegistryDelegate, CXProviderDelegate {
func providerDidReset(_ provider: CXProvider) {}
static let shared: VoIPService = .init()
var deviceID: String?
override private init() {super.init()}
// pushkit 초기화
func initPushkit() {
let registry = PKPushRegistry(queue: nil)
registry.delegate = self
registry.desiredPushTypes = [PKPushType.voIP]
}
func pushRegistry(
_ registry: PKPushRegistry,
didUpdate pushCredentials: PKPushCredentials,
for type: PKPushType
) {
self.deviceID = pushCredentials.token.map { String(format: "%02.2hhx", $0) }.joined()
print("self.deviceID <<<<<<<<< \(self.deviceID)")
}
// 푸시가 정상적으로 받을 시 호출될 함수
func pushRegistry(
_ registry: PKPushRegistry,
didReceiveIncomingPushWith payload: PKPushPayload,
for type: PKPushType, completion: @escaping () -> Void
) {
// payload 처리
let strPayLoad = ((payload.dictionaryPayload["aps"] as? [AnyHashable : Any])?["alert"] as? [AnyHashable : Any])?["incoming_caller_id"] as? String ?? ""
CallKitService.shared.provider!.setDelegate(self, queue: nil)
CallKitService.shared.setCXCallUpdate(strPayLoad) // callkit 화면에 노출
CallKitService.shared.cxUUID = UUID() // 통화 거절 등에도 사용되므로 변수처리
CallKitService.shared.provider!.reportNewIncomingCall(with: CallKitService.shared.cxUUID!, update: CallKitService.shared.cxUpdate!, completion: { error in })
}
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
// Callkit 전화통화 수락
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
// Callkit 전화통화 거절
action.fulfill()
}
func provider(_ provider: CXProvider, perform action: CXStartCallAction) {
action.fulfill(withDateStarted: Date())
}
func provider(_ provider: CXProvider, perform action: CXSetMutedCallAction) {
action.fulfill()
}
}
º CallKitConfig.swift
- Callkit 설정
import Foundation
import CallKit
class CallKitConfig {
static let shared: CallKitConfig = .init()
var cxProviderConfig: CXProviderConfiguration = {
let configuration = CXProviderConfiguration()
configuration.supportsVideo = false
configuration.maximumCallGroups = 1
configuration.maximumCallsPerCallGroup = 1
configuration.includesCallsInRecents = false
return configuration
} ()
var provider: CXProvider?
var callKitController: CXCallController?
var cxUUID: UUID?
var cxUpdate: CXCallUpdate?
private init() {}
func initializeCallKit() {
callKitController = CXCallController(queue: DispatchQueue.main)
provider = CXProvider(configuration: cxProviderConfig)
}
func setCXCallUpdate(_ viewNumber: String) {
cxUpdate = CXCallUpdate()
cxUpdate!.remoteHandle = CXHandle(type: .generic, value: viewNumber)
}
}
º Push Test
- 테스트는 실제 디바이스로 진행
curl -v \
-d '{"aps":{"alert":{"incoming_caller_id":"0123456789","incoming_caller_name":"Tester"}}}' \
-H "apns-push-type: voip" \
-H "apns-expiration: 0" \
-H "apns-priority: 0" \
-H "apns-topic: <Bundle_ID>.voip" \
--http2 \
--cert ./<인증서(pem)> \
https://api.push.apple.com/3/device/<device id>
** production 으로 테스트를 진행하는 경우
'https://api.sandbox.push.apple.com:443' 대신 'https://api.push.apple.com'으로 사용한다.
** TestFlight에서 테스트를 진행하는경우 export 시에 aps-enviroment가 자동으로 production으로 설정되기때문에 'https://api.push.apple.com'으로 테스트해야한다.
'swift' 카테고리의 다른 글
Floating Button (0) | 2023.04.27 |
---|---|
VoIP 인증서 (for Pushkit) (0) | 2023.01.05 |