본문 바로가기

iOS

SwiftUI - 토스페이먼트, 결제 동의 관련

SwiftUI로 토스페이먼트 연동하여 결제를 하는 서비스를 만들던 중 '결제 동의'를 하지 않아도, 결제가 가능한 문제를 경험했습니다.

결제 동의란의 체크표시를 하던, 하지 않던 결제가 가능했던 것인데요!

결제 동의란의 상태 값을 제대로 받아오지 못하고 있다고 생각했습니다.

토스페이먼츠에서 깃허브에 제공한 코드를 활용하여 개발 하였고, 당시 오픈 소스에 SwiftUI에 토스페이먼츠를 사용한 다른 코드가 없었기 때문에 오류를 수정하기란 쉽지 않았습니다.

 

토스페이먼츠 제공 코드:

- https://github.com/tosspayments/payment-sdk-ios/blob/95a65f9b0e080b370dfcc762c0059f82bdd56c91/Examples/SwiftUI-Example/TossPaymentsContentView.swift#L33

- https://github.com/tosspayments/payment-sdk-ios/blob/95a65f9b0e080b370dfcc762c0059f82bdd56c91/Examples/SwiftUI-Example/TossPaymentsContentViewModel.swift#L36

해결 과정

xcode의 힌트를 통해 widget.delegate 이외의 추가할 수 있는 코드가 있음을 인지하였고

 

 

let widget: PaymentWidget
  
init() {
    if let apiKey = apiKey {
      widget = PaymentWidget(clientKey: apiKey, customerKey: UUID().uuidString)
      widget.delegate = self
      widget.agreementWidget?.agreementUIDelegate = self
      widget.agreementWidget?.widgetStatusDelegate = self
    } else {
      fatalError("TOSS_API not found in Info.plist")
    }
}

extension TossPaymentsModel: TossPaymentsAgreementUIDelegate {
  
  func didUpdateHeight(_ widget: AgreementWidget, height: CGFloat) {
  }
  
  func didUpdateAgreementStatus(_ widget: AgreementWidget, agreementStatus: AgreementStatus) {
    self.agreement = agreementStatus.agreedRequiredTerms
  }
  
}

Delegate를 추가한 후, 결제 동의 값을 받아오는 didUpdateAgreementStatus 함수를 알 수 있었습니다.

하지만, 뷰는 그려져도 결제 동의 값은 적용되지 않았습니다......

이유를 알아보기 위해, PaymentWidget의 코드를 하나하나 뜯어가며 원인을 알아보려고 하였습니다.

 

 

PaymentWidget의 코드를 보다보니, agreementWidget이 PaymentWidget의 변수임을 알 수 있었고

 

 

renderAgreement 함수를 통해서, AgreementWidget이 생성된다는 것을 알 수 있었습니다.

 

 

init() {
    if let apiKey = apiKey {
      widget = PaymentWidget(clientKey: apiKey, customerKey: UUID().uuidString)
      widget.delegate = self
      widget.agreementWidget = widget.renderAgreement()
      widget.agreementWidget?.agreementUIDelegate = self
      widget.agreementWidget?.widgetStatusDelegate = self
    } else {
      fatalError("TOSS_API not found in Info.plist")
    }
  }

그래서 기존의 코드에 widget.agreementWidget = widget.renderAgreement( )라는 코드를 추가하였습니다.

 

 

그 이후 AgreementWidgetViews에 대한 코드를 https://github.com/tosspayments/payment-sdk-ios/blob/95a65f9b0e080b370dfcc762c0059f82bdd56c91/TossPayments/Sources/SwiftUI/Widget/AgreementWidgetView.swift 보고

import SwiftUI

public struct AgreementWidgetView: UIViewRepresentable {
    public typealias UIViewType = AgreementWidget
    
    private let widget: PaymentWidget
    public init(
        widget: PaymentWidget
    ) {
        self.widget = widget
    }
    
    public func makeUIView(context: Context) -> AgreementWidget {
        widget.renderAgreement()
    }
    
    public func updateUIView(_ uiView: AgreementWidget, context: Context) {
        
    }
}

test 코드에서 agreementWidget?.agreementUIDelegate를 연결하고 난 후, widget.renderAgreement()로 agreementWidget를 생성하기 때문에 문제가 되고 있음을 알 수 있었고

 

public func makeUIView(context: Context) -> AgreementWidget {
    widget.agreementWidget!
}

PaymentWidget에서 생성된 AgreementWidget를 사용함으로써,

결제 동의 값을 성공적으로 받아올 수 있었습니다.