부트페이 결제 라이브러리를 사용하고 느낀점과 배운점을 기록합니다.
📍 나이스 페이먼트를 사용한 카드 정기결제, 통합결제를 다룹니다.
Bootpay 와 SwiftyBooty 중 'Bootpay' 사용
부트페이 홈페이지에서는 두 가지 라이브러리를 다루고 있지만 부트페이 깃헙의 가장 최근 예제에서 Bootpay를 사용하고 있어 Bootpay를 적용했습니다.
pod 'Bootpay'
해줍니다..
하면 에러가 되게되게 많이 나는데요
이 에러가 가장 많이 나옵니다.
iOS deployment target이 낮으니 높이라는 에러입니다.
근데, 저는 보통 iOS deployment target을 15.0 으로 하기 때문에 당최 왜 저런 에러가 나는 것인가 이해할 수가 없었습니다.
짜잔
앱의 iOS deployment target이 아닌 해당 라이브러리의 iOS deployment target을 말하는 것이였습니다
그래서 Bootpay 라이브러리의 Minimum target을 올려주고 Bootpay 하위 라이브러리인 CryptoSwift와 ObjectMapper도 Minimum target을 같이 올려주면 해결됩니다
‼️ pod에 새로운 라이브러리를 추가하여 pod install할 때마다
iOS deployment target이 초기 세팅값으로 돌아가니 그 때마다 다시 minimum target을 올려주어야합니다.
Info.plist 외엔 따로 설정할 게 없습니다.
App Transport Security Settings -> Allow Arbitrary Loads를
"YES" 로 설정해줍니다.
타 카드사 앱으로 이동하는 것과 같이
다른 앱으로 이동했다가 다시 기존 앱으로 돌아와야하는 경우 CFBundleURLName과 CFBundleURLSchemes도 설정해주어야합니다.
제가 진행 중인 앱은 해당 사항이 없어 설정하지 않았습니다.
일단, 어떻게 쓰는건지가 제일 관건인데요.
참고하기 가장 좋은 예제는 부트페이 깃헙에 있습니다.
저는 iOS-example-swift repo에 있는 예제가 제일 좋았습니다.
왜냐하면 각 케이스별 VC가 다 있습니다.
이렇게 참고하시면 되고, 저는 통합결제와 카드자동 결제만 참고했습니다
import Bootpay
purchaseButton.rx.tap
.subscribe(onNext: { [weak self] in
self?.bootpayStart()
})
.disposed(by: disposeBag)
func bootpayStart() {
let payload = generatePayload()
...
}
func generatePayload() -> Payload {
let payload = Payload()
guard let membership = selectedPayment,
let appUser = AppData.user else {
return payload
}
payload.applicationId = BootpayManager.shared.appID
if membership != .lifetime {
payload.pg = "나이스페이"
payload.method = "카드자동"
}
payload.price = membership.cost
payload.orderId = membership.subscriptionId
payload.subscriptionId = membership.subscriptionId
payload.orderName = membership.bootPayTitle
let extra = BootExtra()
extra.cardQuota = String(3)
payload.extra = extra
let user = BootUser()
user.username = appUser.name
user.userId = appUser.uid
payload.user = user
return payload
}
통합결제일 경우 payload.pg 와 payload.method를 비워둡니다.
작성할 때 각 pg사와 method의 string값을 모르는 경우 여기서 일반결제 요청하기 항목으로 가면
이렇게 각 파라미터 별 string 값을 확인할 수 있습니다.
이제 생성한 Payload를 파라미터로 전달하며 bootpay를 request 하면 끝입니다.
간단하게 보면 이렇게 생긴 request 입니다.
isModal, animation, modalPresentationStyle은 default 값이 설정되어 있어 request를 작성해도 보여지지 않을 수 있습니다.
default 값과 다르게 설정하고 싶다면 그냥 쑤셔서 적어버리면 됩니다.
func bootpayStart() {
let payload = generatePayload()
if payload.method == "카드자동" {
Bootpay.requestSubscription(viewController: self, payload: payload, isModal: true)
.onCancel { data in
print("-- cancel: \(data)")
}
.onIssued { data in
print("-- issued: \(data)")
}
.onConfirm { data in
print("-- confirm: \(data)")
return true
}
.onDone { data in
self.viewModel?.input.addPaymentData.onNext(data)
}
.onError { data in
print("-- error: \(data)")
}
.onClose {
print("-- close")
}
} else {
Bootpay.requestPayment(viewController: self, payload: payload, isModal: false)
.onCancel { data in
print("-- cancel: \(data)")
}
.onIssued { data in
print("-- issued: \(data)")
}
.onConfirm { data in
print("-- confirm: \(data)")
return true
}
.onDone { data in
self.viewModel?.input.addPaymentData.onNext(data)
}
.onError { data in
print("-- error: \(data)")
}
.onClose {
print("-- close")
}
}
}
저는 카드 자동 결제, 통합결제를 한 번에 처리하고자 이렇게 작성했습니다.
이 request는 각 상태 별 method를 제공하고 있습니다.
사용자가 결제를 완료한 경우 onDone이 호출되고 관련 data 를 전달받을 수 있습니다.
일단 onDone에서 전달받는 data는 정말 많은 데이터를 담고 있는데요.
JsonParser 를 사용해서 전달 받은 데이터 JSON 을 확인하면 파악하는데에 도움이 됩니다.
‼️ 원본 데이터가 아닙니다 민감 데이터(ex card, 이름) 항목은 삭제했습니다. 대략적으로 이렇게 옵니다.
func parsePaymentData(_ data: [String: Any]) {
if let dataDict = data["data"] as? [String: Any] {
if let purchasedAt = dataDict["published_at"] as? String,
let receiptId = dataDict["receipt_id"] as? String {
getBillingKey(receiptId, purchasedAt)
} else {
print("Failed to retrieve the required data.")
}
} else {
print("Data key not found in the dictionary.")
}
}
위처럼 필요한 항목만 골라서 사용했습니다.
이렇게하면 결제는 끝입니다 !
다만 정기결제를 구현하는 경우 Billing_key를 발급받는 로직이 추가로 구현되어야합니다.
앱 단에서는 보안 상의 이유로 바로 Billing_key를 발급 받을 수 없고 서버에서 구현되어야합니다.
아직 하는 중이라, 이거도 하게되면 적어보겠습니다..
감사합니다. 이런 정보를 나눠주셔서 좋아요.