관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 2. 전화걸기, 전화받기, VoIP(Voice over IP) - PushKit 본문

iOS 응용 (swift)

[iOS - swift] 2. 전화걸기, 전화받기, VoIP(Voice over IP) - PushKit

jake-kim 2022. 2. 12. 21:06

1. 전화걸기, 전화받기, VoIP(Voice over IP) - CallKit

2. 전화걸기, 전화받기, VoIP(Voice over IP) - PushKit

iOS에서의 VoIP 개념?

  • VoIP(Voice over Internet Protocol): 셀룰러 서비스 대신 인터넷 연결을 사용하여 전화를 걸고 받을 수 있는 프로토콜
  • 높은 에너지를 사용한다는 단점 존재
  • iOS 8이전에는 VoIP앱이 인터넷 연결을 사용하여 전화를 수신하기 위해 서버와 지속적인 연결이 필요했기 때문에 background에서 연결을 유지하면 배터리 소모, 앱이 충돌 등의 다양한 문제가 발생
  • iOS 8부터는 PushKit을 도입하여, Message앱에 적용하여 배터리 성능 및 안정성을 개선

PushKit 이란

  • complications, file providers, VoIP 서비스들의 push notification에 대한 `응답`하는 프레임워크
  • 일반적으로 APNs로 사용하는 Push Notification과 동일한 형태지만, 앱을 깨울 수 있고 더 많은 데이터를 제공할 수 있도록 하는 기능

  • 예시 - VoIP 앱) 앱이 종료된 상태에서 VoIP 호출이 수신될 때 앱을 깨우고 싶은 경우, APN으로만 하면 푸시 알림이 앱을 바로 깨우지 않기 때문에 PushKit사용

PushKit의 역할

  • 백그라운드에서 알림을 수신하고 연결을 설정하거나 데이터를 처리하고 사용자에게 Local 알림을 표출
  • 사용자가 알림을 swipe하면 전화/데이터가 연결 및 표출
  • PushKit 알림은 사용자에게 배지, 경고, 소리등으로 표시되지 않음
  • VoIP 알림의 경우 최대 payload 크기는 5KB(5120byte)
  • VoIP 푸시가 발생한 겨우에만 장치를 깨우므로 에너지 절약에 이점
  • 일반적인 알림인 Push Notification보다 더 많은 데이터를 포함시킬 수 있는 장점
  • VoIP푸시가 수신될 때 앱이 실행되고 있지 않으면 앱이 자동으로 다시 시작

PushKit 적용

  • 프로젝트에서 background mode 추가
  • 프로젝트에서 VoIP 활성화
  • XCode에서 푸시 수신 설정
  • Target -> Signing & Capabilities -> +Capability: push notification 추가
  • Background Modes -> Remote notifications도 체크
  • 애플에서 PushKit은 항상 CallKit과 사용하도록 되어있으므로, CallKit도 아래처럼 사용
    * CallKit 개념은 이전 포스팅 글 참고
    import UIKit
    import CallKit
    import PushKit
    
    class ViewController: UIViewController {
      let provider = CXProvider(configuration: CXProviderConfiguration(localizedName: "jake"))
      
      override func viewDidLoad() {
        super.viewDidLoad()
        
        let registry = PKPushRegistry(queue: nil)
        registry.delegate = self
        registry.desiredPushTypes = [PKPushType.voIP]
      }
    }
    
    extension ViewController: CXProviderDelegate {
      func providerDidReset(_ provider: CXProvider) {
      }
      
      func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
        action.fulfill()
      }
      
      func provider(_ provider: CXProvider, perform action: CXEndCallAction) {
        action.fulfill()
      }
    }
    
    extension ViewController: PKPushRegistryDelegate {
      func pushRegistry(
        _ registry: PKPushRegistry,
        didUpdate pushCredentials: PKPushCredentials,
        for type: PKPushType
      ) {
        let deviceID = pushCredentials.token.map { String(format: "%02.2hhx", $0) }.joined()
        // deviceID를 server에 전송
      }
      
      func pushRegistry(
        _ registry: PKPushRegistry,
        didReceiveIncomingPushWith payload: PKPushPayload,
        for type: PKPushType, completion: @escaping () -> Void
      ) {
        self.provider.setDelegate(self, queue: nil)
        let update = CXCallUpdate()
        update.remoteHandle = CXHandle(type: .generic, value: "jake")
        update.hasVideo = false
        self.provider.reportNewIncomingCall(with: UUID(), update: update, completion: { error in })
      }
    }

-> 서버에서 VoIP 관련 푸시를 받으면, 앱이 꺼져있거나 백그라운드 상태일지라도 바로 전화 UI 표출

(deprecated) 푸시 테스트

(아래 글의 테스트는 동작이 안되니 참고 용도)

  • VoIP 푸시 알림 수신 준비
    • VoIP 앱에는 고유한 앱 번들 ID에 매핑된 개별 VoIP 서비스 인증서가 필요
    • 이 인증서를 통해 알림 서버가 VoIP 서비스에 연결이 가능
  • https://developer.apple.com/certificates에서 인증서를 다운받기 전에 App Identifiers 생성: Certificates, Identifiers & Profiles -> Identifiers -> + 버튼(생성)
    • 주의) 만들때 Push Notifications 옵션 체크
  • 인증서를 만들기 위해 CSR(Certificate SIgninging Request) 생성
    • Keychain Access 앱 실행 > 키체인 접근 > 인증 기관에서 인증서 요청
    • 요청항목에 "디스크에 저장됨", "본인이 키 쌍 정보 지정"에 체크 > "사용자 이메일 주소" 입력 후 계속 클릭
  • VoIP 서비스 인증서 생성
    • Certificates, Identifiers & Profiles -> Certificates -> + 버튼(생성) -> 아래 옵션에서 "VoIP Services Certificate" 체크
    • 생성 후 다운로드
      인증서
  • Keychan Access 앱 실행 -> 인증서 -> 다운받은 인증서 VoIP Services를 드래그하여 이동
  • 키 내보내기 선택
    • 동료 개발자와 공유할 수 있도록 p12로 내보내기

푸시를 테스트하기위해 pem파일로 변경

openssl pkcs12 -in {인증서 이름}.p12 -out {인증서 이름}.pem​

  • 실제 디바이스 실행 -> console창에 ID 복사
  • .pem파일이 있는곳으로 가서, curl로 아래 코드 수정하여 실행
    • {bundleID}
    • {PemName}
    • {DeviceID}
curl -v \
-d '{"aps":{"alert":"푸시 테스트 메시지","badge":42}}' \
-H "apns-topic: {BundleID}" \
-H "apns-priority: 10" \
--http2 \
--cert {PemName}.pem \
https://api.development.push.apple.com/3/device/{DeviceID}

* 전체 코드: https://github.com/JK0369/ExPushKit

* 참고

https://websitebeaver.com/callkit-swift-tutorial-super-easy

https://github.com/noodlewerk/NWPusher

https://medium.com/mindful-engineering/voice-over-internet-protocol-voip-801ee15c3722

Comments