diff --git a/.gitignore b/.gitignore index 339f5a7..f5d6d72 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ ### Xcode ### build +.build *.xcodeproj/* !*.xcodeproj/project.pbxproj !*.xcworkspace/contents.xcworkspacedata diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 8039895..11a1f1f 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -34,4 +34,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: dc94aab5cf45a14d04fee8f93c0c0613b8dbcd1a -COCOAPODS: 1.10.1 +COCOAPODS: 1.11.3 diff --git a/Example/iamport-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Example/iamport-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved index 2e53b4d..fd1177e 100644 --- a/Example/iamport-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Example/iamport-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -11,12 +11,12 @@ } }, { - "package": "RxBus", - "repositoryURL": "https://github.com/ridi/RxBus-swift.git", + "package": "RxBusForPort", + "repositoryURL": "https://github.com/iamport/RxBus-Swift", "state": { "branch": null, - "revision": "b154da5fffb4c5d0d17b7f46e9cd38f382e298e4", - "version": "1.3.2" + "revision": "24458425acf1da825a8e7587231052cef90c3a6b", + "version": "1.3.5" } }, { @@ -28,6 +28,15 @@ "version": "6.2.0" } }, + { + "package": "SwiftFormat", + "repositoryURL": "https://github.com/nicklockwood/SwiftFormat", + "state": { + "branch": null, + "revision": "ae4d0b672cd7094ae513097c617951a5ac714418", + "version": "0.50.8" + } + }, { "package": "Then", "repositoryURL": "https://github.com/devxoul/Then.git", diff --git a/Example/iamport-ios/View/PaymentResultViewController.swift b/Example/iamport-ios/View/PaymentResultViewController.swift index 06b1a9a..7f188d5 100644 --- a/Example/iamport-ios/View/PaymentResultViewController.swift +++ b/Example/iamport-ios/View/PaymentResultViewController.swift @@ -18,7 +18,7 @@ import RxSwift class PaymentResultViewController: UIViewController, UIGestureRecognizerDelegate { // 결과 전달 받을 RxSubject - let impResponseRelay = BehaviorRelay(value: nil) + let impResponseRelay = BehaviorRelay(value: nil) var disposeBag = DisposeBag() override func viewDidLoad() { @@ -53,7 +53,7 @@ class PaymentResultViewController: UIViewController, UIGestureRecognizerDelegate // imp_success, success 해당 값을 맹신할 수 없습니다. // 뱅크페이 실시간 계좌이체는 해당 값이 전달되지 않는 케이스가 있습니다. // 결과 콜백을 받으면, Iamport REST API 등을 통해 "실제 결제 여부" 를 체크하셔야 합니다. - private func isSuccess(_ iamportResponse: IamPortResponse) -> Bool { + private func isSuccess(_ iamportResponse: IamportResponse) -> Bool { iamportResponse.imp_success ?? false || iamportResponse.success ?? false } diff --git a/Example/iamport-ios/View/PaymentView.swift b/Example/iamport-ios/View/PaymentView.swift index a081e04..0579fc9 100644 --- a/Example/iamport-ios/View/PaymentView.swift +++ b/Example/iamport-ios/View/PaymentView.swift @@ -61,8 +61,8 @@ class PaymentViewController: UIViewController, WKNavigationDelegate { } let userCode = viewModel.order.userCode // iamport 에서 부여받은 가맹점 식별코드 - if let request = viewModel.createPaymentData() { - dump(request) + if let payment = viewModel.createPaymentData() { + dump(payment) // #case1 use for UIViewController @@ -70,7 +70,7 @@ class PaymentViewController: UIViewController, WKNavigationDelegate { Iamport.shared.useNaviButton(enable: true) Iamport.shared.payment(viewController: self, - userCode: userCode.value, iamPortRequest: request) { iamPortResponse in + userCode: userCode.value, payment: payment) { iamPortResponse in viewModel.iamportCallback(iamPortResponse) } diff --git a/Example/iamport-ios/View/PaymentWebViewModeView.swift b/Example/iamport-ios/View/PaymentWebViewModeView.swift index 06fd83b..77215fa 100644 --- a/Example/iamport-ios/View/PaymentWebViewModeView.swift +++ b/Example/iamport-ios/View/PaymentWebViewModeView.swift @@ -87,11 +87,11 @@ class PaymentWebViewModeViewController: UIViewController, WKNavigationDelegate { } let userCode = viewModel.order.userCode // iamport 에서 부여받은 가맹점 식별코드 - if let request = viewModel.createPaymentData() { - dump(request) + if let payment = viewModel.createPaymentData() { + dump(payment) //WebView 사용 - Iamport.shared.paymentWebView(webViewMode: wkWebView, userCode: userCode.value, iamPortRequest: request) { [weak self] iamPortResponse in + Iamport.shared.paymentWebView(webViewMode: wkWebView, userCode: userCode.value, payment: payment) { [weak self] iamPortResponse in viewModel.iamportCallback(iamPortResponse) self?.presentationMode?.wrappedValue.dismiss() } diff --git a/Example/iamport-ios/View/ViewController.swift b/Example/iamport-ios/View/ViewController.swift index dfe94a6..3f75897 100644 --- a/Example/iamport-ios/View/ViewController.swift +++ b/Example/iamport-ios/View/ViewController.swift @@ -50,15 +50,15 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { // 아임포트 SDK 본인인증 요청 func requestCertification() { let userCode = "iamport" // 다날 - let request = createCertificationData() - dump(request) + let certification = createCertificationData() + dump(certification) guard let navController = navigationController else { print("navigationController 를 찾을 수 없습니다") return } - Iamport.shared.certification(navController: navController, userCode: userCode, iamPortCertification: request) { [weak self] iamPortResponse in + Iamport.shared.certification(navController: navController, userCode: userCode, certification: certification) { [weak self] iamPortResponse in self?.paymentCallback(iamPortResponse) } @@ -106,7 +106,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { } else { } Iamport.shared.paymentWebView(webViewMode: wkWebView, - userCode: userCode, iamPortRequest: request) { [weak self] iamPortResponse in + userCode: userCode, payment: request) { [weak self] iamPortResponse in self?.paymentCallback(iamPortResponse) } @@ -132,11 +132,11 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { } // 아임포트 결제 데이터 생성 - func createPaymentData() -> IamPortRequest { + func createPaymentData() -> IamportPayment { let display = CardQuota() display.card_quota = [] - return IamPortRequest( + return IamportPayment( pg: PG.html5_inicis.makePgRawName(pgId: ""), merchant_uid: "muid_ios_\(Int(Date().timeIntervalSince1970))", amount: "1000").then { @@ -149,8 +149,8 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { } // 아임포트 본인인증 데이터 생성 - func createCertificationData() -> IamPortCertification { - IamPortCertification(merchant_uid: "muid_ios_\(Int(Date().timeIntervalSince1970))").then { + func createCertificationData() -> IamportCertification { + IamportCertification(merchant_uid: "muid_ios_\(Int(Date().timeIntervalSince1970))").then { $0.min_age = 19 $0.name = "김빙봉" $0.phone = "010-1234-5678" @@ -160,7 +160,7 @@ class ViewController: UIViewController, UIGestureRecognizerDelegate { } // 결제 완료 후 콜백 함수 (예시) - func paymentCallback(_ response: IamPortResponse?) { + func paymentCallback(_ response: IamportResponse?) { print("------------------------------------------") print("결과 왔습니다~~") print("Iamport Payment response: \(response)") diff --git a/Example/iamport-ios/ViewModel.swift b/Example/iamport-ios/ViewModel.swift index b580c29..d883928 100644 --- a/Example/iamport-ios/ViewModel.swift +++ b/Example/iamport-ios/ViewModel.swift @@ -46,7 +46,7 @@ public class ViewModel: ObservableObject, Then { @Published var isCert: Bool = false @Published var showResult: Bool = false @Published var CardDirectCode: String = "" - var iamPortResponse: IamPortResponse? + var iamPortResponse: IamportResponse? init() { order = Order().then { order in @@ -91,10 +91,10 @@ public class ViewModel: ObservableObject, Then { } // 아임포트 결제 데이터 생성 - func createPaymentData() -> IamPortRequest? { + func createPaymentData() -> IamportPayment? { let payMethod = order.payMethod.value - let req = IamPortRequest( + let req = IamportPayment( pg: order.pg.value, merchant_uid: order.merchantUid.value, amount: order.price.value).then { @@ -144,7 +144,7 @@ public class ViewModel: ObservableObject, Then { // 결제 완료 후 콜백 함수 (예시) - func iamportCallback(_ response: IamPortResponse?) { + func iamportCallback(_ response: IamportResponse?) { print("------------------------------------------") print("결과 왔습니다~~") if let res = response { @@ -163,8 +163,8 @@ public class ViewModel: ObservableObject, Then { } // 아임포트 본인인증 데이터 생성 - func createCertificationData() -> IamPortCertification { - IamPortCertification(merchant_uid: cert.merchantUid.value).then { + func createCertificationData() -> IamportCertification { + IamportCertification(merchant_uid: cert.merchantUid.value).then { $0.min_age = Int(cert.minAge.value) $0.name = cert.name.value $0.phone = cert.phone.value @@ -219,4 +219,4 @@ public class ViewModel: ObservableObject, Then { // -} \ No newline at end of file +} diff --git a/Package.resolved b/Package.resolved index 86634b2..8eedb0f 100644 --- a/Package.resolved +++ b/Package.resolved @@ -12,7 +12,7 @@ }, { "package": "RxBus", - "repositoryURL": "https://github.com/ridi/RxBus-swift", + "repositoryURL": "https://github.com/iamport/RxBus-Swift", "state": { "branch": null, "revision": "b154da5fffb4c5d0d17b7f46e9cd38f382e298e4", @@ -28,6 +28,15 @@ "version": "6.2.0" } }, + { + "package": "SwiftFormat", + "repositoryURL": "https://github.com/nicklockwood/SwiftFormat", + "state": { + "branch": null, + "revision": "ae4d0b672cd7094ae513097c617951a5ac714418", + "version": "0.50.8" + } + }, { "package": "Then", "repositoryURL": "https://github.com/devxoul/Then.git", diff --git a/Package.swift b/Package.swift index b48fcd8..95eea16 100644 --- a/Package.swift +++ b/Package.swift @@ -22,6 +22,7 @@ let package = Package( .package(name: "RxBusForPort", url: "https://github.com/iamport/RxBus-Swift", .upToNextMinor(from: "1.3.0")), .package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.4.0")), .package(url: "https://github.com/devxoul/Then.git", .upToNextMajor(from: "2.7.0")), + .package(url: "https://github.com/nicklockwood/SwiftFormat", from: "0.50.4") ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/Sources/iamport-ios/Assets/iamportcdn.html b/Sources/iamport-ios/Assets/iamportcdn.html index 9ebe57d..1d371d3 100644 --- a/Sources/iamport-ios/Assets/iamportcdn.html +++ b/Sources/iamport-ios/Assets/iamportcdn.html @@ -4,52 +4,50 @@ - - - + - \ No newline at end of file + diff --git a/Sources/iamport-ios/Classes/Data/Approve.swift b/Sources/iamport-ios/Classes/Data/Approve.swift index 93efe81..0f35432 100644 --- a/Sources/iamport-ios/Classes/Data/Approve.swift +++ b/Sources/iamport-ios/Classes/Data/Approve.swift @@ -15,4 +15,4 @@ class ApproveData: Codable { var merchantUid: String var success: Bool var reason: String? -} \ No newline at end of file +} diff --git a/Sources/iamport-ios/Classes/Data/BankPayResultCode.swift b/Sources/iamport-ios/Classes/Data/BankPayResultCode.swift index ec90826..cd932e4 100644 --- a/Sources/iamport-ios/Classes/Data/BankPayResultCode.swift +++ b/Sources/iamport-ios/Classes/Data/BankPayResultCode.swift @@ -13,8 +13,8 @@ enum BankPayResultCode: String, CaseIterable { case FAIL_CERT_MODULE_INIT static func from(_ s: String) -> BankPayResultCode? { - for value in self.allCases { - if (s == value.code) { + for value in allCases { + if s == value.code { return value } } @@ -54,5 +54,4 @@ enum BankPayResultCode: String, CaseIterable { return "인증모듈 초기화 오류" } } - } diff --git a/Sources/iamport-ios/Classes/Data/CHAI.swift b/Sources/iamport-ios/Classes/Data/CHAI.swift index a95dd9f..8522c83 100644 --- a/Sources/iamport-ios/Classes/Data/CHAI.swift +++ b/Sources/iamport-ios/Classes/Data/CHAI.swift @@ -15,9 +15,7 @@ struct CHAI { static let CHANNEL = "mobile" } - public enum CHAI_MODE: String, CaseIterable, Codable { - case prod case staging case dev @@ -25,18 +23,18 @@ public enum CHAI_MODE: String, CaseIterable, Codable { var url: String { switch self { case .prod: - return CONST.CHAI_SERVICE_URL + return Constant.CHAI_SERVICE_URL case .staging: - return CONST.CHAI_SERVICE_STAGING_URL + return Constant.CHAI_SERVICE_STAGING_URL case .dev: - return CONST.CHAI_SERVICE_DEV_URL + return Constant.CHAI_SERVICE_DEV_URL } } static func getChaiUrl(mode: String) -> String { - for value in self.allCases { - if (mode == value.rawValue) { - dlog("Found CHAI mode => [\(mode)]") + for value in allCases { + if mode == value.rawValue { + debug_log("Found CHAI mode => [\(mode)]") return value.url } } @@ -44,4 +42,4 @@ public enum CHAI_MODE: String, CaseIterable, Codable { print("Not found CHAI mode => [\(mode)]") return prod.url // default } -} \ No newline at end of file +} diff --git a/Sources/iamport-ios/Classes/Data/Card.swift b/Sources/iamport-ios/Classes/Data/Card.swift index 3cbc37c..16773e8 100644 --- a/Sources/iamport-ios/Classes/Data/Card.swift +++ b/Sources/iamport-ios/Classes/Data/Card.swift @@ -6,7 +6,7 @@ import Foundation public class Card: Codable { var direct: Direct - public init(direct: Direct) { + public init(direct: Direct) { self.direct = direct } } @@ -17,4 +17,4 @@ public class Direct: Codable { public init(code: String) { self.code = code } -} \ No newline at end of file +} diff --git a/Sources/iamport-ios/Classes/Data/CardQuota.swift b/Sources/iamport-ios/Classes/Data/CardQuota.swift index 5c5a478..d95aece 100644 --- a/Sources/iamport-ios/Classes/Data/CardQuota.swift +++ b/Sources/iamport-ios/Classes/Data/CardQuota.swift @@ -5,7 +5,7 @@ import Foundation public class CardQuota: Codable { - public var card_quota: Array? + public var card_quota: [Int]? public init() { card_quota = nil diff --git a/Sources/iamport-ios/Classes/Data/ChaiPayment.swift b/Sources/iamport-ios/Classes/Data/ChaiPayment.swift index 45f4ad2..895d721 100644 --- a/Sources/iamport-ios/Classes/Data/ChaiPayment.swift +++ b/Sources/iamport-ios/Classes/Data/ChaiPayment.swift @@ -12,11 +12,9 @@ class PaymentMetadata: Codable { } } -class BaseChaiPayment { -} +class BaseChaiPayment {} class ChaiPayment: BaseChaiPayment, Codable { - var paymentId: String // "198ad2c1cc485629447c4527247c198bdb0cd82c" var type: String // "payment" var status: String // "waiting" @@ -32,37 +30,20 @@ class ChaiPayment: BaseChaiPayment, Codable { var cashbackAmount: Float = 0 // 0 var taxFreeAmount: Float = 0 // 0 var bookShowAmount: Float = 0 // 0 - var serviceFeeAmount: Float = 0// 0 - var merchantDiscountAmount: Float = 0// 0 - var merchantCashbackAmount: Float = 0// 0 - var canceledAmount: Float = 0// 0 - var canceledBillingAmount: Float = 0// 0 - var canceledPointAmount: Float = 0// 0 - var canceledCashAmount: Float = 0// 0 - var canceledDiscountAmount: Float = 0// 0 - var canceledCashbackAmount: Float = 0// 0 + var serviceFeeAmount: Float = 0 // 0 + var merchantDiscountAmount: Float = 0 // 0 + var merchantCashbackAmount: Float = 0 // 0 + var canceledAmount: Float = 0 // 0 + var canceledBillingAmount: Float = 0 // 0 + var canceledPointAmount: Float = 0 // 0 + var canceledCashAmount: Float = 0 // 0 + var canceledDiscountAmount: Float = 0 // 0 + var canceledCashbackAmount: Float = 0 // 0 var returnUrl: String // "https://ksmobile.inicis.com/smart/chaipayAcsResult.ini" var description: String // "결제테스트" var createdAt: String // "2020-10-27T06:36:12.218Z" var updatedAt: String // "2020-10-27T06:36:12.218Z" var metadata: PaymentMetadata - // var merchantUserId: String - // var cashbacks: Array // [] -/* - cashbacks = ( - { - description = "\Uc790\Ub3d9\Ucda9\Uc804\Uc774 \Ucf1c\Uc838\Uc788\Ub294 \Uacbd\Uc6b0 \Uacb0\Uc81c\Ub9c8\Ub2e4 \Uce90\Uc2dc\Ubc31"; - discount = "1%"; - endAt = "2021-12-31T14:59:59.000Z"; - priceMax = 2000000; - priceMin = 1; - promotionId = "we230f0-8h2hf4h-en2j04f0-f2949f42h"; - startAt = "2020-01-29T15:00:00.801Z"; - title = "\Uc790\Ub3d9\Ucda9\Uc804 1% \Uce90\Uc2dc\Ubc31"; - type = cashback; - } - ); -*/ init(paymentId: String, type: String, status: String, displayStatus: String, idempotencyKey: String, currency: String, checkoutAmount: Float, @@ -74,7 +55,8 @@ class ChaiPayment: BaseChaiPayment, Codable { canceledCashAmount: Float, canceledDiscountAmount: Float, canceledCashbackAmount: Float, returnUrl: String, description: String, createdAt: String, - updatedAt: String, metadata: PaymentMetadata) { + updatedAt: String, metadata: PaymentMetadata) + { self.paymentId = paymentId self.type = type self.status = status @@ -101,7 +83,6 @@ class ChaiPayment: BaseChaiPayment, Codable { self.canceledCashbackAmount = canceledCashbackAmount self.returnUrl = returnUrl self.description = description -// self.cashbacks = cashbacks self.createdAt = createdAt self.updatedAt = updatedAt self.metadata = metadata diff --git a/Sources/iamport-ios/Classes/Data/ChaiPaymentStatus.swift b/Sources/iamport-ios/Classes/Data/ChaiPaymentStatus.swift index bebe2a7..bf9f826 100644 --- a/Sources/iamport-ios/Classes/Data/ChaiPaymentStatus.swift +++ b/Sources/iamport-ios/Classes/Data/ChaiPaymentStatus.swift @@ -8,11 +8,11 @@ enum ChaiPaymentStatus: String, CaseIterable { case waiting, prepared, approved, user_canceled, canceled, failed, timeout, - confirmed, partial_confirmed, inactive, churn; + confirmed, partial_confirmed, inactive, churn static func from(displayStatus: String) -> ChaiPaymentStatus? { - for value in self.allCases { - if (displayStatus == value.rawValue) { + for value in allCases { + if displayStatus == value.rawValue { return value } } diff --git a/Sources/iamport-ios/Classes/Data/ChaiPaymentSubscription.swift b/Sources/iamport-ios/Classes/Data/ChaiPaymentSubscription.swift index 52608ba..5db3fd7 100644 --- a/Sources/iamport-ios/Classes/Data/ChaiPaymentSubscription.swift +++ b/Sources/iamport-ios/Classes/Data/ChaiPaymentSubscription.swift @@ -15,4 +15,4 @@ class ChaiPaymentSubscription: BaseChaiPayment, Codable { var merchantUserId: String var createdAt: String // "2020-10-27T06:36:12.218Z" var updatedAt: String // "2020-10-27T06:36:12.218Z" -} \ No newline at end of file +} diff --git a/Sources/iamport-ios/Classes/Data/Currency.swift b/Sources/iamport-ios/Classes/Data/Currency.swift index e9523d1..4836f7d 100644 --- a/Sources/iamport-ios/Classes/Data/Currency.swift +++ b/Sources/iamport-ios/Classes/Data/Currency.swift @@ -9,4 +9,4 @@ public enum Currency: String, Codable { case USD case EUR case JPY -} \ No newline at end of file +} diff --git a/Sources/iamport-ios/Classes/Data/Extra.swift b/Sources/iamport-ios/Classes/Data/Extra.swift index e52f46c..73af851 100644 --- a/Sources/iamport-ios/Classes/Data/Extra.swift +++ b/Sources/iamport-ios/Classes/Data/Extra.swift @@ -5,7 +5,6 @@ import Foundation import Then - enum OS: String, Codable { case aos, ios } diff --git a/Sources/iamport-ios/Classes/Data/IamPortApprove.swift b/Sources/iamport-ios/Classes/Data/IamPortApprove.swift index 2f9f0be..e8ebcde 100644 --- a/Sources/iamport-ios/Classes/Data/IamPortApprove.swift +++ b/Sources/iamport-ios/Classes/Data/IamPortApprove.swift @@ -15,12 +15,13 @@ public class IamPortApprove: Then { var idempotencyKey: String var publicAPIKey: String var status: String - var msg: String? = nil + var msg: String? init(userCode: String, merchantUid: String, paymentId: String?, impUid: String, idempotencyKey: String, publicAPIKey: String, status: String, - subscriptionId: String?, customerUid: String) { + subscriptionId: String?, customerUid: String) + { self.userCode = userCode self.merchantUid = merchantUid self.customerUid = customerUid @@ -32,16 +33,15 @@ public class IamPortApprove: Then { self.status = status } - static func make(payment: Payment, prepareData: PrepareData, status: ChaiPaymentStatus) -> IamPortApprove { + static func make(payment: IamportRequest, prepareData: PrepareData, status: ChaiPaymentStatus) -> IamPortApprove { IamPortApprove(userCode: payment.userCode, - merchantUid: payment.getMerchantUid(), - paymentId: prepareData.paymentId, - impUid: prepareData.impUid, - idempotencyKey: prepareData.idempotencyKey, - publicAPIKey: prepareData.publicAPIKey, - status: status.rawValue, - subscriptionId: prepareData.subscriptionId, - customerUid: payment.getCustomerUid()) + merchantUid: payment.getMerchantUid(), + paymentId: prepareData.paymentId, + impUid: prepareData.impUid, + idempotencyKey: prepareData.idempotencyKey, + publicAPIKey: prepareData.publicAPIKey, + status: status.rawValue, + subscriptionId: prepareData.subscriptionId, + customerUid: payment.getCustomerUid() ?? Constant.EMPTY_STR) } } - diff --git a/Sources/iamport-ios/Classes/Data/IamPortCertification.swift b/Sources/iamport-ios/Classes/Data/IamportCertification.swift similarity index 88% rename from Sources/iamport-ios/Classes/Data/IamPortCertification.swift rename to Sources/iamport-ios/Classes/Data/IamportCertification.swift index 3b6c8df..92e43fa 100644 --- a/Sources/iamport-ios/Classes/Data/IamPortCertification.swift +++ b/Sources/iamport-ios/Classes/Data/IamportCertification.swift @@ -5,9 +5,8 @@ import Foundation import Then -// https://docs.iamport.kr/tech/mobile-authentication -public class IamPortCertification: Codable, Then { - +// https://portone.gitbook.io/docs/etc/phone +public class IamportCertification: Codable, Then { let merchant_uid: String public var min_age: Int? @@ -28,7 +27,7 @@ public class IamPortCertification: Codable, Then { // ReactNative / Ionic 등 앱 내 local html을 통해 IMP.certification()이 호출되는 경우에는 URL 도메인을 인식할 수 없으므로 본 파라메터 지정이 권장됩니다.(지정하지 않으면 아임포트라고 전달합니다) // 운영하시는 서비스의 대표 도메인 URL(예시 : https://www.iamport.co.kr) 또는 서비스 명칭(예시 : 아임포트)을 지정하시면 됩니다. public var company: String? - private var m_redirect_url: String? = CONST.IAMPORT_DETECT_URL // 콜백 + private var m_redirect_url: String? = Constant.IAMPORT_DETECT_URL // 콜백 public init(merchant_uid: String) { self.merchant_uid = merchant_uid diff --git a/Sources/iamport-ios/Classes/Data/IamPortRequest.swift b/Sources/iamport-ios/Classes/Data/IamportPayment.swift similarity index 92% rename from Sources/iamport-ios/Classes/Data/IamPortRequest.swift rename to Sources/iamport-ios/Classes/Data/IamportPayment.swift index 6481e14..939dd70 100644 --- a/Sources/iamport-ios/Classes/Data/IamPortRequest.swift +++ b/Sources/iamport-ios/Classes/Data/IamportPayment.swift @@ -10,7 +10,7 @@ import Then (PG : .html5_inicis, pay_method : .trans) 일 때, :// 을 붙여주세요. 간헐적으로 결제를 못해서 미결제남. (PG : .smilepay, pay_method : .card) 또한 :// 으로 CNS 측에 등록되어있을 수 있으니 확인해주세요. 안그러면 스마일페이 앱에서 404 에러남. */ -public class IamPortRequest: Codable, Then { +public class IamportPayment: Codable, Then { var pg: String // 없음안됨 public var pay_method: String = PayMethod.card.rawValue public var escrow: Bool? // default false @@ -27,17 +27,16 @@ public class IamPortRequest: Codable, Then { public var buyer_email: String? public var buyer_addr: String? public var buyer_postcode: String? - public var notice_url: Array? + public var notice_url: [String]? public var display: CardQuota? public var digital: Bool? // default false public var vbank_due: String? // YYYYMMDDhhmm - private var m_redirect_url: String? = CONST.IAMPORT_DETECT_URL // 콜백 + private var m_redirect_url: String? = Constant.IAMPORT_DETECT_URL // 콜백 public var app_scheme: String? // 명세상 nilable 이나 RN 에서 필수 public var biz_num: String? public var popup: Bool? // 엑심베이일때 false 로 해야 열림 private var niceMobileV2: Bool? = true - // 네이버 관련 public var naverPopupMode: Bool? public var naverUseCfm: String? @@ -72,14 +71,12 @@ public class IamPortRequest: Codable, Then { } } -extension IamPortRequest { +extension IamportPayment { /** * string pg 으로 enum PG 가져옴 */ var pgEnum: PG? { - get { - PG.convertPG(pgString: pg) - } + PG.convertPG(pgString: pg) } public func setPlatform(platform: String) { @@ -89,5 +86,4 @@ extension IamPortRequest { m_redirect_url = Utils.getRedirectUrl(platformKey: platform) } } - } diff --git a/Sources/iamport-ios/Classes/Data/IamportRequest.swift b/Sources/iamport-ios/Classes/Data/IamportRequest.swift new file mode 100644 index 0000000..b304a2c --- /dev/null +++ b/Sources/iamport-ios/Classes/Data/IamportRequest.swift @@ -0,0 +1,89 @@ +// +// Created by BingBong on 2021/01/07. +// + +import Foundation +import Then + +enum IamportPayload: Codable { + case payment(IamportPayment) + case certification(IamportCertification) +} + +struct IamportRequest: Codable, Then { + let userCode: String + let tierCode: String? + var payload: IamportPayload + + init(userCode: String, tierCode: String? = nil, payment: IamportPayment) { + self.userCode = userCode + self.tierCode = tierCode + payload = .payment(payment) + } + + init(userCode: String, tierCode: String? = nil, certification: IamportCertification) { + self.userCode = userCode + self.tierCode = tierCode + payload = .certification(certification) + } + + var isCertification: Bool { + switch payload { + case .payment: + return true + default: + return false + } + } + + func getMerchantUid() -> String { + switch payload { + case let .payment(payment): return payment.merchant_uid + case let .certification(certification): return certification.merchant_uid + } + } + + func getCustomerUid() -> String? { + switch payload { + case let .payment(payment): return payment.customer_uid + // TODO: throw error instead + case let .certification(certification): return nil + } + } + + static func validator(_ request: IamportRequest, _ validateResult: @escaping ((Bool, String)) -> Void) { + var validResult = (true, Constant.PASS_PAYMENT_VALIDATOR) + guard case let .payment(payment) = request.payload else { return } + + payment.do { it in + + let payMethod = it.pay_method + + if payMethod == PayMethod.vbank.rawValue { + if it.vbank_due.nilOrEmpty { + validResult = (false, Constant.ERR_PAYMENT_VALIDATOR_VBANK) + } + } + + if payMethod == PayMethod.phone.rawValue { + if it.digital == nil { + validResult = (false, Constant.ERR_PAYMENT_VALIDATOR_PHONE) + } + } + + if PG.convertPG(pgString: it.pg) == PG.danal_tpay && payMethod == PayMethod.vbank.rawValue { + if it.biz_num.nilOrEmpty { + validResult = (false, Constant.ERR_PAYMENT_VALIDATOR_DANAL_VBANK) + } + } + + if PG.convertPG(pgString: it.pg) == PG.eximbay { + if it.popup == nil || it.popup == true { + validResult = (false, Constant.ERR_PAYMENT_VALIDATOR_EXIMBAY) + } + } + } + + validateResult(validResult) + } +} diff --git a/Sources/iamport-ios/Classes/Data/IamPortResponse.swift b/Sources/iamport-ios/Classes/Data/IamportResponse.swift similarity index 74% rename from Sources/iamport-ios/Classes/Data/IamPortResponse.swift rename to Sources/iamport-ios/Classes/Data/IamportResponse.swift index 1d43949..3933a3a 100644 --- a/Sources/iamport-ios/Classes/Data/IamPortResponse.swift +++ b/Sources/iamport-ios/Classes/Data/IamportResponse.swift @@ -5,16 +5,16 @@ import Foundation import Then -public class IamPortResponse: Encodable, Then { +public class IamportResponse: Encodable, Then { public var imp_success: Bool? = false public var success: Bool? = false public var imp_uid: String? public var merchant_uid: String? - public var error_msg: String? = nil - public var error_code: String? = nil + public var error_msg: String? + public var error_code: String? - static func structToClass(_ impStruct: IamPortResponseStruct) -> IamPortResponse { - IamPortResponse().then { it in + static func structToClass(_ impStruct: IamPortResponseStruct) -> IamportResponse { + IamportResponse().then { it in it.imp_success = impStruct.imp_success it.success = impStruct.success it.imp_uid = impStruct.imp_uid @@ -24,9 +24,8 @@ public class IamPortResponse: Encodable, Then { } } - - static func makeSuccess(payment: Payment, prepareData: PrepareData? = nil, msg: String) -> IamPortResponse { - IamPortResponse().then { it in + static func makeSuccess(payment: IamportRequest, prepareData: PrepareData? = nil, msg: String) -> IamportResponse { + IamportResponse().then { it in it.imp_success = true it.success = true it.imp_uid = prepareData?.impUid @@ -35,8 +34,8 @@ public class IamPortResponse: Encodable, Then { } } - static func makeFail(payment: Payment, prepareData: PrepareData? = nil, msg: String) -> IamPortResponse { - IamPortResponse().then { it in + static func makeFail(payment: IamportRequest, prepareData: PrepareData? = nil, msg: String) -> IamportResponse { + IamportResponse().then { it in it.imp_success = false it.success = false it.imp_uid = prepareData?.impUid @@ -46,9 +45,8 @@ public class IamPortResponse: Encodable, Then { } } -extension IamPortResponse: CustomStringConvertible { +extension IamportResponse: CustomStringConvertible { public var description: String { - let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted let jsonData = try? encoder.encode(self) @@ -56,14 +54,14 @@ extension IamPortResponse: CustomStringConvertible { return responseJson } else { return """ - IamPortResponse :: - imp_success: \(String(describing: imp_success)) - success: \(String(describing: success)) - imp_uid: \(String(describing: imp_uid)) - merchant_uid : \(String(describing: merchant_uid)) - error_msg: \(String(describing: error_msg)) - error_code: \(String(describing: error_code))) - """ + IamPortResponse :: + imp_success: \(String(describing: imp_success)) + success: \(String(describing: success)) + imp_uid: \(String(describing: imp_uid)) + merchant_uid : \(String(describing: merchant_uid)) + error_msg: \(String(describing: error_msg)) + error_code: \(String(describing: error_code))) + """ } } } @@ -83,7 +81,6 @@ public struct IamPortResponseStruct { extension IamPortResponseStruct: Decodable { public init(from decoder: Decoder) throws { - let values = try decoder.container(keyedBy: CodingKeys.self) let decodeImp_success = try? values.decode(String.self, forKey: .imp_success) @@ -112,4 +109,3 @@ extension IamPortResponseStruct: Decodable { error_msg = try? values.decode(String.self, forKey: .error_msg) } } - diff --git a/Sources/iamport-ios/Classes/Data/NaverInterface.swift b/Sources/iamport-ios/Classes/Data/NaverInterface.swift index c224306..dbeea38 100644 --- a/Sources/iamport-ios/Classes/Data/NaverInterface.swift +++ b/Sources/iamport-ios/Classes/Data/NaverInterface.swift @@ -10,4 +10,4 @@ public class NaverInterface: Codable { var saClickId: String? var merchantCustomCode1: String? var merchantCustomCode2: String? -} \ No newline at end of file +} diff --git a/Sources/iamport-ios/Classes/Data/PG.swift b/Sources/iamport-ios/Classes/Data/PG.swift index d4f07d6..482f9ad 100644 --- a/Sources/iamport-ios/Classes/Data/PG.swift +++ b/Sources/iamport-ios/Classes/Data/PG.swift @@ -5,11 +5,9 @@ import Foundation public enum PG: String, CaseIterable, Codable { - case chai case kcp case html5_inicis // only for 결제 -// case inicis // only for 본인인증 case kcp_billing case uplus case jtnet @@ -85,15 +83,13 @@ public enum PG: String, CaseIterable, Codable { return "토스페이" case .smartro: return "스마트로" -// case .inicis: -// return "이니시스본인인증" } } public func makePgRawName(pgId: String? = nil) -> String { - var id: String = CONST.EMPTY_STR + var id: String = Constant.EMPTY_STR if let pg = pgId { - if (pg.count > 0) { + if pg.count > 0 { id = ".\(pg)" } } @@ -101,18 +97,12 @@ public enum PG: String, CaseIterable, Codable { } public static func convertPG(pgString: String) -> PG? { - for value in self.allCases { - if (pgString == value.rawValue) { + for value in allCases { + if pgString == value.rawValue { return value } } return nil } - -// static func getPGNames() -> Array { -// values().map { -// "${it.korName} (${it.name})" -// }.toList() -// } -} \ No newline at end of file +} diff --git a/Sources/iamport-ios/Classes/Data/PayMethod.swift b/Sources/iamport-ios/Classes/Data/PayMethod.swift index 847a10e..10a829e 100644 --- a/Sources/iamport-ios/Classes/Data/PayMethod.swift +++ b/Sources/iamport-ios/Classes/Data/PayMethod.swift @@ -78,8 +78,8 @@ public enum PayMethod: String, CaseIterable, Codable { } public static func convertPayMethod(_ payMethodString: String) -> PayMethod { - for value in self.allCases { - if (payMethodString == value.rawValue) { + for value in allCases { + if payMethodString == value.rawValue { return value } } diff --git a/Sources/iamport-ios/Classes/Data/Payment.swift b/Sources/iamport-ios/Classes/Data/Payment.swift deleted file mode 100644 index 8836a79..0000000 --- a/Sources/iamport-ios/Classes/Data/Payment.swift +++ /dev/null @@ -1,85 +0,0 @@ -// -// Created by BingBong on 2021/01/07. -// - -import Foundation -import Then - -struct Payment: Codable, Then { - let userCode: String - var tierCode: String? = nil - var iamPortRequest: IamPortRequest? - var iamPortCertification: IamPortCertification? - - init(userCode: String, tierCode: String? = nil, iamPortRequest: IamPortRequest) { - self.userCode = userCode - self.tierCode = tierCode - self.iamPortRequest = iamPortRequest - } - - init(userCode: String, tierCode: String? = nil, iamPortCertification: IamPortCertification) { - self.userCode = userCode - self.tierCode = tierCode - self.iamPortCertification = iamPortCertification - } - - func isCertification() -> Bool { - if iamPortCertification != nil { - return true - } else { - return false - } - } - - func getMerchantUid() -> String { - if (isCertification()) { - return iamPortCertification?.merchant_uid ?? CONST.EMPTY_STR - } - return iamPortRequest?.merchant_uid ?? CONST.EMPTY_STR - } - - func getCustomerUid() -> String { - if (isCertification()) { - return CONST.EMPTY_STR - } - return iamPortRequest?.customer_uid ?? CONST.EMPTY_STR - } - - static func validator(_ payment: Payment, _ validateResult: @escaping ((Bool, String)) -> Void) { - - var validResult = ((true, CONST.PASS_PAYMENT_VALIDATOR)) - - payment.iamPortRequest?.do { it in - - let payMethod = it.pay_method - - if (payMethod == PayMethod.vbank.rawValue) { - if (it.vbank_due.nilOrEmpty) { - validResult = (false, CONST.ERR_PAYMENT_VALIDATOR_VBANK) - } - } - - if (payMethod == PayMethod.phone.rawValue) { - if (it.digital == nil) { - validResult = (false, CONST.ERR_PAYMENT_VALIDATOR_PHONE) - } - } - - if (PG.convertPG(pgString: it.pg) == PG.danal_tpay && payMethod == PayMethod.vbank.rawValue) { - if (it.biz_num.nilOrEmpty) { - validResult = (false, CONST.ERR_PAYMENT_VALIDATOR_DANAL_VBANK) - } - } - - if (PG.convertPG(pgString: it.pg) == PG.eximbay) { - if (it.popup == nil || it.popup == true) { - validResult = (false, CONST.ERR_PAYMENT_VALIDATOR_EXIMBAY) - } - } - - } - - validateResult(validResult) - } - -} diff --git a/Sources/iamport-ios/Classes/Data/Period.swift b/Sources/iamport-ios/Classes/Data/Period.swift index b56f99a..7b2cd7a 100644 --- a/Sources/iamport-ios/Classes/Data/Period.swift +++ b/Sources/iamport-ios/Classes/Data/Period.swift @@ -4,13 +4,12 @@ import Foundation - // 이니시스 정기결제 제공기간 옵션 // 참조 : https://guide.iamport.kr/32498112-82c4-44cb-a23a-ef5b896ee548 public class Period: Codable { var from: String // YYYYMMDD var to: String // YYYYMMDD - public init(from: String, to: String) { + public init(from: String, to: String) { self.from = from self.to = to } diff --git a/Sources/iamport-ios/Classes/Data/Platform.swift b/Sources/iamport-ios/Classes/Data/Platform.swift index 026f78f..ae551b6 100644 --- a/Sources/iamport-ios/Classes/Data/Platform.swift +++ b/Sources/iamport-ios/Classes/Data/Platform.swift @@ -14,7 +14,7 @@ public enum Platform: String, CaseIterable { var redirectUrl: String { switch self { case .native: - return CONST.IAMPORT_DETECT_URL + return Constant.IAMPORT_DETECT_URL case .reactnative: return Utils.getRedirectUrl(platformKey: "rn") case .flutter: @@ -27,13 +27,12 @@ public enum Platform: String, CaseIterable { } static func convertPlatform(platformStr: String) -> Platform? { - for value in self.allCases { - if (platformStr == value.rawValue) { + for value in allCases { + if platformStr == value.rawValue { return value } } return nil } - } diff --git a/Sources/iamport-ios/Classes/Data/PrepareData.swift b/Sources/iamport-ios/Classes/Data/PrepareData.swift index 8663289..23e0397 100644 --- a/Sources/iamport-ios/Classes/Data/PrepareData.swift +++ b/Sources/iamport-ios/Classes/Data/PrepareData.swift @@ -12,12 +12,13 @@ struct PrepareData: Codable { let returnUrl: String let publicAPIKey: String var mode: String? = nil - var isSbcr: Bool? // FIXME : 서버 배포 후 non nullable 로 수정해야댐 + var isSbcr: Bool? // FIXME: 서버 배포 후 non nullable 로 수정해야댐 init(impUid: String, paymentId: String? = nil, subscriptionId: String? = nil, idempotencyKey: String, returnUrl: String, publicAPIKey: String, - isSbcr: Bool?) { + isSbcr: Bool?) + { self.impUid = impUid self.paymentId = paymentId self.subscriptionId = subscriptionId @@ -38,4 +39,4 @@ struct PrepareDataError: Codable { self.errorCode = errorCode self.errorMsg = errorMsg } -} \ No newline at end of file +} diff --git a/Sources/iamport-ios/Classes/Data/PrepareRequest.swift b/Sources/iamport-ios/Classes/Data/PrepareRequest.swift index 4611f42..0eff91b 100644 --- a/Sources/iamport-ios/Classes/Data/PrepareRequest.swift +++ b/Sources/iamport-ios/Classes/Data/PrepareRequest.swift @@ -6,14 +6,13 @@ import Foundation import Then class PrepareRequest: DictionaryEncodable, Then { - - var channel: String = CHAI.CHANNEL //fixed - var provider: PG = PG.chai //fixed - var pay_method: String = PayMethod.trans.rawValue //fixed + var channel: String = CHAI.CHANNEL // fixed + var provider: PG = .chai // fixed + var pay_method: String = PayMethod.trans.rawValue // fixed var escrow: Bool? // true or false var amount: String // 결제금액 var tax_free: Float? // 결제금액 중 면세공급가액 - var name: String //주문명 + var name: String // 주문명 var merchant_uid: String // 가맹점 주문번호 var customer_uid: String? var user_code: String // 아임포트 가맹점 식별코드 @@ -26,7 +25,7 @@ class PrepareRequest: DictionaryEncodable, Then { var buyer_postcode: String? // 구매자 우편번호 var app_scheme: String? // 결제 후 돌아갈 app scheme var custom_data: String? // 결제 건에 연결해 저장할 meta data - var notice_url: Array? // Webhook Url + var notice_url: [String]? // Webhook Url var confirm_url: String? // Confirm process Url var _extra: Extra // 차이 마케팅 팀과 사전협의된 파라메터 @@ -39,41 +38,35 @@ class PrepareRequest: DictionaryEncodable, Then { self._extra = _extra } - - static func make(chaiId: String, payment: Payment) -> PrepareRequest? { - - guard let request = payment.iamPortRequest else { + static func make(chaiId: String, request: IamportRequest) -> PrepareRequest? { + guard case let .payment(payment) = request.payload else { print("PrepareRequest, make, iamPortRequest is nil") return nil } - let empty = CONST.EMPTY_STR - - return PrepareRequest(user_code: payment.userCode, - merchant_uid: request.merchant_uid, - amount: request.amount, - name: Utils.getOrEmpty(value: request.name), - pg_id: chaiId, - _extra: Extra(native: OS.ios, bypass: empty)).then { + return PrepareRequest(user_code: request.userCode, + merchant_uid: payment.merchant_uid, + amount: payment.amount, + name: Utils.getOrEmpty(value: payment.name), + pg_id: chaiId, + _extra: Extra(native: OS.ios, bypass: Constant.EMPTY_STR)).then { $0.escrow = false - $0.tax_free = request.tax_free - $0.tier_code = empty - $0.buyer_name = request.buyer_name - $0.buyer_email = request.buyer_email - $0.buyer_tel = request.buyer_tel - $0.buyer_addr = request.buyer_addr - $0.buyer_postcode = request.buyer_postcode - $0.app_scheme = request.app_scheme - $0.custom_data = request.custom_data - $0.notice_url = request.notice_url - $0.customer_uid = request.customer_uid - $0.confirm_url = request.confirm_url + $0.tax_free = payment.tax_free + $0.tier_code = Constant.EMPTY_STR + $0.buyer_name = payment.buyer_name + $0.buyer_email = payment.buyer_email + $0.buyer_tel = payment.buyer_tel + $0.buyer_addr = payment.buyer_addr + $0.buyer_postcode = payment.buyer_postcode + $0.app_scheme = payment.app_scheme + $0.custom_data = payment.custom_data + $0.notice_url = payment.notice_url + $0.customer_uid = payment.customer_uid + $0.confirm_url = payment.confirm_url } } - static func makeDictionary(chaiId: String, payment: Payment) -> [String: Any]? { - make(chaiId: chaiId, payment: payment)?.dictionary() + static func makeDictionary(chaiId: String, payment: IamportRequest) -> [String: Any]? { + make(chaiId: chaiId, request: payment)?.dictionary() } - } - diff --git a/Sources/iamport-ios/Classes/Data/ProductItem.swift b/Sources/iamport-ios/Classes/Data/ProductItem.swift index ff62812..7e5bdd0 100644 --- a/Sources/iamport-ios/Classes/Data/ProductItem.swift +++ b/Sources/iamport-ios/Classes/Data/ProductItem.swift @@ -5,10 +5,8 @@ import Foundation import Then - public class BaseProduct: Codable, Then { - public init() { - } + public init() {} } public class ProductItem: BaseProduct { @@ -27,225 +25,214 @@ public class ProductItem: BaseProduct { startDate, endDate, sellerId, count } - public override func encode(to encoder: Encoder) throws { + override public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - if (categoryType != nil) { + if categoryType != nil { try container.encode(categoryType, forKey: .categoryType) } - if (categoryId != nil) { + if categoryId != nil { try container.encode(categoryId, forKey: .categoryId) } - if (uid != nil) { + if uid != nil { try container.encode(uid, forKey: .uid) } - if (name != nil) { + if name != nil { try container.encode(name, forKey: .name) } - if (payReferrer != nil) { + if payReferrer != nil { try container.encode(payReferrer, forKey: .payReferrer) } - if (startDate != nil) { + if startDate != nil { try container.encode(startDate, forKey: .startDate) } - if (endDate != nil) { + if endDate != nil { try container.encode(endDate, forKey: .endDate) } - if (sellerId != nil) { + if sellerId != nil { try container.encode(sellerId, forKey: .sellerId) } - if (count != nil) { + if count != nil { try container.encode(count, forKey: .count) } } } - public class ProductItemForOrder: BaseProduct { - public var id: String? //상품고유ID - public var merchantProductId: String? //상품관리ID(필요한 경우만 선언. 정의하지 않으면 id값과 동일한 값을 자동 적용합니다) - public var ecMallProductId: String? //지식쇼핑상품관리ID(필요한 경우만 선언. 정의하지 않으면 id값과 동일한 값을 자동 적용합니다) - public var name: String? //상품명 - public var basePrice: Int? //상품가격 - public var taxType: String? //부가세 부과 여부(TAX or TAX_FREE) - public var quantity: Int? //상품구매수량 - public var infoUrl: String? //상품상세페이지 URL - public var imageUrl: String? //상품 Thumbnail 이미지 URL - public var giftName: String? //해당상품 구매시 제공되는 사은품 명칭(없으면 정의하지 않음) - public var options: Array? //구매자가 선택한 상품 옵션에 대한 상세 정보 - public var supplements: Array? - public var shipping: Shipping? //상품 배송관련 상세 정보 + public var id: String? // 상품고유ID + public var merchantProductId: String? // 상품관리ID(필요한 경우만 선언. 정의하지 않으면 id값과 동일한 값을 자동 적용합니다) + public var ecMallProductId: String? // 지식쇼핑상품관리ID(필요한 경우만 선언. 정의하지 않으면 id값과 동일한 값을 자동 적용합니다) + public var name: String? // 상품명 + public var basePrice: Int? // 상품가격 + public var taxType: String? // 부가세 부과 여부(TAX or TAX_FREE) + public var quantity: Int? // 상품구매수량 + public var infoUrl: String? // 상품상세페이지 URL + public var imageUrl: String? // 상품 Thumbnail 이미지 URL + public var giftName: String? // 해당상품 구매시 제공되는 사은품 명칭(없으면 정의하지 않음) + public var options: [ProductOption]? // 구매자가 선택한 상품 옵션에 대한 상세 정보 + public var supplements: [Supplement]? + public var shipping: Shipping? // 상품 배송관련 상세 정보 private enum CodingKeys: String, CodingKey { case id, merchantProductId, ecMallProductId, name, basePrice, taxType, quantity, infoUrl, imageUrl, giftName, options, supplements, shipping } - public override func encode(to encoder: Encoder) throws { + override public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - if (id != nil) { + if id != nil { try container.encode(id, forKey: .id) } - if (merchantProductId != nil) { + if merchantProductId != nil { try container.encode(merchantProductId, forKey: .merchantProductId) } - if (ecMallProductId != nil) { + if ecMallProductId != nil { try container.encode(ecMallProductId, forKey: .ecMallProductId) } - if (name != nil) { + if name != nil { try container.encode(name, forKey: .name) } - if (basePrice != nil) { + if basePrice != nil { try container.encode(basePrice, forKey: .basePrice) } - if (taxType != nil) { + if taxType != nil { try container.encode(taxType, forKey: .taxType) } - if (quantity != nil) { + if quantity != nil { try container.encode(quantity, forKey: .quantity) } - if (infoUrl != nil) { + if infoUrl != nil { try container.encode(infoUrl, forKey: .infoUrl) } - if (imageUrl != nil) { + if imageUrl != nil { try container.encode(imageUrl, forKey: .imageUrl) } - if (giftName != nil) { + if giftName != nil { try container.encode(giftName, forKey: .giftName) } - if (options != nil) { + if options != nil { try container.encode(options, forKey: .options) } - if (supplements != nil) { + if supplements != nil { try container.encode(supplements, forKey: .supplements) } - if (shipping != nil) { + if shipping != nil { try container.encode(shipping, forKey: .shipping) } } } - // 확실치 않은 정보들은 nullable 처리.. 어차피 네이버가 따로 검수! public class ProductOption: Codable, Then { public var optionQuantity: Int? public var optionPrice: Int? public var selectionCode: String? - public var selections: Array? - public init() { - } + public var selections: [Selection]? + public init() {} } public class Selection: Codable, Then { public var code: String? public var label: String? public var value: String? - public init() { - } + public init() {} } public class Supplement: Codable, Then { - public var id: String? //추가구성품의 ID - public var name: String? //추가구성품 상품명 - public var price: Int? //추가구성품 가격 - public var quantity: Int? //추가구성품 수량 - public init() { - } + public var id: String? // 추가구성품의 ID + public var name: String? // 추가구성품 상품명 + public var price: Int? // 추가구성품 가격 + public var quantity: Int? // 추가구성품 수량 + public init() {} } public class Shipping: Codable, Then { public var groupId: String? public var method: String? public var baseFee: Int? - public var feeRule: Array? + public var feeRule: [FeeRule]? public var feePayType: String? - public init() { - } + public init() {} } public class FeeRule: Codable, Then { public var freeByThreshold: Int? - public init() { - } + public init() {} } - - /** -Json 로그로 확인해보기 - - let productItem = ProductItem().then { - $0.name = "name" - $0.uid = "uid" - $0.payReferrer = "uid" - $0.count = 3 - } - - let productItemForOrder = ProductItemForOrder().then { - $0.name = "name" - $0.merchantProductId = "merchantProductId" - $0.taxType = "taxType" - $0.imageUrl = "http://imageUrlimageUrl" - $0.basePrice = 3 - $0.quantity = 5 - - $0.options = [ - ProductOption().then { option in - option.optionQuantity = 888 - option.optionPrice = 555 - option.selections = [ - Selection().then { selection in - selection.code = "0" - selection.value = "레드" - selection.label = "빨간맛" - }, - Selection().then { selection in - selection.code = "1" - selection.value = "그린" - selection.label = "초록맛" - }, - - Selection().then { selection in - selection.code = "2" - selection.value = "블루" - selection.label = "파란맛" - } - ] - } - ] - $0.supplements = [ - Supplement().then { supplement in - supplement.id = "id" - supplement.name = "name" - supplement.price = 239847329 - } - ] - $0.shipping = Shipping().then { - $0.groupId = "groupId" - $0.baseFee = 999 - $0.feeRule = [FeeRule().then { - $0.freeByThreshold = 1 - }, FeeRule().then { - $0.freeByThreshold = 2 - }, FeeRule().then { - $0.freeByThreshold = 3 - }] - } - - } - - request.naverProducts = [productItem, productItem, productItemForOrder, productItemForOrder] - - let encoder = JSONEncoder() - encoder.outputFormatting = .prettyPrinted - let jsonData = try? encoder.encode(request) - debugPrint("====================") - if let json = jsonData, - let request = String(data: json, encoding: .utf8) { - debugPrint(request) - } - debugPrint("====================") - - - - */ + Json 로그로 확인해보기 + + let productItem = ProductItem().then { + $0.name = "name" + $0.uid = "uid" + $0.payReferrer = "uid" + $0.count = 3 + } + + let productItemForOrder = ProductItemForOrder().then { + $0.name = "name" + $0.merchantProductId = "merchantProductId" + $0.taxType = "taxType" + $0.imageUrl = "http://imageUrlimageUrl" + $0.basePrice = 3 + $0.quantity = 5 + + $0.options = [ + ProductOption().then { option in + option.optionQuantity = 888 + option.optionPrice = 555 + option.selections = [ + Selection().then { selection in + selection.code = "0" + selection.value = "레드" + selection.label = "빨간맛" + }, + Selection().then { selection in + selection.code = "1" + selection.value = "그린" + selection.label = "초록맛" + }, + + Selection().then { selection in + selection.code = "2" + selection.value = "블루" + selection.label = "파란맛" + } + ] + } + ] + $0.supplements = [ + Supplement().then { supplement in + supplement.id = "id" + supplement.name = "name" + supplement.price = 239847329 + } + ] + $0.shipping = Shipping().then { + $0.groupId = "groupId" + $0.baseFee = 999 + $0.feeRule = [FeeRule().then { + $0.freeByThreshold = 1 + }, FeeRule().then { + $0.freeByThreshold = 2 + }, FeeRule().then { + $0.freeByThreshold = 3 + }] + } + + } + + request.naverProducts = [productItem, productItem, productItemForOrder, productItemForOrder] + + let encoder = JSONEncoder() + encoder.outputFormatting = .prettyPrinted + let jsonData = try? encoder.encode(request) + debugPrint("====================") + if let json = jsonData, + let request = String(data: json, encoding: .utf8) { + debugPrint(request) + } + debugPrint("====================") + + */ diff --git a/Sources/iamport-ios/Classes/Data/ProvidePgScheme.swift b/Sources/iamport-ios/Classes/Data/ProvidePgScheme.swift index 76d4854..aafc3cb 100644 --- a/Sources/iamport-ios/Classes/Data/ProvidePgScheme.swift +++ b/Sources/iamport-ios/Classes/Data/ProvidePgScheme.swift @@ -5,8 +5,7 @@ import Foundation public enum ProvidePgScheme: String, CaseIterable { - -// url 에서 제공하지 않는 PG와 앱 패키지 + // url 에서 제공하지 않는 PG와 앱 패키지 case BANKPAY = "kftc-bankpay" case ISP = "ispmobile" case KB_BANKPAY = "kb-bankpay" @@ -19,7 +18,7 @@ public enum ProvidePgScheme: String, CaseIterable { func getNiceBankPayPrefix() -> String { let process = "://eftpay?" - return "\(self.rawValue)\(process)" + return "\(rawValue)\(process)" } // func getNiceBankPayAppCls() -> String { diff --git a/Sources/iamport-ios/Classes/Data/UserData.swift b/Sources/iamport-ios/Classes/Data/UserData.swift index 59dbf29..e6e9894 100644 --- a/Sources/iamport-ios/Classes/Data/UserData.swift +++ b/Sources/iamport-ios/Classes/Data/UserData.swift @@ -18,4 +18,4 @@ struct UserData: Codable, Then { self.sandbox = sandbox self.type = type } -} \ No newline at end of file +} diff --git a/Sources/iamport-ios/Classes/Data/Users.swift b/Sources/iamport-ios/Classes/Data/Users.swift index f00980b..6aff157 100644 --- a/Sources/iamport-ios/Classes/Data/Users.swift +++ b/Sources/iamport-ios/Classes/Data/Users.swift @@ -8,9 +8,9 @@ import Then struct Users: Codable, Then { var code: Int var msg: String? - var data: Array + var data: [UserData] - public init(code: Int, msg: String?, data: Array) { + public init(code: Int, msg: String?, data: [UserData]) { self.code = code self.msg = msg self.data = data diff --git a/Sources/iamport-ios/Classes/Domain/Iamport.swift b/Sources/iamport-ios/Classes/Domain/Iamport.swift index 590de79..9cdef8a 100644 --- a/Sources/iamport-ios/Classes/Domain/Iamport.swift +++ b/Sources/iamport-ios/Classes/Domain/Iamport.swift @@ -3,17 +3,16 @@ // import Foundation -import WebKit -import RxSwift import RxCocoa +import RxSwift +import WebKit // 머천트에서 직접 가져다가 쓰는 부분 open class Iamport { - public static let shared = Iamport() private var sdk: IamportSdk? - private var paymentResult: ((IamPortResponse?) -> Void)? // 결제 결과 callback + private var paymentResult: ((IamportResponse?) -> Void)? // 결제 결과 callback private var animate = true private var useNaviButton = false @@ -22,27 +21,20 @@ open class Iamport { HTTPCookieStorage.shared.cookieAcceptPolicy = HTTPCookie.AcceptPolicy.always } - private func clear() { - sdk?.clearData() - sdk = nil - paymentResult = nil - } - - private func paymentStart(sdk: IamportSdk, userCode: String, tierCode: String? = nil, iamPortRequest: IamPortRequest, approveCallback: ((IamPortApprove) -> Void)? = nil, paymentResultCallback: @escaping (IamPortResponse?) -> Void) { + private func startPayment(sdk: IamportSdk, userCode: String, tierCode: String? = nil, payment: IamportPayment, approveCallback: ((IamPortApprove) -> Void)? = nil, paymentResultCallback: @escaping (IamportResponse?) -> Void) { paymentResult = paymentResultCallback self.sdk = sdk sdk.animate = animate sdk.useNaviButton = useNaviButton - sdk.initStart(payment: Payment(userCode: userCode, tierCode: tierCode, iamPortRequest: iamPortRequest), approveCallback: approveCallback, paymentResultCallback: paymentResultCallback) + sdk.initStart(request: IamportRequest(userCode: userCode, tierCode: tierCode, payment: payment), approveCallback: approveCallback, paymentResultCallback: paymentResultCallback) } - - private func certStart(sdk: IamportSdk, userCode: String, tierCode: String? = nil, iamPortCertification: IamPortCertification, certificationResultCallback: @escaping (IamPortResponse?) -> Void) { + private func startCertification(sdk: IamportSdk, userCode: String, tierCode: String? = nil, certification: IamportCertification, certificationResultCallback: @escaping (IamportResponse?) -> Void) { paymentResult = certificationResultCallback self.sdk = sdk sdk.animate = animate sdk.useNaviButton = useNaviButton - sdk.initStart(payment: Payment(userCode: userCode, tierCode: tierCode, iamPortCertification: iamPortCertification), certificationResultCallback: certificationResultCallback) + sdk.initStart(request: IamportRequest(userCode: userCode, tierCode: tierCode, certification: certification), certificationResultCallback: certificationResultCallback) } /** @@ -54,29 +46,24 @@ open class Iamport { - paymentResultCallback: 결제 후 콜백 함수 */ - public func payment(navController: UINavigationController, userCode: String, tierCode: String? = nil, iamPortRequest: IamPortRequest, approveCallback: ((IamPortApprove) -> Void)? = nil, paymentResultCallback: @escaping (IamPortResponse?) -> Void) { + public func payment(navController: UINavigationController, userCode: String, tierCode: String? = nil, payment: IamportPayment, approveCallback: ((IamPortApprove) -> Void)? = nil, paymentResultCallback: @escaping (IamportResponse?) -> Void) { print("IamPort SDK payment for navController mode") - clear() - paymentStart(sdk: IamportSdk(naviController: navController), userCode: userCode, tierCode: tierCode, iamPortRequest: iamPortRequest, approveCallback: approveCallback, paymentResultCallback: paymentResultCallback) + startPayment(sdk: IamportSdk(navController: navController), userCode: userCode, tierCode: tierCode, payment: payment, approveCallback: approveCallback, paymentResultCallback: paymentResultCallback) } - public func payment(viewController: UIViewController, userCode: String, tierCode: String? = nil, iamPortRequest: IamPortRequest, approveCallback: ((IamPortApprove) -> Void)? = nil, paymentResultCallback: @escaping (IamPortResponse?) -> Void) { + public func payment(viewController: UIViewController, userCode: String, tierCode: String? = nil, payment: IamportPayment, approveCallback: ((IamPortApprove) -> Void)? = nil, paymentResultCallback: @escaping (IamportResponse?) -> Void) { print("IamPort SDK payment for viewController mode") - clear() - paymentStart(sdk: IamportSdk(viewController: viewController), userCode: userCode, tierCode: tierCode, iamPortRequest: iamPortRequest, approveCallback: approveCallback, paymentResultCallback: paymentResultCallback) + startPayment(sdk: IamportSdk(viewController: viewController), userCode: userCode, tierCode: tierCode, payment: payment, approveCallback: approveCallback, paymentResultCallback: paymentResultCallback) } - - public func paymentWebView(webViewMode: WKWebView, userCode: String, tierCode: String? = nil, iamPortRequest: IamPortRequest, approveCallback: ((IamPortApprove) -> Void)? = nil, paymentResultCallback: @escaping (IamPortResponse?) -> Void) { + public func paymentWebView(webViewMode: WKWebView, userCode: String, tierCode: String? = nil, payment: IamportPayment, approveCallback: ((IamPortApprove) -> Void)? = nil, paymentResultCallback: @escaping (IamportResponse?) -> Void) { print("IamPort SDK payment for webview mode") - clear() - paymentStart(sdk: IamportSdk(webViewMode: webViewMode), userCode: userCode, tierCode: tierCode, iamPortRequest: iamPortRequest, approveCallback: approveCallback, paymentResultCallback: paymentResultCallback) + startPayment(sdk: IamportSdk(webViewMode: webViewMode), userCode: userCode, tierCode: tierCode, payment: payment, approveCallback: approveCallback, paymentResultCallback: paymentResultCallback) } - // (외부로 나가는 용도) webview 에 업데이트 되는 현재 url public var updateWebViewUrl = PublishRelay() @@ -86,7 +73,6 @@ open class Iamport { */ public func pluginMobileWebSupporter(mobileWebMode: WKWebView) { print("IamPort SDK payment for mobileweb mode") - clear() sdk = IamportSdk(mobileWebMode: mobileWebMode) // 생성 및 mobileWebMode 실행 } @@ -107,25 +93,22 @@ open class Iamport { - iamPortCertification: 본인인증 요청 데이터 - paymentResultCallback: 결제 후 콜백 함수 */ - public func certification(navController: UINavigationController, userCode: String, tierCode: String? = nil, iamPortCertification: IamPortCertification, certificationResultCallback: @escaping (IamPortResponse?) -> Void) { + public func certification(navController: UINavigationController, userCode: String, tierCode: String? = nil, certification: IamportCertification, certificationResultCallback: @escaping (IamportResponse?) -> Void) { print("IamPort SDK certification") - clear() - certStart(sdk: IamportSdk(naviController: navController), userCode: userCode, tierCode: tierCode, iamPortCertification: iamPortCertification, certificationResultCallback: certificationResultCallback) + startCertification(sdk: IamportSdk(navController: navController), userCode: userCode, tierCode: tierCode, certification: certification, certificationResultCallback: certificationResultCallback) } - public func certification(viewController: UIViewController, userCode: String, tierCode: String? = nil, iamPortCertification: IamPortCertification, certificationResultCallback: @escaping (IamPortResponse?) -> Void) { + public func certification(viewController: UIViewController, userCode: String, tierCode: String? = nil, iamPortCertification: IamportCertification, certificationResultCallback: @escaping (IamportResponse?) -> Void) { print("IamPort SDK certification") - clear() - certStart(sdk: IamportSdk(viewController: viewController), userCode: userCode, tierCode: tierCode, iamPortCertification: iamPortCertification, certificationResultCallback: certificationResultCallback) + startCertification(sdk: IamportSdk(viewController: viewController), userCode: userCode, tierCode: tierCode, certification: iamPortCertification, certificationResultCallback: certificationResultCallback) } - public func certification(webview: WKWebView, userCode: String, tierCode: String? = nil, iamPortCertification: IamPortCertification, certificationResultCallback: @escaping (IamPortResponse?) -> Void) { + public func certification(webview: WKWebView, userCode: String, tierCode: String? = nil, certification: IamportCertification, certificationResultCallback: @escaping (IamportResponse?) -> Void) { print("IamPort SDK certification") - clear() - certStart(sdk: IamportSdk(webViewMode: webview), userCode: userCode, tierCode: tierCode, iamPortCertification: iamPortCertification, certificationResultCallback: certificationResultCallback) + startCertification(sdk: IamportSdk(webViewMode: webview), userCode: userCode, tierCode: tierCode, certification: certification, certificationResultCallback: certificationResultCallback) } // 외부 앱 종료후 AppDelegate 에서 받은 URL @@ -142,7 +125,7 @@ open class Iamport { } public func close() { - print("IamPort SDK clear") - clear() + sdk = nil + paymentResult = nil } } diff --git a/Sources/iamport-ios/Classes/Domain/StrategyRepository.swift b/Sources/iamport-ios/Classes/Domain/StrategyRepository.swift index daf4c9c..7abb546 100644 --- a/Sources/iamport-ios/Classes/Domain/StrategyRepository.swift +++ b/Sources/iamport-ios/Classes/Domain/StrategyRepository.swift @@ -26,13 +26,11 @@ class StrategyRepository { // EventBus.shared.clearRelay.accept(()) // } - /** * PG 와 PayMethod 로 결제 타입하여 가져옴 * @return PaymentKinds */ - private func getPaymentKinds(payment: Payment) -> PaymentKinds { - + private func getPaymentKinds(request: IamportRequest) -> PaymentKinds { func isChaiPayment(pgPair: (PG, PayMethod)) -> Bool { pgPair.0 == PG.chai } @@ -45,32 +43,30 @@ class StrategyRepository { pgPair.0 == PG.html5_inicis && pgPair.1 == PayMethod.trans } - dlog(payment.iamPortRequest?.pgEnum) + guard case let .payment(payment) = request.payload else { return .WEB } - if let request = payment.iamPortRequest, let it = request.pgEnum { - let pair = (it, PayMethod.convertPayMethod(request.pay_method)) + if let it = payment.pgEnum { + let pair = (it, PayMethod.convertPayMethod(payment.pay_method)) - if (isChaiPayment(pgPair: pair)) { + if isChaiPayment(pgPair: pair) { return PaymentKinds.CHAI - } else if (isNiceTransPayment(pgPair: pair)) { + } else if isNiceTransPayment(pgPair: pair) { return PaymentKinds.NICE - } else if (isInisisTransPayment(pgPair: pair)) { + } else if isInisisTransPayment(pgPair: pair) { return PaymentKinds.INISIS } else { - return PaymentKinds.WEB } } else { - return PaymentKinds.WEB // default WEB } } - func getWebViewStrategy(_ payment: Payment) -> IStrategy { - switch getPaymentKinds(payment: payment) { + func getWebViewStrategy(_ payment: IamportRequest) -> IStrategy { + switch getPaymentKinds(request: payment) { case .NICE: return niceTransWebViewStrategy @@ -89,18 +85,16 @@ class StrategyRepository { niceTransWebViewStrategy } - func processBankPayPayment(_ payment: Payment, _ url: URL) { - if (getPaymentKinds(payment: payment) == PaymentKinds.NICE) { + func processBankPayPayment(_ payment: IamportRequest, _ url: URL) { + if getPaymentKinds(request: payment) == PaymentKinds.NICE { niceTransWebViewStrategy.processBankPayPayment(url) return } - dlog("NICE 가 아니므로 무시") + debug_log("NICE 가 아니므로 무시") } - func requestCertification(_ payment: Payment) { + func requestCertification(_ payment: IamportRequest) { certificationWebViewStrategy.doWork(payment) } - - } diff --git a/Sources/iamport-ios/Classes/Domain/Utils/AppScheme.swift b/Sources/iamport-ios/Classes/Domain/Utils/AppScheme.swift index 14e4849..89eb374 100644 --- a/Sources/iamport-ios/Classes/Domain/Utils/AppScheme.swift +++ b/Sources/iamport-ios/Classes/Domain/Utils/AppScheme.swift @@ -5,7 +5,6 @@ import Foundation enum AppScheme: CaseIterable { - case bankpay // 뱅크페이 case ispmobile // ISP/페이북 case hdcard // 현대카드 앱카드 @@ -35,7 +34,6 @@ enum AppScheme: CaseIterable { var scheme: String { switch self { - case .bankpay: return "kftc-bankpay" case .ispmobile: @@ -93,7 +91,6 @@ enum AppScheme: CaseIterable { var appID: String { switch self { - case .bankpay: return "id398456030" case .ispmobile: @@ -150,9 +147,8 @@ enum AppScheme: CaseIterable { } private static func findAppScheme(_ scheme: String) -> AppScheme? { - for value in AppScheme.allCases { - if (scheme.caseInsensitiveCompare(value.scheme) == .orderedSame) { + if scheme.caseInsensitiveCompare(value.scheme) == .orderedSame { return value } } @@ -160,7 +156,7 @@ enum AppScheme: CaseIterable { return nil } - // TODO appId 를 api 에서 받아왔으면 좋겠다.. + // TODO: appId 를 api 에서 받아왔으면 좋겠다.. static func getAppStoreUrl(scheme: String) -> String? { let appScheme = findAppScheme(scheme) @@ -172,7 +168,4 @@ enum AppScheme: CaseIterable { let marketUrl = "itms-apps://itunes.apple.com/app/\(appId)" return marketUrl } - } - - diff --git a/Sources/iamport-ios/Classes/Domain/Utils/CompletionHandlerWrapper.swift b/Sources/iamport-ios/Classes/Domain/Utils/CompletionHandlerWrapper.swift index e03f655..15a9843 100644 --- a/Sources/iamport-ios/Classes/Domain/Utils/CompletionHandlerWrapper.swift +++ b/Sources/iamport-ios/Classes/Domain/Utils/CompletionHandlerWrapper.swift @@ -21,4 +21,4 @@ class CompletionHandlerWrapper { deinit { respondHandler(defaultValue) } -} \ No newline at end of file +} diff --git a/Sources/iamport-ios/Classes/Domain/Utils/CONST.swift b/Sources/iamport-ios/Classes/Domain/Utils/Constant.swift similarity index 90% rename from Sources/iamport-ios/Classes/Domain/Utils/CONST.swift rename to Sources/iamport-ios/Classes/Domain/Utils/Constant.swift index c8abaee..68335c2 100644 --- a/Sources/iamport-ios/Classes/Domain/Utils/CONST.swift +++ b/Sources/iamport-ios/Classes/Domain/Utils/Constant.swift @@ -4,8 +4,7 @@ import Foundation -class CONST { - +class Constant { static let COLON_SLASH_SLASH = "://" static let HTTP_SCHEME = "http" @@ -27,9 +26,6 @@ class CONST { static let IAMPORT_DETECT_URL = "\(IAMPORT_DETECT_SCHEME)\(IAMPORT_DETECT_ADDRESS)" static let IAMPORT_PROD_URL = "https://service.iamport.kr" -// static let IAMPORT_PROD_URL = "http://1b8309246be2.ngrok.io" -// static let IAMPORT_TEST_URL = "https://kicc.iamport.kr" - static let CHAI_SERVICE_URL = "https://api.chai.finance" static let CHAI_SERVICE_DEV_URL = "https://api-dev.chai.finance" @@ -51,10 +47,9 @@ class CONST { static let NETWORK_TIMEOUT_SEC = 20 static let NETWORK_SHORT_TIMEOUT_SEC = 5 static let POLLING_DELAY = 1 -// + private static let TIME_OUT_ONE_MIN = 60 -// // POLLING_DELAY // 1분 단위 static let TIME_OUT_MIN = 5 // 분 static let TIME_OUT = TIME_OUT_ONE_MIN * TIME_OUT_MIN // 차이 폴링 타임아웃 @@ -63,7 +58,6 @@ class CONST { static let USER_TYPE_PAYMENT = "payment" static let USER_TYPE_CERTIFICATION = "certification" - // payment 객체 validation 관련 static let PASS_PAYMENT_VALIDATOR = "성공" @@ -72,5 +66,4 @@ class CONST { static let ERR_PAYMENT_VALIDATOR_PHONE = "\(PREFIX_ERR) 휴대폰 소액결제는 digital 항목 필수입니다" static let ERR_PAYMENT_VALIDATOR_DANAL_VBANK = "\(PREFIX_ERR) 다날 가상계좌 결제는 사업자 등록번호(biz_num) 항목 필수입니다 (계약된 사업자등록번호 10자리)" static let ERR_PAYMENT_VALIDATOR_EXIMBAY = "\(PREFIX_ERR) eximbay 는 모바일앱 결제시 IamPortRequest popup 파라미터를 false 로 지정해야 결제창이 열립니다." -// static let ERR_PAYMENT_VALIDATOR_PAYPAL = "페이팔 결제는 m_redirect_url 항목 필수입니다" } diff --git a/Sources/iamport-ios/Classes/Domain/Utils/DictionaryEncodable.swift b/Sources/iamport-ios/Classes/Domain/Utils/DictionaryEncodable.swift index 25d2d7e..a29cb27 100644 --- a/Sources/iamport-ios/Classes/Domain/Utils/DictionaryEncodable.swift +++ b/Sources/iamport-ios/Classes/Domain/Utils/DictionaryEncodable.swift @@ -4,15 +4,15 @@ import Foundation -protocol DictionaryEncodable: Encodable { -} +protocol DictionaryEncodable: Encodable {} extension DictionaryEncodable { func dictionary() -> [String: Any]? { let encoder = JSONEncoder() encoder.dateEncodingStrategy = .millisecondsSince1970 guard let json = try? encoder.encode(self), - let dict = try? JSONSerialization.jsonObject(with: json, options: []) as? [String: Any] else { + let dict = try? JSONSerialization.jsonObject(with: json, options: []) as? [String: Any] + else { return nil } return dict diff --git a/Sources/iamport-ios/Classes/Domain/Utils/EventBus.swift b/Sources/iamport-ios/Classes/Domain/Utils/EventBus.swift index 17ea4ef..0a68a67 100644 --- a/Sources/iamport-ios/Classes/Domain/Utils/EventBus.swift +++ b/Sources/iamport-ios/Classes/Domain/Utils/EventBus.swift @@ -4,24 +4,23 @@ import Foundation import RxBusForPort -import RxSwift import RxRelay +import RxSwift class EventBus { - public static let shared = EventBus() // SDK 에 결제요청 - let paymentRelay = PublishRelay() + let paymentRelay = PublishRelay() - var paymentBus: Observable { + var paymentBus: Observable { paymentRelay.asObservable() } // 실제 종료 시그널 IamportSdk 에서 사용 - let impResponseRelay = PublishRelay() + let impResponseRelay = PublishRelay() - public var impResponseBus: Observable { + public var impResponseBus: Observable { impResponseRelay.asObservable() } @@ -33,17 +32,16 @@ class EventBus { } // WebViewController 에 결제요청 - let webViewPaymentRelay = BehaviorRelay(value: nil) + let webViewPaymentRelay = BehaviorRelay(value: nil) - var webViewPaymentBus: Observable { + var webViewPaymentBus: Observable { webViewPaymentRelay.asObservable() } - struct MainEvents { - + enum MainEvents { // 현재 결제 종류 판별 struct JudgeEvent: BusEvent { - let judge: (JudgeStrategy.JudgeKinds, UserData?, Payment) + let judge: (JudgeStrategy.JudgeKinds, UserData?, IamportRequest) } // 차이앱 열기 위한 url @@ -57,21 +55,19 @@ class EventBus { } } - struct WebViewEvents { - + enum WebViewEvents { /** * WebViewController, WebViewStrategy 에서만 사용 * 결제 결과 콜백 및 종료 */ struct ImpResponse: BusEvent { - let impResponse: IamPortResponse? + let impResponse: IamportResponse? } /** * 오픈 웹뷰 이벤트 */ - struct OpenWebView: BusEvent { - } + struct OpenWebView: BusEvent {} // webview 에 업데이트 되는 현재 url struct UpdateUrl: BusEvent { @@ -82,8 +78,8 @@ class EventBus { let url: URL } - /* - 외부앱 종료시 받은 URL(for 뱅크페이 앱 처리) + /** + * 외부앱 종료시 받은 URL(for 뱅크페이 앱 처리) */ struct ReceivedAppDelegateURL: BusEvent { let url: URL @@ -102,7 +98,5 @@ class EventBus { struct ThirdPartyUri: BusEvent { let thirdPartyUri: URL } - } - -} \ No newline at end of file +} diff --git a/Sources/iamport-ios/Classes/Domain/Utils/Network.swift b/Sources/iamport-ios/Classes/Domain/Utils/Network.swift index e325e4c..3a8af02 100644 --- a/Sources/iamport-ios/Classes/Domain/Utils/Network.swift +++ b/Sources/iamport-ios/Classes/Domain/Utils/Network.swift @@ -2,16 +2,15 @@ // Created by BingBong on 2021/02/05. // -import Foundation import Alamofire +import Foundation -// TODO Alamofire -> Moya 로 변경하자 +// TODO: Alamofire -> Moya 로 변경하자 class Network { - static func getURLSessionConfiguration(useShortTimeout: Bool = false) -> URLSessionConfiguration { - var timeout = CONST.NETWORK_TIMEOUT_SEC - if (useShortTimeout) { - timeout = CONST.NETWORK_SHORT_TIMEOUT_SEC + var timeout = Constant.NETWORK_TIMEOUT_SEC + if useShortTimeout { + timeout = Constant.NETWORK_SHORT_TIMEOUT_SEC } let sessionConfiguration = URLSessionConfiguration.default.then { config in config.timeoutIntervalForRequest = TimeInterval(timeout) @@ -21,12 +20,7 @@ class Network { return sessionConfiguration } - static let alamoFireManager: Alamofire.Session = { - Alamofire.Session(configuration: getURLSessionConfiguration()) - }() - - static let alamoFireManagerShortTimeOut: Alamofire.Session = { - Alamofire.Session(configuration: getURLSessionConfiguration(useShortTimeout: true)) - }() + static let alamoFireManager: Alamofire.Session = .init(configuration: getURLSessionConfiguration()) + static let alamoFireManagerShortTimeOut: Alamofire.Session = .init(configuration: getURLSessionConfiguration(useShortTimeout: true)) } diff --git a/Sources/iamport-ios/Classes/Domain/Utils/Utils.swift b/Sources/iamport-ios/Classes/Domain/Utils/Utils.swift index 6c5b7f0..0af68f2 100644 --- a/Sources/iamport-ios/Classes/Domain/Utils/Utils.swift +++ b/Sources/iamport-ios/Classes/Domain/Utils/Utils.swift @@ -3,36 +3,35 @@ // import Foundation -import UIKit import RxSwift import SystemConfiguration +import UIKit #if !IAMPORTSPM -extension Bundle { - static var module: Bundle { - Bundle(identifier: "org.cocoapods.iamport-ios")! + extension Bundle { + static var module: Bundle { + Bundle(identifier: "org.cocoapods.iamport-ios")! + } } -} #endif -func dlog(_ log: Any...) { +func debug_log(_ log: Any..., file: String = #file, line: UInt = #line, column: UInt = #column, function: String = #function) { #if DEBUG - debugPrint(log) + debugPrint("\(file)(\(function)):\(line):\(column) \(log)") #endif } -func ddump(_ value: T) { +func debug_dump(_ value: T) { #if DEBUG - dump(value) + dump(value) #endif } extension UIView { - // 뷰컨트롤러 찾기 var viewController: UIViewController? { - if let vc = self.next as? UIViewController { + if let vc = next as? UIViewController { return vc - } else if let superView = self.superview { + } else if let superView = superview { return superView.viewController } else { return nil @@ -53,7 +52,7 @@ extension URL { } func valueOf(_ queryParameterName: String) -> String? { - guard let url = URLComponents(string: self.absoluteString) else { + guard let url = URLComponents(string: absoluteString) else { return nil } return url.queryItems?.first(where: { $0.name == queryParameterName })?.value @@ -104,14 +103,12 @@ extension Data { extension String { func trim() -> String { - return self.trimmingCharacters(in: CharacterSet.whitespaces) + return trimmingCharacters(in: CharacterSet.whitespaces) } } extension Optional where Wrapped == String { - var nilOrEmpty: Bool { - guard let strongSelf = self else { return true } @@ -120,25 +117,23 @@ extension Optional where Wrapped == String { } } - -class Utils { - - static public func getQueryStringToImpResponse(_ url: URL) -> IamPortResponse? { +enum Utils { + public static func getQueryStringToImpResponse(_ url: URL) -> IamportResponse? { #if DEBUG - dlog(url.queryParams().toJsonString()) + debug_log(url.queryParams().toJsonString()) #endif let data = url.queryParams().toJsonData() if let impStruct = try? JSONDecoder().decode(IamPortResponseStruct.self, from: data) { - return IamPortResponse.structToClass(impStruct) + return IamportResponse.structToClass(impStruct) } return nil } static func justOpenApp(_ url: URL, moveAppStore: (() -> Void)? = nil) { return UIApplication.shared.open(url, options: [:]) { openApp in - if (!openApp) { + if !openApp { if let move = moveAppStore { - dlog("앱스토어로 이동") + debug_log("앱스토어로 이동") move() } } @@ -147,7 +142,7 @@ class Utils { static func openAppWithCanOpen(_ url: URL) -> Bool { let result = UIApplication.shared.canOpenURL(url) - if (result) { + if result { justOpenApp(url) } return result @@ -158,7 +153,7 @@ class Utils { */ static func isAppUrl(_ uri: URL) -> Bool { if let it = uri.scheme { - return it != CONST.HTTP_SCHEME && it != CONST.HTTPS_SCHEME && it != CONST.ABOUT_BLANK_SCHEME && it != CONST.FILE_SCHEME; + return it != Constant.HTTP_SCHEME && it != Constant.HTTPS_SCHEME && it != Constant.ABOUT_BLANK_SCHEME && it != Constant.FILE_SCHEME } return false } @@ -167,7 +162,7 @@ class Utils { * 결제 끝났는지 여부 */ static func isPaymentOver(_ uri: URL) -> Bool { - return uri.absoluteString.contains(CONST.IAMPORT_DETECT_URL) + return uri.absoluteString.contains(Constant.IAMPORT_DETECT_URL) } static func getActionPolicy(_ uri: URL) -> Bool { @@ -175,7 +170,6 @@ class Utils { } static func isInternetAvailable() -> Bool { - var zeroAddress = sockaddr_in() zeroAddress.sin_len = UInt8(MemoryLayout.size) zeroAddress.sin_family = sa_family_t(AF_INET) @@ -201,36 +195,33 @@ class Utils { static func getOrEmpty(value: String?) -> String { if let result = value { - return !result.isEmpty ? result : CONST.EMPTY_STR + return !result.isEmpty ? result : Constant.EMPTY_STR } - return CONST.EMPTY_STR + return Constant.EMPTY_STR } - public static func delay(bySeconds seconds: Double, dispatchLevel: DispatchLevel = .userInteractive, closure: @escaping () -> Void) { let dispatchTime = DispatchTime.now() + seconds dispatchLevel.dispatchQueue.asyncAfter(deadline: dispatchTime, execute: closure) } public static func getRedirectUrl(platformKey: String) -> String { - "\(CONST.IAMPORT_DETECT_SCHEME)\(CONST.IAMPORT_DETECT_ADDRESS)/\(platformKey)" + "\(Constant.IAMPORT_DETECT_SCHEME)\(Constant.IAMPORT_DETECT_ADDRESS)/\(platformKey)" } public enum DispatchLevel { case main, userInteractive, userInitiated, utility, background var dispatchQueue: DispatchQueue { switch self { - case .main: return DispatchQueue.main - case .userInteractive: return DispatchQueue.global(qos: .userInteractive) - case .userInitiated: return DispatchQueue.global(qos: .userInitiated) - case .utility: return DispatchQueue.global(qos: .utility) - case .background: return DispatchQueue.global(qos: .background) + case .main: return DispatchQueue.main + case .userInteractive: return DispatchQueue.global(qos: .userInteractive) + case .userInitiated: return DispatchQueue.global(qos: .userInitiated) + case .utility: return DispatchQueue.global(qos: .utility) + case .background: return DispatchQueue.global(qos: .background) } } } - - } extension String { diff --git a/Sources/iamport-ios/Classes/Domain/strategy/BaseStrategy.swift b/Sources/iamport-ios/Classes/Domain/strategy/BaseStrategy.swift index c9a1bb0..9ec0de4 100644 --- a/Sources/iamport-ios/Classes/Domain/strategy/BaseStrategy.swift +++ b/Sources/iamport-ios/Classes/Domain/strategy/BaseStrategy.swift @@ -7,51 +7,46 @@ import RxBusForPort import RxSwift public class BaseStrategy: IStrategy { - var disposeBag = DisposeBag() - var payment: Payment? + var payment: IamportRequest? func clear() { payment = nil disposeBag = DisposeBag() } - func successFinish(payment: Payment, prepareData: PrepareData? = nil, msg: String) { + /** + * 성공해서 SDK 종료 + */ + func success(request: IamportRequest) { + success(request: request, msg: Constant.EMPTY_STR) + } + + func success(request: IamportRequest, prepareData: PrepareData? = nil, msg: String) { print(msg) - IamPortResponse.makeSuccess(payment: payment, prepareData: prepareData, msg: msg).do { it in - sdkFinish(it) + IamportResponse.makeSuccess(payment: request, prepareData: prepareData, msg: msg).do { it in + finish(it) } } - func failureFinish(payment: Payment, prepareData: PrepareData? = nil, msg: String) { + func failure(request: IamportRequest, prepareData: PrepareData? = nil, msg: String) { print(msg) - IamPortResponse.makeFail(payment: payment, prepareData: prepareData, msg: msg).do { it in - sdkFinish(it) + IamportResponse.makeFail(payment: request, prepareData: prepareData, msg: msg).do { it in + finish(it) } } - func sdkFinish(_ response: IamPortResponse?) { + func finish(_ response: IamportResponse?) { clear() -// RxBus.shared.post(event: EventBus.WebViewEvents.ImpResponse(impResponse: response)) EventBus.shared.impResponseRelay.accept(response) } - func doWork(_ payment: Payment) { + func doWork(_ payment: IamportRequest) { clear() self.payment = payment - EventBus.shared.clearBus.subscribe { [weak self] event in + EventBus.shared.clearBus.subscribe { [weak self] _ in self?.clear() }.disposed(by: disposeBag) - } - - - /** - * 성공해서 SDK 종료 - */ - func successFinish(payment: Payment) { - successFinish(payment: payment, msg: CONST.EMPTY_STR) - } - } diff --git a/Sources/iamport-ios/Classes/Domain/strategy/BaseWebViewStrategy.swift b/Sources/iamport-ios/Classes/Domain/strategy/BaseWebViewStrategy.swift index bcae005..36f4ec0 100644 --- a/Sources/iamport-ios/Classes/Domain/strategy/BaseWebViewStrategy.swift +++ b/Sources/iamport-ios/Classes/Domain/strategy/BaseWebViewStrategy.swift @@ -3,66 +3,65 @@ // import Foundation -import WebKit import RxBusForPort import RxSwift +import WebKit public class BaseWebViewStrategy: IStrategy { var disposeBag = DisposeBag() - var payment: Payment? + var request: IamportRequest? func clear() { - payment = nil + request = nil disposeBag = DisposeBag() } - func successFinish(payment: Payment, msg: String) { + func success(request: IamportRequest, msg: String) { print(msg) - IamPortResponse.makeSuccess(payment: payment, msg: msg).do { it in - sdkFinish(it) + IamportResponse.makeSuccess(payment: request, msg: msg).do { it in + finish(it) } } - func failureFinish(payment: Payment, msg: String) { + func failure(request: IamportRequest, msg: String) { print(msg) - IamPortResponse.makeFail(payment: payment, msg: msg).do { it in - sdkFinish(it) + IamportResponse.makeFail(payment: request, msg: msg).do { it in + finish(it) } } - func sdkFinish(_ response: IamPortResponse?) { + func finish(_ response: IamportResponse?) { clear() RxBus.shared.post(event: EventBus.WebViewEvents.ImpResponse(impResponse: response)) } - func doWork(_ payment: Payment) { + func doWork(_ payment: IamportRequest) { clear() - self.payment = payment + request = payment - EventBus.shared.clearBus.subscribe { [weak self] event in + EventBus.shared.clearBus.subscribe { [weak self] _ in self?.clear() // 종료 없이 only clear }.disposed(by: disposeBag) RxBus.shared.asObservable(event: EventBus.WebViewEvents.UpdateUrl.self) - .subscribe { [weak self] event in - guard let el = event.element else { - print("Error not found WebViewEvents") - return - } - dlog("onUpdatedUrl \(el.url)") - self?.onUpdatedUrl(url: el.url) - }.disposed(by: disposeBag) + .subscribe { [weak self] event in + guard let el = event.element else { + print("Error not found WebViewEvents") + return + } + debug_log("onUpdatedUrl \(el.url)") + self?.onUpdatedUrl(url: el.url) + }.disposed(by: disposeBag) } - func onUpdatedUrl(url: URL) { + func onUpdatedUrl(url _: URL) { // NOTHING here, use Child Strategy } /** * 성공해서 SDK 종료 */ - func successFinish(payment: Payment) { - successFinish(payment: payment, msg: CONST.EMPTY_STR) + func success(request: IamportRequest) { + success(request: request, msg: Constant.EMPTY_STR) } - } diff --git a/Sources/iamport-ios/Classes/Domain/strategy/CertificationWebViewStrategy.swift b/Sources/iamport-ios/Classes/Domain/strategy/CertificationWebViewStrategy.swift index 1619fbc..d7c682b 100644 --- a/Sources/iamport-ios/Classes/Domain/strategy/CertificationWebViewStrategy.swift +++ b/Sources/iamport-ios/Classes/Domain/strategy/CertificationWebViewStrategy.swift @@ -3,10 +3,8 @@ // import Foundation -import WebKit import RxBusForPort import RxSwift +import WebKit -class CertificationWebViewStrategy: WebViewStrategy { - -} +class CertificationWebViewStrategy: WebViewStrategy {} diff --git a/Sources/iamport-ios/Classes/Domain/strategy/ChaiStrategy.swift b/Sources/iamport-ios/Classes/Domain/strategy/ChaiStrategy.swift index e0078d8..bd6624c 100644 --- a/Sources/iamport-ios/Classes/Domain/strategy/ChaiStrategy.swift +++ b/Sources/iamport-ios/Classes/Domain/strategy/ChaiStrategy.swift @@ -2,19 +2,17 @@ // Created by BingBong on 2021/01/25. // +import Alamofire import Foundation import RxBusForPort import RxSwift -import Alamofire - -// TODO API 들을 따로 모아서 관리하기 +// TODO: API 들을 따로 모아서 관리하기 class ChaiStrategy: BaseStrategy { - var prepareData: PrepareData? var chaiId: String? - var timeOutTime: DispatchTime? //= DispatchTime.now() + var timeOutTime: DispatchTime? // = DispatchTime.now() override func clear() { chaiId = nil @@ -31,70 +29,66 @@ class ChaiStrategy: BaseStrategy { * 4. 백그라운드 chai 서버 폴링 * 5. if(차이폴링 approve) IMP 최종승인 요청 */ - func doWork(_ pgId: String, _ payment: Payment) { + func doWork(_ pgId: String, _ payment: IamportRequest) { super.doWork(payment) chaiId = pgId print("doWork! \(payment)") - //* 2. IMP 서버에 결제시작 요청 (+ chai id) + // * 2. IMP 서버에 결제시작 요청 (+ chai id) let headers: HTTPHeaders = ["Content-Type": "application/json"] - let url = CONST.IAMPORT_PROD_URL + "/chai_payments/prepare" - dlog(url) - + let url = Constant.IAMPORT_PROD_URL + "/chai_payments/prepare" + debug_log(url) let prepareRequest = PrepareRequest.makeDictionary(chaiId: pgId, payment: payment) - dlog(prepareRequest ?? "not make prepareRequest") - + debug_log(prepareRequest ?? "not make prepareRequest") let doNetwork = Network.alamoFireManager.request(url, method: .post, parameters: prepareRequest, encoding: JSONEncoding.default, headers: headers) - dlog(doNetwork) + debug_log(doNetwork) doNetwork.responseJSON { [weak self] response in switch response.result { - case .success(let data): + case let .success(data): do { - dlog(data) + debug_log(data) let dataJson = try JSONSerialization.data(withJSONObject: data, options: .prettyPrinted) - dlog(dataJson) + debug_log(dataJson) guard let getData = try? JSONDecoder().decode(Prepare.self, from: dataJson) else { let errorData = try JSONDecoder().decode(PrepareError.self, from: dataJson) - self?.failureFinish(payment: payment, msg: "code : \(errorData.code), msg : \(String(describing: errorData.msg))") + self?.failure(request: payment, msg: "code : \(errorData.code), msg : \(String(describing: errorData.msg))") return } guard getData.code == 0 else { - self?.failureFinish(payment: payment, msg: "code : \(getData.code), msg : \(String(describing: getData.msg))") + self?.failure(request: payment, msg: "code : \(getData.code), msg : \(String(describing: getData.msg))") return } - dlog(getData) + debug_log(getData) self?.processPrepare(getData.data) } catch { - self?.failureFinish(payment: payment, msg: "success but \(error.localizedDescription)") + self?.failure(request: payment, msg: "success but \(error.localizedDescription)") } - case .failure(let error): - self?.failureFinish(payment: payment, msg: "네트워크 연결실패 \(error.localizedDescription)") + case let .failure(error): + self?.failure(request: payment, msg: "네트워크 연결실패 \(error.localizedDescription)") } } } private func getChaiStatusUrl(_ prepareData: PrepareData) -> String { - guard let mode = prepareData.mode else { print("getChaiStatusUrl :: mode 가 없습니다") - return CONST.EMPTY_STR + return Constant.EMPTY_STR } let url = "\(CHAI_MODE.getChaiUrl(mode: mode))/v1/payment" - if (isSubscription(prepareData: prepareData)) { - + if isSubscription(prepareData: prepareData) { guard let subscriptionId = prepareData.subscriptionId else { print("getChaiStatusUrl :: subscriptionId 가 없습니다") - return CONST.EMPTY_STR + return Constant.EMPTY_STR } // 정기결제 상황~~ return "\(url)/subscription/\(subscriptionId)" @@ -102,33 +96,33 @@ class ChaiStrategy: BaseStrategy { guard let paymentId = prepareData.paymentId else { print("getChaiStatusUrl :: paymentId 가 없습니다") - return CONST.EMPTY_STR + return Constant.EMPTY_STR } // 일반결제~ return "\(url)/\(paymentId)" } - private func getDisplayStatus(payment: Payment, prepareData: PrepareData, dataJson: Data) -> String? { + private func getDisplayStatus(payment: IamportRequest, prepareData: PrepareData, dataJson: Data) -> String? { do { - if (isSubscription(prepareData: prepareData)) { + if isSubscription(prepareData: prepareData) { let getData = try JSONDecoder().decode(ChaiPaymentSubscription.self, from: dataJson) - ddump(getData) + debug_dump(getData) return getData.displayStatus } let getData = try JSONDecoder().decode(ChaiPayment.self, from: dataJson) - ddump(getData) + debug_dump(getData) return getData.displayStatus } catch { - failureFinish(payment: payment, msg: "success but \(error.localizedDescription)") + failure(request: payment, msg: "success but \(error.localizedDescription)") return nil } } func checkRemoteChaiStatus() { - guard let prepare = prepareData, - prepare.subscriptionId != nil || prepare.paymentId != nil else { + prepare.subscriptionId != nil || prepare.paymentId != nil + else { print("prepareData 정보 찾을 수 없음") return } @@ -136,12 +130,12 @@ class ChaiStrategy: BaseStrategy { let headers: HTTPHeaders = [ "Content-Type": "application/json", "Idempotency-Key": prepare.idempotencyKey, - "public-API-Key": prepare.publicAPIKey + "public-API-Key": prepare.publicAPIKey, ] // GET CHAI 일반결제 or 정기결제에 따라 api url 을 달리 가져옴 let url = getChaiStatusUrl(prepare) - dlog(url) + debug_log(url) let doNetwork = Network.alamoFireManager.request(url, method: .get, encoding: JSONEncoding.default, headers: headers) @@ -152,25 +146,25 @@ class ChaiStrategy: BaseStrategy { } switch response.result { - case .success(let data): + case let .success(data): do { - dlog(data) + debug_log(data) let dataJson = try JSONSerialization.data(withJSONObject: data, options: .prettyPrinted) // CHAI 일반결제 or 정기결제에 따라 response data parsing 후 displayStatus 를 가져옴 let displayStatus = self?.getDisplayStatus(payment: payment, prepareData: prepareData, dataJson: dataJson) - if let status = ChaiPaymentStatus.from(displayStatus: displayStatus ?? CONST.EMPTY_STR) { + if let status = ChaiPaymentStatus.from(displayStatus: displayStatus ?? Constant.EMPTY_STR) { switch status { case .approved: print("결제승인! \(status.rawValue)") self?.confirmMerchant(payment: payment, prepareData: prepareData, status: status) case .confirmed: - self?.successFinish(payment: payment, prepareData: prepareData, msg: "가맹점 측 결제 승인 완료 (결제 성공) \(status.rawValue)") + self?.success(request: payment, prepareData: prepareData, msg: "가맹점 측 결제 승인 완료 (결제 성공) \(status.rawValue)") case .partial_confirmed: - self?.successFinish(payment: payment, prepareData: prepareData, msg: "부분 취소된 결제 \(status.rawValue)") + self?.success(request: payment, prepareData: prepareData, msg: "부분 취소된 결제 \(status.rawValue)") case .waiting, .prepared: self?.tryPolling() @@ -181,13 +175,12 @@ class ChaiStrategy: BaseStrategy { IamPortApprove.make(payment: payment, prepareData: prepareData, status: status).do { self?.requestApprovePayments(approve: $0) } - } } } catch { - self?.failureFinish(payment: payment, msg: "success but \(error.localizedDescription)") + self?.failure(request: payment, msg: "success but \(error.localizedDescription)") } - case .failure(let error): + case let .failure(error): // self?.failureFinish(payment: payment, msgC: "통신실패 \(error.localizedDescription)") print("네트워크 통신실패로 인한 폴링 시도!! \(error.localizedDescription)") self?.tryPolling() @@ -196,7 +189,7 @@ class ChaiStrategy: BaseStrategy { } private func tryPolling() { - if (isTimeOut()) { + if isTimeOut() { guard let payment = payment, let prepareData = prepareData else { print("isTimeOut 이나, payment : \(self.payment), prepareData : \(self.prepareData)") // sdkFinish(nil) @@ -205,12 +198,12 @@ class ChaiStrategy: BaseStrategy { } // failureFinish(payment: payment, prepareData: prepareData, msg: "I'mport : 타임아웃으로 인해 결제를 진행하지 않습니다") - print("[\(CONST.TIME_OUT_MIN)] 분 이상 결제되지 않아 미결제 처리합니다. 결제를 재시도 해주세요.") + print("[\(Constant.TIME_OUT_MIN)] 분 이상 결제되지 않아 미결제 처리합니다. 결제를 재시도 해주세요.") clear() return } - Utils.delay(bySeconds: Double(CONST.POLLING_DELAY), dispatchLevel: .userInteractive) { + Utils.delay(bySeconds: Double(Constant.POLLING_DELAY), dispatchLevel: .userInteractive) { print("폴링!!") self.checkRemoteChaiStatus() } @@ -218,26 +211,23 @@ class ChaiStrategy: BaseStrategy { func isTimeOut() -> Bool { if let timeOut = timeOutTime { - dlog("now time \(DispatchTime.now()) : timeout \(timeOut)") + debug_log("now time \(DispatchTime.now()) : timeout \(timeOut)") return DispatchTime.now() >= timeOut } return true } - - private func confirmMerchant(payment: Payment, prepareData: PrepareData, status: ChaiPaymentStatus) { - + private func confirmMerchant(payment: IamportRequest, prepareData: PrepareData, status: ChaiPaymentStatus) { IamPortApprove.make(payment: payment, prepareData: prepareData, status: status).do { RxBus.shared.post(event: EventBus.MainEvents.AskApproveFromChai(approve: $0)) } - Utils.delay(bySeconds: Double(CONST.CHAI_FINAL_PAYMENT_TIME_OUT_SEC), dispatchLevel: .userInteractive) { - print("최종 결제 타임아웃! over \(CONST.CHAI_FINAL_PAYMENT_TIME_OUT_SEC) sec") + Utils.delay(bySeconds: Double(Constant.CHAI_FINAL_PAYMENT_TIME_OUT_SEC), dispatchLevel: .userInteractive) { + print("최종 결제 타임아웃! over \(Constant.CHAI_FINAL_PAYMENT_TIME_OUT_SEC) sec") self.clear() } } - private func isSubscription(prepareData: PrepareData) -> Bool { guard prepareData.subscriptionId == nil else { return true @@ -267,15 +257,14 @@ class ChaiStrategy: BaseStrategy { // } func requestApprovePayments(approve: IamPortApprove) { - -// 어차피 밖에서 수정하지 못함 + // 어차피 밖에서 수정하지 못함 // if (!matchApproveData(approve: approve)) { // print("결제 데이터 매칭 실패로 최종결제하지 않습니다.") // dlog("상세정보\n payment :: \(payment) \n prepareData :: \(prepareData) \n approve :: \(approve)") // return // } - if (isSubscription(approve: approve)) { + if isSubscription(approve: approve) { processApprovePaymentsSubscription(approve: approve) return } @@ -293,13 +282,14 @@ class ChaiStrategy: BaseStrategy { return } - let getUrl = CONST.IAMPORT_PROD_URL + "/chai_payments/result/\(approve.userCode)/\(approve.idempotencyKey)" + let getUrl = Constant.IAMPORT_PROD_URL + "/chai_payments/result/\(approve.userCode)/\(approve.idempotencyKey)" let queryItems = [ URLQueryItem(name: CHAI.PAYMENT_ID, value: paymentId), URLQueryItem(name: CHAI.IDEMPOTENCY_KEY, value: approve.idempotencyKey), URLQueryItem(name: CHAI.STATUS, value: ChaiPaymentStatus.from(displayStatus: approve.status)?.rawValue), - URLQueryItem(name: CHAI.NATIVE, value: OS.ios.rawValue), ] + URLQueryItem(name: CHAI.NATIVE, value: OS.ios.rawValue), + ] var urlComponents = URLComponents(string: getUrl) urlComponents?.queryItems = queryItems @@ -309,10 +299,10 @@ class ChaiStrategy: BaseStrategy { return } - dlog(url) + debug_log(url) let doNetwork = Network.alamoFireManager.request(url, method: .get, encoding: JSONEncoding.default, headers: headers) - dlog(doNetwork) + debug_log(doNetwork) doNetwork.responseJSON { [weak self] response in guard let payment = self?.payment, let prepareData = self?.prepareData else { @@ -321,27 +311,26 @@ class ChaiStrategy: BaseStrategy { } switch response.result { - case .success(let data): + case let .success(data): do { - let dataJson = try JSONSerialization.data(withJSONObject: data, options: .prettyPrinted) - dlog(dataJson) + debug_log(dataJson) let getData = try JSONDecoder().decode(Approve.self, from: dataJson) - ddump(getData) + debug_dump(getData) guard getData.code == 0 else { - self?.failureFinish(payment: payment, prepareData: prepareData, msg: "결제실패 :: \(getData.msg)") + self?.failure(request: payment, prepareData: prepareData, msg: "결제실패 :: \(getData.msg)") return } - self?.successFinish(payment: payment, prepareData: prepareData, msg: "결제성공") + self?.success(request: payment, prepareData: prepareData, msg: "결제성공") } catch { - self?.failureFinish(payment: payment, prepareData: prepareData, msg: "결제콜백") + self?.failure(request: payment, prepareData: prepareData, msg: "결제콜백") } - case .failure(let error): - self?.failureFinish(payment: payment, prepareData: prepareData, msg: "네트워크 통신오류로 인한 최종결제 실패 :: \(error.localizedDescription)") + case let .failure(error): + self?.failure(request: payment, prepareData: prepareData, msg: "네트워크 통신오류로 인한 최종결제 실패 :: \(error.localizedDescription)") } } } @@ -361,14 +350,15 @@ class ChaiStrategy: BaseStrategy { return } - let getUrl = CONST.IAMPORT_PROD_URL + "/chai_payments/result/\(approve.userCode)/\(approve.idempotencyKey)/\(customerUid)" + let getUrl = Constant.IAMPORT_PROD_URL + "/chai_payments/result/\(approve.userCode)/\(approve.idempotencyKey)/\(customerUid)" let queryItems = [ URLQueryItem(name: CHAI.SUBSCRIPTION_ID, value: subscriptionId), URLQueryItem(name: CHAI.IDEMPOTENCY_KEY, value: approve.idempotencyKey), // URLQueryItem(name: CHAI.STATUS, value: ChaiPaymentStatus.approved.rawValue), URLQueryItem(name: CHAI.STATUS, value: ChaiPaymentStatus.from(displayStatus: approve.status)?.rawValue), - URLQueryItem(name: CHAI.NATIVE, value: OS.ios.rawValue), ] + URLQueryItem(name: CHAI.NATIVE, value: OS.ios.rawValue), + ] var urlComponents = URLComponents(string: getUrl) urlComponents?.queryItems = queryItems @@ -378,10 +368,10 @@ class ChaiStrategy: BaseStrategy { return } - dlog(url) + debug_log(url) let doNetwork = Network.alamoFireManager.request(url, method: .get, encoding: JSONEncoding.default, headers: headers) - dlog(doNetwork) + debug_log(doNetwork) doNetwork.responseJSON { [weak self] response in guard let payment = self?.payment, let prepareData = self?.prepareData else { @@ -390,33 +380,31 @@ class ChaiStrategy: BaseStrategy { } switch response.result { - case .success(let data): + case let .success(data): do { - let dataJson = try JSONSerialization.data(withJSONObject: data, options: .prettyPrinted) - dlog(dataJson) + debug_log(dataJson) let getData = try JSONDecoder().decode(Approve.self, from: dataJson) - ddump(getData) + debug_dump(getData) guard getData.code == 0 else { - self?.failureFinish(payment: payment, prepareData: prepareData, msg: "결제실패 :: \(getData.msg)") + self?.failure(request: payment, prepareData: prepareData, msg: "결제실패 :: \(getData.msg)") return } - self?.successFinish(payment: payment, prepareData: prepareData, msg: "결제성공") + self?.success(request: payment, prepareData: prepareData, msg: "결제성공") } catch { - self?.failureFinish(payment: payment, prepareData: prepareData, msg: "결제콜백") + self?.failure(request: payment, prepareData: prepareData, msg: "결제콜백") } - case .failure(let error): - self?.failureFinish(payment: payment, prepareData: prepareData, msg: "네트워크 통신오류로 인한 최종결제 실패 :: \(error.localizedDescription)") + case let .failure(error): + self?.failure(request: payment, prepareData: prepareData, msg: "네트워크 통신오류로 인한 최종결제 실패 :: \(error.localizedDescription)") } } } private func processPrepare(_ prepareData: PrepareData) { - guard prepareData.subscriptionId != nil || prepareData.paymentId != nil else { guard let payment = payment else { print("processPrepare :: payment is null") @@ -425,21 +413,20 @@ class ChaiStrategy: BaseStrategy { let errMsg = "subscriptionId & paymentId 모두 값이 없습니다." print(errMsg) - failureFinish(payment: payment, msg: errMsg) + failure(request: payment, msg: errMsg) return } self.prepareData = prepareData if let url = URL(string: prepareData.returnUrl) { - dlog(url) + debug_log(url) RxBus.shared.post(event: EventBus.MainEvents.ChaiUri(appAddress: url)) } - timeOutTime = DispatchTime.now() + Double(CONST.TIME_OUT) - dlog("set timeOutTime \(String(describing: timeOutTime))") + timeOutTime = DispatchTime.now() + Double(Constant.TIME_OUT) + debug_log("set timeOutTime \(String(describing: timeOutTime))") checkRemoteChaiStatus() } - } diff --git a/Sources/iamport-ios/Classes/Domain/strategy/IStrategy.swift b/Sources/iamport-ios/Classes/Domain/strategy/IStrategy.swift index aecdc17..d78d041 100644 --- a/Sources/iamport-ios/Classes/Domain/strategy/IStrategy.swift +++ b/Sources/iamport-ios/Classes/Domain/strategy/IStrategy.swift @@ -6,6 +6,6 @@ import Foundation protocol IStrategy { func clear() - func doWork(_ payment: Payment) - func sdkFinish(_ response: IamPortResponse?) -} \ No newline at end of file + func doWork(_ payment: IamportRequest) + func finish(_ response: IamportResponse?) +} diff --git a/Sources/iamport-ios/Classes/Domain/strategy/InicisTransWebViewStrategy.swift b/Sources/iamport-ios/Classes/Domain/strategy/InicisTransWebViewStrategy.swift index d3cbe27..97b7832 100644 --- a/Sources/iamport-ios/Classes/Domain/strategy/InicisTransWebViewStrategy.swift +++ b/Sources/iamport-ios/Classes/Domain/strategy/InicisTransWebViewStrategy.swift @@ -3,16 +3,14 @@ // import Foundation -import WebKit import RxBusForPort import RxSwift +import WebKit class InicisTransWebViewStrategy: WebViewStrategy { - override func onUpdatedUrl(url: URL) { - - if let appScheme = payment?.iamPortRequest?.app_scheme { - if (url.absoluteString.hasPrefix(appScheme)) { + if case let .payment(payment) = request?.payload, let appScheme = payment.app_scheme { + if url.absoluteString.hasPrefix(appScheme) { processInicisTrans(appScheme, url) return } @@ -22,7 +20,7 @@ class InicisTransWebViewStrategy: WebViewStrategy { } private func processInicisTrans(_ appScheme: String, _ url: URL) { - dlog("processInicisTrans") + debug_log("processInicisTrans") func isParseUrl(_ str: String) -> Bool { if URL(string: str) != nil { return true @@ -32,23 +30,22 @@ class InicisTransWebViewStrategy: WebViewStrategy { } var scheme = "\(appScheme)?" - if (!appScheme.contains(CONST.COLON_SLASH_SLASH)) { - scheme = "\(appScheme)\(CONST.COLON_SLASH_SLASH)?" + if !appScheme.contains(Constant.COLON_SLASH_SLASH) { + scheme = "\(appScheme)\(Constant.COLON_SLASH_SLASH)?" } - let m_redirect_url = payment?.iamPortRequest?.getRedirectUrl() ?? CONST.IAMPORT_DETECT_URL + guard case let .payment(payment) = request?.payload else { return } let removeAppScheme = url.absoluteString.replacingOccurrences(of: scheme, with: "") let separated = removeAppScheme.components(separatedBy: "=") let redirectUrl = separated.map { s -> String in s.removingPercentEncoding ?? s }.filter { s in -// s.contains(CONST.IAMPORT_DETECT_URL) - s.contains(m_redirect_url) + s.contains(payment.getRedirectUrl() ?? Constant.IAMPORT_DETECT_URL) }.first if let urlStr = redirectUrl, let url = URL(string: urlStr) { - dlog("parse url \(url.absoluteString)") + debug_log("parse url \(url.absoluteString)") RxBus.shared.post(event: EventBus.WebViewEvents.FinalBankPayProcess(url: url)) } } diff --git a/Sources/iamport-ios/Classes/Domain/strategy/JudgeStrategy.swift b/Sources/iamport-ios/Classes/Domain/strategy/JudgeStrategy.swift index d668c9a..a1e10bf 100644 --- a/Sources/iamport-ios/Classes/Domain/strategy/JudgeStrategy.swift +++ b/Sources/iamport-ios/Classes/Domain/strategy/JudgeStrategy.swift @@ -2,13 +2,12 @@ // Created by BingBong on 2021/01/08. // +import Alamofire import Foundation import RxBusForPort import RxSwift -import Alamofire public class JudgeStrategy: BaseStrategy { - // 유저 정보 판단 결과 타입 enum JudgeKinds { case CHAI, WEB, CERT, ERROR @@ -16,29 +15,29 @@ public class JudgeStrategy: BaseStrategy { var ignoreNative = false - func doWork(_ payment: Payment, ignoreNative: Bool) { + func doWork(_ payment: IamportRequest, ignoreNative: Bool) { self.ignoreNative = ignoreNative doWork(payment) } - override func doWork(_ payment: Payment) { + override func doWork(_ payment: IamportRequest) { super.doWork(payment) let headers: HTTPHeaders = ["Content-Type": "application/json"] - let url = CONST.IAMPORT_PROD_URL + "/users/pg/\(payment.userCode)" + let url = Constant.IAMPORT_PROD_URL + "/users/pg/\(payment.userCode)" print(url) let doNetwork = Network.alamoFireManagerShortTimeOut.request(url, method: .get, encoding: JSONEncoding.default, headers: headers) doNetwork.responseJSON { [weak self] response in switch response.result { - case .success(let data): + case let .success(data): do { - dlog(data) + debug_log(data) let dataJson = try JSONSerialization.data(withJSONObject: data, options: .prettyPrinted) let getData = try JSONDecoder().decode(Users.self, from: dataJson) guard getData.code == 0 else { - self?.failureFinish(payment: payment, msg: "code : \(getData.code), msg : \(String(describing: getData.msg))") + self?.failure(request: payment, msg: "code : \(getData.code), msg : \(String(describing: getData.msg))") return } @@ -48,49 +47,50 @@ public class JudgeStrategy: BaseStrategy { RxBus.shared.post(event: EventBus.MainEvents.JudgeEvent(judge: result)) } } catch { - self?.failureFinish(payment: payment, msg: "success but \(error.localizedDescription)") + self?.failure(request: payment, msg: "success but \(error.localizedDescription)") } - case .failure(let error): - self?.failureFinish(payment: payment, msg: "네트워크 연결실패 \(error.localizedDescription)") + case let .failure(error): + self?.failure(request: payment, msg: "네트워크 연결실패 \(error.localizedDescription)") } } } - private func judge(_ payment: Payment, _ userDataList: Array) -> (JudgeKinds, UserData?, Payment) { - + private func judge(_ request: IamportRequest, _ userDataList: [UserData]) -> (JudgeKinds, UserData?, IamportRequest) { guard !userDataList.isEmpty else { - failureFinish(payment: payment, msg: "Not found PG [ \(String(describing: payment.iamPortRequest?.pg)) ] and any PG in your info.") - return (JudgeKinds.ERROR, nil, payment) + failure(request: request, msg: "User data list is empty") + return (JudgeKinds.ERROR, nil, request) } - dlog("userDataList :: \(userDataList)") + debug_log("userDataList :: \(userDataList)") // 1. 본인인증의 경우 판단 (현재 있는지 없는지만 판단) - if (payment.isCertification()) { + if request.isCertification { guard let defCertUser = (userDataList.first { data in - data.pg_provider != nil && data.type == CONST.USER_TYPE_CERTIFICATION + data.pg_provider != nil && data.type == Constant.USER_TYPE_CERTIFICATION }) else { - failureFinish(payment: payment, msg: "본인인증 설정 또는 가입을 먼저 해주세요.") - return (JudgeKinds.ERROR, nil, payment) + failure(request: request, msg: "본인인증 설정 또는 가입을 먼저 해주세요.") + return (JudgeKinds.ERROR, nil, request) } - return (JudgeKinds.CERT, defCertUser, payment) + return (JudgeKinds.CERT, defCertUser, request) } // 2. 결제요청의 경우 판단 guard let defPaymentUser = findDefaultUserData(userDataList) else { - failureFinish(payment: payment, msg: "Not found Default PG. All PG empty.") - return (JudgeKinds.ERROR, nil, payment) + failure(request: request, msg: "Not found Default PG. All PG empty.") + return (JudgeKinds.ERROR, nil, request) } - guard let split = payment.iamPortRequest?.pg.split(separator: ".") else { - failureFinish(payment: payment, msg: "Not found My PG.") - return (JudgeKinds.ERROR, nil, payment) + guard case let .payment(payment) = request.payload else { + failure(request: request, msg: "Not found My PG.") + return (JudgeKinds.ERROR, nil, request) } + let split = payment.pg.split(separator: ".") + let myPg = String(split[0]) var findPg: UserData? - if (split.count > 1) { + if split.count > 1 { let pgId = String(split[1]) findPg = userDataList.first { data in data.pg_provider == myPg && data.pg_id == pgId @@ -101,63 +101,61 @@ public class JudgeStrategy: BaseStrategy { } } - dlog("findPg \(String(describing: findPg))") + debug_log("findPg \(String(describing: findPg))") - let result: (JudgeKinds, UserData?, Payment) + let result: (JudgeKinds, UserData?, IamportRequest) switch findPg { case .none: guard let pg_provider = defPaymentUser.pg_provider, - let pg = PG.convertPG(pgString: pg_provider) else { - failureFinish(payment: payment, msg: "Not found defPaymentUser pg_provider") - return (JudgeKinds.ERROR, nil, payment) + let pg = PG.convertPG(pgString: pg_provider) + else { + failure(request: request, msg: "Not found defPaymentUser pg_provider") + return (JudgeKinds.ERROR, nil, request) } - result = getPgTriple(user: defPaymentUser, payment: replacePG(pg: pg, payment: payment)) - case .some(let pg): - result = getPgTriple(user: pg, payment: payment) + result = getPgTriple(user: defPaymentUser, request: replacePG(pg: pg, request: request)) + case let .some(pg): + result = getPgTriple(user: pg, request: request) } return result } - - private func findDefaultUserData(_ userDataList: Array) -> UserData? { + private func findDefaultUserData(_ userDataList: [UserData]) -> UserData? { userDataList.first { data in - data.pg_provider != nil && data.type == CONST.USER_TYPE_PAYMENT + data.pg_provider != nil && data.type == Constant.USER_TYPE_PAYMENT } } - /** * pg 정보 값 가져옴 first : 타입, second : pg유저, third : 결제 요청 데이터 */ - private func getPgTriple(user: UserData, payment: Payment) -> (JudgeKinds, UserData?, Payment) { + private func getPgTriple(user: UserData, request: IamportRequest) -> (JudgeKinds, UserData?, IamportRequest) { if let pgProvider = user.pg_provider, let pg = PG.convertPG(pgString: pgProvider) { switch pg { case .chai: - if (ignoreNative) { // ignoreNative 인 경우 webview strategy 가 동작하기 위하여 - return (JudgeKinds.WEB, user, payment) + if ignoreNative { // ignoreNative 인 경우 webview strategy 가 동작하기 위하여 + return (JudgeKinds.WEB, user, request) } - return (JudgeKinds.CHAI, user, payment) + return (JudgeKinds.CHAI, user, request) default: - return (JudgeKinds.WEB, user, payment) + return (JudgeKinds.WEB, user, request) } } else { - return (JudgeKinds.WEB, user, payment) + return (JudgeKinds.WEB, user, request) } } /** * payment PG 를 default PG 로 수정함 */ - private func replacePG(pg: PG, payment: Payment) -> Payment { - let iamPortRequest = payment.iamPortRequest?.with { - $0.pg = pg.makePgRawName() - } - return payment.with { - $0.iamPortRequest = iamPortRequest + private func replacePG(pg: PG, request: IamportRequest) -> IamportRequest { + guard case let .payment(payment) = request.payload else { return request } + return request.with { + $0.payload = .payment(payment.with { + $0.pg = pg.makePgRawName() + }) } } - } diff --git a/Sources/iamport-ios/Classes/Domain/strategy/NiceTransWebViewStrategy.swift b/Sources/iamport-ios/Classes/Domain/strategy/NiceTransWebViewStrategy.swift index 50a38e7..b49a112 100644 --- a/Sources/iamport-ios/Classes/Domain/strategy/NiceTransWebViewStrategy.swift +++ b/Sources/iamport-ios/Classes/Domain/strategy/NiceTransWebViewStrategy.swift @@ -3,18 +3,17 @@ // import Foundation -import WebKit import RxBusForPort import RxSwift +import WebKit class NiceTransWebViewStrategy: WebViewStrategy { - var bankTid: String? var niceTransUrl: String? override func onUpdatedUrl(url: URL) { - dlog("아주 나이스~ \(url)") - if (isNiceTransScheme(url)) { + debug_log("아주 나이스~ \(url)") + if isNiceTransScheme(url) { let queryParams = url.queryParams() bankTid = (queryParams[NiceBankpay.USER_KEY] as? String) niceTransUrl = (queryParams[NiceBankpay.CALLBACKPARAM] as? String) @@ -32,17 +31,16 @@ class NiceTransWebViewStrategy: WebViewStrategy { - Parameter url: 외부앱 뱅크페이 결제 종료시 받은 URL */ public func processBankPayPayment(_ url: URL) { - // bankpaycode값과 bankpayvalue값을 추출해 각각 bankpay_code와 bankpay_value값으로 전달 let queryItems = URLComponents(string: url.absoluteString)?.queryItems - guard let bankpayCode = (queryItems?.filter({ $0.name == NiceBankpay.CODE }).first?.value) else { + guard let bankpayCode = (queryItems?.filter { $0.name == NiceBankpay.CODE }.first?.value) else { print("bankpayCode 를 찾을 수 없음") dump(queryItems) return } - guard let bankpayValue = (queryItems?.filter({ $0.name == NiceBankpay.VALUE }).first?.value) else { + guard let bankpayValue = (queryItems?.filter { $0.name == NiceBankpay.VALUE }.first?.value) else { print("bankpayValue 를 찾을 수 없음") dump(queryItems) return @@ -52,12 +50,11 @@ class NiceTransWebViewStrategy: WebViewStrategy { func makeNiceTransPaymentsQuery(res: (String, String)) -> String { if let niceUrl = niceTransUrl, let tid = bankTid { - let result = "\(niceUrl)" + - "?\(NiceBankpay.CALLBACKPARAM2)=\(tid)" + - "&\(NiceBankpay.CODEPARAM)=\(res.0)" + - "&\(NiceBankpay.VALUEPARAM)=\(res.1)" - dlog("makeNiceTransPaymentsQuery \(result)") + "?\(NiceBankpay.CALLBACKPARAM2)=\(tid)" + + "&\(NiceBankpay.CODEPARAM)=\(res.0)" + + "&\(NiceBankpay.VALUEPARAM)=\(res.1)" + debug_log("makeNiceTransPaymentsQuery \(result)") return result } return "" @@ -68,27 +65,25 @@ class NiceTransWebViewStrategy: WebViewStrategy { case .OK: print("BankPayResultCode :: OK") if let url = URL(string: makeNiceTransPaymentsQuery(res: resPair)) { - dlog("url :: \(url)") + debug_log("url :: \(url)") RxBus.shared.post(event: EventBus.WebViewEvents.FinalBankPayProcess(url: url)) } case .CANCEL, .TIME_OUT, .FAIL_SIGN, .FAIL_OTP, .FAIL_CERT_MODULE_INIT: - dlog(code.desc) - if let it = payment { - failureFinish(payment: it, msg: code.desc) + debug_log(code.desc) + if let it = request { + failure(request: it, msg: code.desc) return } print("payment 가 없으므로 sdk 종료") - sdkFinish(nil) + finish(nil) } } else { print("알 수 없는 에러 code : \(resPair.0)") } - } private func isNiceTransScheme(_ uri: URL) -> Bool { uri.scheme == ProvidePgScheme.BANKPAY.rawValue } - } diff --git a/Sources/iamport-ios/Classes/Domain/strategy/WebViewStrategy.swift b/Sources/iamport-ios/Classes/Domain/strategy/WebViewStrategy.swift index 689fc5b..6f55d53 100644 --- a/Sources/iamport-ios/Classes/Domain/strategy/WebViewStrategy.swift +++ b/Sources/iamport-ios/Classes/Domain/strategy/WebViewStrategy.swift @@ -3,13 +3,12 @@ // import Foundation -import WebKit import RxBusForPort import RxSwift +import WebKit class WebViewStrategy: BaseWebViewStrategy { - - override func doWork(_ payment: Payment) { + override func doWork(_ payment: IamportRequest) { super.doWork(payment) print("헬로 WebViewStrategy") // 오픈 웹뷰! @@ -19,20 +18,20 @@ class WebViewStrategy: BaseWebViewStrategy { override func onUpdatedUrl(url: URL) { super.onUpdatedUrl(url: url) - if (url.scheme == CONST.ABOUT_BLANK_SCHEME) { + if url.scheme == Constant.ABOUT_BLANK_SCHEME { return // 이동하지 않음 } - if (Utils.isAppUrl(url)) { + if Utils.isAppUrl(url) { RxBus.shared.post(event: EventBus.WebViewEvents.ThirdPartyUri(thirdPartyUri: url)) return } - if (Utils.isPaymentOver(url)) { + if Utils.isPaymentOver(url) { let response = Utils.getQueryStringToImpResponse(url) - dlog("paymentOver :: \(String(describing: response))") - ddump(response) - sdkFinish(response) + debug_log("paymentOver :: \(String(describing: response))") + debug_dump(response) + finish(response) return } } diff --git a/Sources/iamport-ios/Classes/Presentation/IamPortMobileWebMode.swift b/Sources/iamport-ios/Classes/Presentation/IamPortMobileWebMode.swift index 0d5327d..0b2effb 100644 --- a/Sources/iamport-ios/Classes/Presentation/IamPortMobileWebMode.swift +++ b/Sources/iamport-ios/Classes/Presentation/IamPortMobileWebMode.swift @@ -2,23 +2,21 @@ // Created by BingBong on 2021/06/21. // - import Foundation -import UIKit -import WebKit import RxBusForPort -import RxSwift import RxRelay +import RxSwift +import UIKit +import WebKit class IamPortMobileWebMode: IamPortWebViewMode { - // for communicate WebView enum JsInterface: String, CaseIterable { case IAMPORT_MOBILE_WEB_MODE = "iamportmobilewebmode" static func convertJsInterface(s: String) -> JsInterface? { - for value in self.allCases { - if (s == value.rawValue) { + for value in allCases { + if s == value.rawValue { return value } } @@ -26,7 +24,6 @@ class IamPortMobileWebMode: IamPortWebViewMode { } } - override func clearWebView() { if let wv = webview { wv.configuration.userContentController.do { controller in @@ -36,12 +33,9 @@ class IamPortMobileWebMode: IamPortWebViewMode { } wv.stopLoading() } -// super.clearWebView() } - override func setupWebView() { - webview?.do { wv in wv.configuration.userContentController.do { controller in for value in JsInterface.allCases { @@ -52,22 +46,14 @@ class IamPortMobileWebMode: IamPortWebViewMode { wv.backgroundColor = UIColor.white - dlog("wv.uiDelegate : \(wv.uiDelegate)") - if ((wv.uiDelegate is IamPortWKWebViewDelegate) == false) { - dlog("새로 할당 uiDelegate") + if !(wv.uiDelegate is IamPortWKWebViewDelegate) { + debug_log("setUpWebView :: UIDelegate is not IamportWKWebViewDelegate, assigned new one") wv.uiDelegate = viewModel.iamPortWKWebViewDelegate - } else { - dlog("기존꺼 사용 uiDelegate") } - - dlog("wv.navigationDelegate : \(wv.navigationDelegate)") - if ((wv.navigationDelegate is IamPortWKWebViewDelegate) == false) { - dlog("새로 할당 navigationDelegate") + if !(wv.navigationDelegate is IamPortWKWebViewDelegate) { + debug_log("setUpWebView :: NavigationDelegate is not IamportWKWebViewDelegate, assigned new one") wv.navigationDelegate = viewModel.iamPortWKWebViewDelegate - } else { - dlog("기존꺼 사용 navigationDelegate") } - } } @@ -75,10 +61,9 @@ class IamPortMobileWebMode: IamPortWebViewMode { // } - // 결제 데이터가 있을때 처리 할 이벤트들 - override func subscribeCertification(_ payment: Payment) { - dlog("subscribe mobile mode certification") + override func subscribeCertification(_ payment: IamportRequest) { + debug_log("subscribeCertification :: subscribe mobile mode certification") let webViewEvents = EventBus.WebViewEvents.self @@ -93,10 +78,9 @@ class IamPortMobileWebMode: IamPortWebViewMode { requestCertification(payment) } - // 실제 결제 요청 동작 - override func subscribePayment(_ payment: Payment) { - dlog("subscribe mobile mode payment") + override func subscribePayment(_ payment: IamportRequest) { + debug_log("subscribe mobile mode payment") let webViewEvents = EventBus.WebViewEvents.self @@ -112,9 +96,8 @@ class IamPortMobileWebMode: IamPortWebViewMode { requestPayment(payment) } - override func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - - dlog("body \(message.body)") + override func userContentController(_: WKUserContentController, didReceive message: WKScriptMessage) { + debug_log("body \(message.body)") if let jsMethod = JsInterface.convertJsInterface(s: message.name) { switch jsMethod { @@ -125,18 +108,17 @@ class IamPortMobileWebMode: IamPortWebViewMode { return } - guard let payment = try? JSONDecoder().decode(Payment.self, from: dataJson) else { + guard let payment = try? JSONDecoder().decode(IamportRequest.self, from: dataJson) else { print("JSONDecoder 실패") return } - dlog("받았어!! \(payment)") - ddump(payment) + debug_log("받았어!! \(payment)") + debug_dump(payment) - self.payment = payment + request = payment subscribe(payment) // rxbus 구독 및 strategy doWork } } } - } diff --git a/Sources/iamport-ios/Classes/Presentation/IamPortWKWebViewDelegate.swift b/Sources/iamport-ios/Classes/Presentation/IamPortWKWebViewDelegate.swift index 14465c1..fba3338 100644 --- a/Sources/iamport-ios/Classes/Presentation/IamPortWKWebViewDelegate.swift +++ b/Sources/iamport-ios/Classes/Presentation/IamPortWKWebViewDelegate.swift @@ -3,19 +3,18 @@ // import Foundation -import UIKit -import WebKit import RxBusForPort -import RxSwift import RxRelay +import RxSwift import Then +import UIKit +import WebKit open class IamPortWKWebViewDelegate: NSObject, WKNavigationDelegate { - - var popupWebView: WKWebView? ///window.open()으로 열리는 새창 + var popupWebView: WKWebView? /// window.open()으로 열리는 새창 @available(iOS 8.0, *) - open func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { + open func webView(_: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { // url 변경 시점 if let url = navigationAction.request.url { RxBus.shared.post(event: EventBus.WebViewEvents.UpdateUrl(url: url)) @@ -30,8 +29,7 @@ open class IamPortWKWebViewDelegate: NSObject, WKNavigationDelegate { } extension IamPortWKWebViewDelegate: WKUIDelegate { - - public func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { + public func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for _: WKNavigationAction, windowFeatures _: WKWindowFeatures) -> WKWebView? { let frame = UIScreen.main.bounds popupWebView = WKWebView(frame: frame, configuration: configuration) if let popup = popupWebView { @@ -62,45 +60,48 @@ extension IamPortWKWebViewDelegate: WKUIDelegate { } } - public func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, - completionHandler: @escaping () -> Void) { - dlog("팝업 호출 1") - let completionHandlerWrapper = CompletionHandlerWrapper(completionHandler: completionHandler, defaultValue: Void()) + public func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame _: WKFrameInfo, + completionHandler: @escaping () -> Void) + { + debug_log("팝업 호출 1") + let completionHandlerWrapper = CompletionHandlerWrapper(completionHandler: completionHandler, defaultValue: ()) let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { (action) in - completionHandlerWrapper.respondHandler(Void()) + alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { _ in + completionHandlerWrapper.respondHandler(()) })) presentAlert(webView: webView, alertController: alertController) } - public func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, - completionHandler: @escaping (Bool) -> Void) { - dlog("팝업 호출 2") + public func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame _: WKFrameInfo, + completionHandler: @escaping (Bool) -> Void) + { + debug_log("팝업 호출 2") let completionHandlerWrapper = CompletionHandlerWrapper(completionHandler: completionHandler, defaultValue: false) let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: "취소", style: .cancel, handler: { (action) in - completionHandlerWrapper.respondHandler(false) - })) - alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { (action) in + alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { _ in completionHandlerWrapper.respondHandler(true) })) + alertController.addAction(UIAlertAction(title: "취소", style: .cancel, handler: { _ in + completionHandlerWrapper.respondHandler(false) + })) presentAlert(webView: webView, alertController: alertController) } - public func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame frame: WKFrameInfo, - completionHandler: @escaping (String?) -> Void) { - dlog("팝업 호출 3") + public func webView(_ webView: WKWebView, runJavaScriptTextInputPanelWithPrompt prompt: String, defaultText: String?, initiatedByFrame _: WKFrameInfo, + completionHandler: @escaping (String?) -> Void) + { + debug_log("팝업 호출 3") let completionHandlerWrapper = CompletionHandlerWrapper(completionHandler: completionHandler, defaultValue: "") let alertController = UIAlertController(title: "", message: prompt, preferredStyle: .alert) - alertController.addTextField { (textField) in + alertController.addTextField { textField in textField.text = defaultText } - alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { (action) in + alertController.addAction(UIAlertAction(title: "확인", style: .default, handler: { _ in if let text = alertController.textFields?.first?.text { completionHandlerWrapper.respondHandler(text) } else { @@ -108,7 +109,7 @@ extension IamPortWKWebViewDelegate: WKUIDelegate { } })) - alertController.addAction(UIAlertAction(title: "취소", style: .default, handler: { (action) in + alertController.addAction(UIAlertAction(title: "취소", style: .default, handler: { _ in completionHandlerWrapper.respondHandler(nil) })) diff --git a/Sources/iamport-ios/Classes/Presentation/IamPortWebViewMode.swift b/Sources/iamport-ios/Classes/Presentation/IamPortWebViewMode.swift index 01dda5a..bc6b099 100644 --- a/Sources/iamport-ios/Classes/Presentation/IamPortWebViewMode.swift +++ b/Sources/iamport-ios/Classes/Presentation/IamPortWebViewMode.swift @@ -3,23 +3,22 @@ // import Foundation -import UIKit -import WebKit import RxBusForPort -import RxSwift import RxRelay +import RxSwift import Then +import UIKit +import WebKit class IamPortWebViewMode: UIView, WKUIDelegate { - var disposeBag = DisposeBag() let viewModel = WebViewModel() var webview: WKWebView? - var payment: Payment? + var request: IamportRequest? func start(webview: WKWebView) { - dlog("IamPortWebViewMode 어서오고") + debug_log("IamPortWebViewMode :: start") clearAll() self.webview = webview setupWebView() @@ -27,7 +26,7 @@ class IamPortWebViewMode: UIView, WKUIDelegate { } func close() { - dlog("IamPortWebViewMode close") + debug_log("IamPortWebViewMode :: close") clearAll() } @@ -45,14 +44,13 @@ class IamPortWebViewMode: UIView, WKUIDelegate { } private func clearAll() { - dlog("clearAll") + debug_log("IamPortWebViewMode :: clearAll") clearWebView() - payment = nil + request = nil disposeBag = DisposeBag() } internal func setupWebView() { - if let wv = webview { wv.configuration.userContentController.do { controller in for value in WebViewController.JsInterface.allCases { @@ -69,53 +67,53 @@ class IamPortWebViewMode: UIView, WKUIDelegate { } internal func subscribePayment() { - dlog("webviewmode subscribePayment") + debug_log("IamPortWebViewMode :: subscribePayment") let eventBus = EventBus.shared // 결제 데이터 eventBus.webViewPaymentBus.subscribe { [weak self] event in - guard let el = event.element, let pay = el else { - print("Error not found PaymentEvent") + guard let elem = event.element, let payment = elem else { + print("IamPortWebViewMode :: Error not found PaymentEvent") return } - self?.subscribe(pay) + self?.subscribe(payment) }.disposed(by: disposeBag) } // isCertification 에 따라 bind 할 항목이 달라짐 - internal func subscribe(_ payment: Payment) { - dlog("나왔니?") - self.payment = payment - if (payment.isCertification()) { - dlog("subscribeCertification?") + internal func subscribe(_ payment: IamportRequest) { + debug_log("IamPortWebViewMode :: subscribe") + request = payment + if payment.isCertification { + debug_log("IamPortWebViewMode :: subscribeCertification") subscribeCertification(payment) } else { - dlog("subscribePayment?") + debug_log("IamPortWebViewMode :: subscribePayment") subscribePayment(payment) } } - // 결제 데이터가 있을때 처리 할 이벤트들 - internal func subscribeCertification(_ payment: Payment) { - dlog("subscribe webview mode certification") + // 본인인증 데이터가 있을때 처리 할 이벤트들 + internal func subscribeCertification(_ payment: IamportRequest) { + debug_log("IamPortWebViewMode :: subscribeCertification") let bus = RxBus.shared let webViewEvents = EventBus.WebViewEvents.self bus.asObservable(event: webViewEvents.ImpResponse.self).subscribe { [weak self] event in guard let el = event.element else { - print("Error not found ImpResponse") + print("IamPortWebViewMode :: Cannot find ImpResponse") return } - print("receive ImpResponse") + print("IamPortWebViewMode :: ImpResponse received") self?.sdkFinish(el.impResponse) }.disposed(by: disposeBag) bus.asObservable(event: webViewEvents.OpenWebView.self).subscribe { [weak self] event in - guard nil != event.element else { - print("Error not found OpenWebView") + guard event.element != nil else { + print("IamPortWebViewMode :: Error not found OpenWebView") return } self?.openWebView() @@ -123,7 +121,7 @@ class IamPortWebViewMode: UIView, WKUIDelegate { bus.asObservable(event: webViewEvents.ThirdPartyUri.self).subscribe { [weak self] event in guard let el = event.element else { - print("Error not found ThirdPartyUri") + print("IamPortWebViewMode :: Error not found ThirdPartyUri") return } self?.openThirdPartyApp(el.thirdPartyUri) @@ -133,25 +131,25 @@ class IamPortWebViewMode: UIView, WKUIDelegate { } // 결제 데이터가 있을때 처리 할 이벤트들 - internal func subscribePayment(_ payment: Payment) { - dlog("subscribe webview mode payment") + internal func subscribePayment(_ payment: IamportRequest) { + debug_log("IamPortWebViewMode :: subscribePayment") let bus = RxBus.shared let webViewEvents = EventBus.WebViewEvents.self bus.asObservable(event: webViewEvents.ImpResponse.self).subscribe { [weak self] event in guard let el = event.element else { - print("Error not found ImpResponse") + print("IamPortWebViewMode :: Cannot find ImpResponse") return } - print("receive ImpResponse") + print("IamPortWebViewMode :: receive ImpResponse") self?.sdkFinish(el.impResponse) }.disposed(by: disposeBag) bus.asObservable(event: webViewEvents.OpenWebView.self).subscribe { [weak self] event in - guard nil != event.element else { - print("Error not found OpenWebView") + guard event.element != nil else { + print("IamPortWebViewMode :: Cannot find OpenWebView") return } self?.openWebView() @@ -159,7 +157,7 @@ class IamPortWebViewMode: UIView, WKUIDelegate { bus.asObservable(event: webViewEvents.ThirdPartyUri.self).subscribe { [weak self] event in guard let el = event.element else { - print("Error not found ThirdPartyUri") + print("IamPortWebViewMode :: Error not found ThirdPartyUri") return } self?.openThirdPartyApp(el.thirdPartyUri) @@ -170,7 +168,6 @@ class IamPortWebViewMode: UIView, WKUIDelegate { } internal func subscribeForBankPay() { - let bus = RxBus.shared let events = EventBus.WebViewEvents.self @@ -207,9 +204,9 @@ class IamPortWebViewMode: UIView, WKUIDelegate { /** * 결제 요청 실행 */ - internal func requestPayment(_ it: Payment) { - if (!Utils.isInternetAvailable()) { - sdkFinish(IamPortResponse.makeFail(payment: it, msg: "네트워크 연결 안됨")) + internal func requestPayment(_ it: IamportRequest) { + if !Utils.isInternetAvailable() { + sdkFinish(IamportResponse.makeFail(payment: it, msg: "네트워크 연결 안됨")) return } @@ -219,35 +216,31 @@ class IamPortWebViewMode: UIView, WKUIDelegate { /** * 본인인증 요청 실행 */ - internal func requestCertification(_ it: Payment) { - if (!Utils.isInternetAvailable()) { - sdkFinish(IamPortResponse.makeFail(payment: it, msg: "네트워크 연결 안됨")) + internal func requestCertification(_ it: IamportRequest) { + if !Utils.isInternetAvailable() { + sdkFinish(IamportResponse.makeFail(payment: it, msg: "네트워크 연결 안됨")) return } viewModel.requestCertification(it) } - - /* - 모든 결과 처리 및 SDK 종료 + /** + * 모든 결과 처리 및 SDK 종료 */ - func sdkFinish(_ iamPortResponse: IamPortResponse?) { + func sdkFinish(_ iamPortResponse: IamportResponse?) { print("명시적 sdkFinish") - ddump(iamPortResponse) + debug_dump(iamPortResponse) -// navigationController?.popViewController(animated: false) -// dismiss(animated: true) { close() EventBus.shared.impResponseRelay.accept(iamPortResponse) -// } } /** * 뱅크페이 결과 처리 viewModel 에 요청 */ func processBankPayPayment(_ url: URL) { - if let it = payment { + if let it = request { // 나이스 PG 의 뱅크페이만 동작 // 이니시스 PG 의 뱅크페이의 경우 페이지 전환 후 m_redirect_url 이 내려오므로 그걸 이용 viewModel.processBankPayPayment(it, url) @@ -258,9 +251,9 @@ class IamPortWebViewMode: UIView, WKUIDelegate { * 뱅크페이 결과 처리 viewModel 에 요청 */ func finalProcessBankPayPayment(_ url: URL) { - dlog("finalProcessBankPayPayment :: \(url)") + debug_log("finalProcessBankPayPayment :: \(url)") var request = URLRequest(url: url) -//// request.httpMethod = "POST" // 해보니까 굳이 post 날릴 필요 없는 것 같음 + /// request.httpMethod = "POST" 해보니까 굳이 post 날릴 필요 없는 것 같음 DispatchQueue.main.async { [weak self] in self?.webview?.load(request) } @@ -275,20 +268,19 @@ class IamPortWebViewMode: UIView, WKUIDelegate { } } - func openThirdPartyApp(_ url: URL) { - dlog("openThirdPartyApp \(url)") + debug_log("openThirdPartyApp \(url)") let result = Utils.openAppWithCanOpen(url) // 앱 열기 - if (!result) { - - // 한번 더 열어보고 취소시 앱스토어 이동 + if !result { + /// 한번 더 열어보고 취소시 앱스토어 이동 Utils.justOpenApp(url) { [weak self] in if let scheme = url.scheme, let urlString = AppScheme.getAppStoreUrl(scheme: scheme), - let url = URL(string: urlString) { + let url = URL(string: urlString) + { Utils.justOpenApp(url) // 앱스토어로 이동 } else { - guard (self?.payment) != nil else { + guard (self?.request) != nil else { self?.sdkFinish(nil) return } @@ -301,35 +293,24 @@ class IamPortWebViewMode: UIView, WKUIDelegate { * 결제 요청 실행 */ private func openWebView() { - dlog("오픈! 웹뷰 webview mode") - - let myPG = payment?.iamPortRequest?.pgEnum - -// func bundle() -> Bundle { -// let spmBundle = Bundle.module // spm 에서 리소스 가져오는 방법임, 에러처럼 보이지만 xcode 빌드시 정상 동작(cmd + b) -// guard let _ = spmBundle.url(forResource: CONST.CDN_FILE_NAME, withExtension: CONST.CDN_FILE_EXTENSION) else { -// return Bundle(for: type(of: self)) // use for cocoapods -// } -// return spmBundle // use for swift package manager -// } + debug_log("OpenWebView in WebViewMode") -// let bundle = bundle() let bundle = Bundle.module - var urlRequest: URLRequest? = nil // for webView load - var htmlContents: String? = nil // for webView loadHtml(smilepay 자동 로그인) + var urlRequest: URLRequest? // for webView load + var htmlContents: String? // for webView loadHtml(smilepay 자동 로그인) - if (myPG == PG.smilepay) { - if let filepath = bundle.path(forResource: CONST.CDN_FILE_NAME, ofType: CONST.CDN_FILE_EXTENSION) { + if case let .payment(payment) = request?.payload, payment.pgEnum == PG.smilepay { + if let filepath = bundle.path(forResource: Constant.CDN_FILE_NAME, ofType: Constant.CDN_FILE_EXTENSION) { htmlContents = try? String(contentsOfFile: filepath, encoding: .utf8) } } else { - guard let url = bundle.url(forResource: CONST.CDN_FILE_NAME, withExtension: CONST.CDN_FILE_EXTENSION) else { + guard let url = bundle.url(forResource: Constant.CDN_FILE_NAME, withExtension: Constant.CDN_FILE_EXTENSION) else { print("html file url 비정상") return } - ddump(url) + debug_dump(url) urlRequest = URLRequest(url: url) } @@ -340,9 +321,10 @@ class IamPortWebViewMode: UIView, WKUIDelegate { return } - if (myPG == PG.smilepay) { - if let base = URL(string: CONST.SMILE_PAY_BASE_URL), - let contents = htmlContents { + if case let .payment(payment) = self?.request?.payload, payment.pgEnum == PG.smilepay { + if let base = URL(string: Constant.SMILE_PAY_BASE_URL), + let contents = htmlContents + { wv.loadHTMLString(contents, baseURL: base) } } else { @@ -354,8 +336,8 @@ class IamPortWebViewMode: UIView, WKUIDelegate { } func failFinish(errMsg: String) { - if let pay = payment { - IamPortResponse.makeFail(payment: pay, prepareData: nil, msg: errMsg).do { it in + if let pay = request { + IamportResponse.makeFail(payment: pay, prepareData: nil, msg: errMsg).do { it in sdkFinish(it) } } else { @@ -364,33 +346,33 @@ class IamPortWebViewMode: UIView, WKUIDelegate { } } - extension IamPortWebViewMode: WKScriptMessageHandler { - func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - dlog("body \(message.body)") + func userContentController(_: WKUserContentController, didReceive message: WKScriptMessage) { + debug_log("body \(message.body)") if let jsMethod = WebViewController.JsInterface.convertJsInterface(s: message.name) { switch jsMethod { case .START_WORKING_SDK: print("JS SDK 통한 결제 시작 요청") - guard let pay = payment else { + guard let pay = request else { print(".START_WORKING_SDK payment 를 찾을 수 없음") return } - ddump(pay) + debug_dump(pay) let encoder = JSONEncoder() - // encoder.outputFormatting = .prettyPrinted initSDK(userCode: pay.userCode, tierCode: pay.tierCode) - if (pay.isCertification()) { - let jsonData = try? encoder.encode(pay.iamPortCertification) - certification(impCertificationJsonData: jsonData) - } else { - let jsonData = try? encoder.encode(pay.iamPortRequest) - requestPay(impRequestJsonData: jsonData) + switch pay.payload { + case let .payment(payload): + let jsonData = try? encoder.encode(payload) + requestPay(payloadJsonData: jsonData) + + case let .certification(payload): + let jsonData = try? encoder.encode(payload) + requestCertification(payloadJsonData: jsonData) } case .RECEIVED: @@ -399,47 +381,48 @@ extension IamPortWebViewMode: WKScriptMessageHandler { case .CUSTOM_CALL_BACK: print("Received payment callback") if let data = (message.body as? String)?.data(using: .utf8), - let impStruct = try? JSONDecoder().decode(IamPortResponseStruct.self, from: data) { - let response = IamPortResponse.structToClass(impStruct) + let impStruct = try? JSONDecoder().decode(IamPortResponseStruct.self, from: data) + { + let response = IamportResponse.structToClass(impStruct) sdkFinish(response) } case .DEBUG_CONSOLE_LOG: - dlog("DEBUG_CONSOLE_LOG :: \(message.body)") + debug_log("DEBUG_CONSOLE_LOG :: \(message.body)") } } } - private func evaluateJS(method: String) { + private func evaluateJavaScript(method: String) { webview?.evaluateJavaScript(method) } private func initSDK(userCode: String, tierCode: String? = nil) { - dlog("userCode : '\(userCode)', tierCode : '\(tierCode)'") + debug_log("userCode : '\(userCode)', tierCode : '\(tierCode)'") var jsInitMethod = "init('\(userCode)');" // IMP.init - if (!tierCode.nilOrEmpty) { + if !tierCode.nilOrEmpty { jsInitMethod = "agency('\(userCode)', '\(String(describing: tierCode))');" // IMP.agency } - evaluateJS(method: jsInitMethod) + evaluateJavaScript(method: jsInitMethod) } - private func requestPay(impRequestJsonData: Data?) { - if let json = impRequestJsonData, - let request = String(data: json, encoding: .utf8) { - dlog("requestPay request : '\(request)'") - evaluateJS(method: "requestPay('\(request)');") + private func requestPay(payloadJsonData: Data?) { + if let json = payloadJsonData, + let request = String(data: json, encoding: .utf8) + { + debug_log("requestPay request : '\(request)'") + evaluateJavaScript(method: "requestPay('\(request)');") } } - private func certification(impCertificationJsonData: Data?) { - if let json = impCertificationJsonData, - let request = String(data: json, encoding: .utf8) { - dlog("certification request : '\(request)'") - evaluateJS(method: "certification('\(request)');") + private func requestCertification(payloadJsonData: Data?) { + if let json = payloadJsonData, + let request = String(data: json, encoding: .utf8) + { + debug_log("certification request : '\(request)'") + evaluateJavaScript(method: "certification('\(request)');") } } - } - diff --git a/Sources/iamport-ios/Classes/Presentation/IamportSdk.swift b/Sources/iamport-ios/Classes/Presentation/IamportSdk.swift index 9bf4585..d5b5d94 100644 --- a/Sources/iamport-ios/Classes/Presentation/IamportSdk.swift +++ b/Sources/iamport-ios/Classes/Presentation/IamportSdk.swift @@ -3,75 +3,62 @@ // import Foundation -import WebKit import RxBusForPort import RxSwift import Then +import WebKit public class IamportSdk: Then { - let viewModel = MainViewModel() private var viewController: UIViewController? - private var naviController: UINavigationController? + private var navController: UINavigationController? private var webview: WKWebView? var chaiApproveCallBack: ((IamPortApprove) -> Void)? // 차이 결제 확인 콜백 - var resultCallBack: ((IamPortResponse?) -> Void)? // 결제 결과 콜백 + var resultCallBack: ((IamportResponse?) -> Void)? // 결제 결과 콜백 var iamportWebViewMode: IamPortWebViewMode? - var iamPortMobileWebMode: IamPortMobileWebMode? + var iamportMobileWebMode: IamPortMobileWebMode? var disposeBag = DisposeBag() var animate = true var useNaviButton = false - public init(naviController: UINavigationController) { - initController() - self.naviController = naviController + public init(navController: UINavigationController) { + self.navController = navController } /** - for WebView Mode (WKWebView 를 넘기지만 결제요청은 네이티브에서) - - Parameter webViewMode: - */ + for WebView Mode (WKWebView 를 넘기지만 결제요청은 네이티브에서) + - Parameter webViewMode + */ public init(webViewMode: WKWebView) { - initController() webview = webViewMode iamportWebViewMode = IamPortWebViewMode() } /** for MobileWeb Mode (WKWebView 를 넘기고, 결제요청 또한 JS 에서 사용) - - Parameter mobileWebMode: + - Parameter mobileWebMode */ public init(mobileWebMode: WKWebView) { - initController() webview = mobileWebMode - iamPortMobileWebMode = IamPortMobileWebMode().then { mode in + iamportMobileWebMode = IamPortMobileWebMode().then { mode in mode.start(webview: mobileWebMode) } } public init(viewController: UIViewController) { - initController() self.viewController = viewController } - func initController() { - naviController = nil - webview = nil - viewController = nil - } - // 뷰모델 데이터 클리어 func clearData() { print("IamportSdk clearData!") -// updatePolling(false) -// controlForegroundService(false) iamportWebViewMode?.close() - iamPortMobileWebMode?.close() + iamportMobileWebMode?.close() viewModel.clear() EventBus.shared.clearRelay.accept(()) @@ -79,41 +66,41 @@ public class IamportSdk: Then { disposeBag = DisposeBag() } - private func sdkFinish(_ iamportResponse: IamPortResponse?) { - print("I'mport SDK 에서 종료입니다") + private func finish(_ iamportResponse: IamportResponse?) { + print("IamportSdk :: SDK Finished") clearData() resultCallBack?(iamportResponse) } - internal func initStart(payment: Payment, approveCallback: ((IamPortApprove) -> Void)?, paymentResultCallback: @escaping (IamPortResponse?) -> Void) { - print("initStart Payment") + internal func initStart(request: IamportRequest, approveCallback: ((IamPortApprove) -> Void)?, paymentResultCallback: @escaping (IamportResponse?) -> Void) { + print("IamportSdk :: initStart(payment)") chaiApproveCallBack = approveCallback resultCallBack = paymentResultCallback - subscribe(payment) // 관찰할 옵저버블 + subscribe(request) // 관찰할 옵저버블 } - internal func initStart(payment: Payment, certificationResultCallback: @escaping (IamPortResponse?) -> Void) { - print("initStart Certification") + internal func initStart(request: IamportRequest, certificationResultCallback: @escaping (IamportResponse?) -> Void) { + print("IamportSdk :: initStart(certification)") resultCallBack = certificationResultCallback - subscribeCertification(payment) // 관찰할 옵저버블 + subscribeCertification(request) // 관찰할 옵저버블 } func postReceivedURL(_ url: URL) { - dlog("외부앱 종료 후 전달 받음 => \(url)") + debug_log("외부앱 종료 후 전달 받음 => \(url)") RxBus.shared.post(event: EventBus.WebViewEvents.ReceivedAppDelegateURL(url: url)) } - private func subscribe(_ payment: Payment) { + private func subscribe(_ request: IamportRequest) { // 결제결과 옵저빙 EventBus.shared.impResponseBus.subscribe { [weak self] iamportResponse in - self?.sdkFinish(iamportResponse) + self?.finish(iamportResponse) }.disposed(by: disposeBag) - // TODO subscribe 결제결과 + // TODO: subscribe 결제결과 // subscribe 웹뷰열기 EventBus.shared.paymentBus.subscribe { [weak self] event in @@ -132,12 +119,10 @@ public class IamportSdk: Then { return } - self?.openApp(payment, appAddress: el.appAddress) + self?.openApp(request, appAddress: el.appAddress) }.disposed(by: disposeBag) - // TODO subscribe 폴링여부 - // 차이 결제 상태 approve 처리 RxBus.shared.asObservable(event: EventBus.MainEvents.AskApproveFromChai.self).subscribe { [weak self] event in guard let el = event.element else { @@ -150,14 +135,13 @@ public class IamportSdk: Then { }.disposed(by: disposeBag) // 결제요청 - requestPayment(payment) + requestPayment(request) } - private func subscribeCertification(_ payment: Payment) { - - // 결제결과 옵저빙 + private func subscribeCertification(_ request: IamportRequest) { + // 본인인증 옵저빙 EventBus.shared.impResponseBus.subscribe { [weak self] iamportResponse in - self?.sdkFinish(iamportResponse) + self?.finish(iamportResponse) }.disposed(by: disposeBag) // subscribe 웹뷰열기 @@ -171,23 +155,23 @@ public class IamportSdk: Then { }.disposed(by: disposeBag) // 본인인증 요청 - requestCertification(payment) + requestCertification(request) } - - private func openApp(_ payment: Payment, appAddress: URL) { + private func openApp(_: IamportRequest, appAddress: URL) { let result = Utils.openAppWithCanOpen(appAddress) // 앱 열기 - // TODO openApp result = false 일 떄, 이미 chai strategy 가 동작할 시나리오 + // TODO: openApp result = false 일 떄, 이미 chai strategy 가 동작할 시나리오 // 취소? 타임아웃 연장? 그대로 진행? ... 등 // 어차피 앱 재설치시, 다시 차이 결제 페이지로 진입할 방법이 없음 - if (!result) { + if !result { Utils.justOpenApp(appAddress) { [weak self] in self?.viewModel.stopChaiStrategy() if let scheme = appAddress.scheme, let urlString = AppScheme.getAppStoreUrl(scheme: scheme), - let url = URL(string: urlString) { + let url = URL(string: urlString) + { Utils.justOpenApp(url) // 앱스토어 이동 } } @@ -208,46 +192,42 @@ public class IamportSdk: Then { viewModel.requestApprovePayments(approve: approve) } - private func requestPayment(_ payment: Payment) { - - Payment.validator(payment) { valid, desc in + private func requestPayment(_ request: IamportRequest) { + IamportRequest.validator(request) { valid, desc in print("Payment validator valid :: \(valid), valid :: \(desc)") - if (!valid) { - self.sdkFinish(IamPortResponse.makeFail(payment: payment, msg: desc)) + if !valid { + self.finish(IamportResponse.makeFail(payment: request, msg: desc)) return } } - if (!Utils.isInternetAvailable()) { - sdkFinish(IamPortResponse.makeFail(payment: payment, msg: "네트워크 연결 안됨")) + if !Utils.isInternetAvailable() { + finish(IamportResponse.makeFail(payment: request, msg: "네트워크 연결 안됨")) return } // webview mode 라면 네이티브 연동 사용하지 않음 // 동작의 문제는 없으나 UI 에서 표현하기 애매함 if webview != nil { - viewModel.judgePayment(payment, ignoreNative: true) + viewModel.judgePayment(request, ignoreNative: true) return } - viewModel.judgePayment(payment) + viewModel.judgePayment(request) } - private func requestCertification(_ payment: Payment) { - - if (!Utils.isInternetAvailable()) { - sdkFinish(IamPortResponse.makeFail(payment: payment, msg: "네트워크 연결 안됨")) + private func requestCertification(_ request: IamportRequest) { + if !Utils.isInternetAvailable() { + finish(IamportResponse.makeFail(payment: request, msg: "네트워크 연결 안됨")) return } - viewModel.judgePayment(payment) + viewModel.judgePayment(request) } - // 웹뷰 컨트롤러 열기 및 데이터 전달 - private func openWebViewController(_ payment: Payment) { - - DispatchQueue.main.async(execute: { [weak self] in + private func openWebViewController(_ payment: IamportRequest) { + DispatchQueue.main.async { [weak self] in EventBus.shared.webViewPaymentRelay.accept(payment) // 여기서 먼저 결제 데이터를 넘김 @@ -258,18 +238,14 @@ public class IamportSdk: Then { let wvc = WebViewController() - self?.naviController?.pushViewController(wvc, animated: self?.animate ?? true) -// self?.naviController.present(WebViewController(), animated: true) + self?.navController?.pushViewController(wvc, animated: self?.animate ?? true) -// wvc.modalPresentationStyle = UIModalPresentationStyle.currentContext -// wvc.modalTransitionStyle = UIModalTransitionStyle.coverVertical wvc.modalPresentationStyle = .fullScreen wvc.useNaviButton = self?.useNaviButton ?? false self?.viewController?.present(wvc, animated: self?.animate ?? true) - dlog("check viewController :: \(String(describing: self?.viewController))") - dlog("check navigationController :: \(String(describing: self?.naviController))") - }) + debug_log("check viewController :: \(String(describing: self?.viewController))") + debug_log("check navigationController :: \(String(describing: self?.navController))") + } } - -} \ No newline at end of file +} diff --git a/Sources/iamport-ios/Classes/Presentation/MainViewModel.swift b/Sources/iamport-ios/Classes/Presentation/MainViewModel.swift index 233013f..e918004 100644 --- a/Sources/iamport-ios/Classes/Presentation/MainViewModel.swift +++ b/Sources/iamport-ios/Classes/Presentation/MainViewModel.swift @@ -3,28 +3,25 @@ // import Foundation -import RxSwift import RxBusForPort +import RxSwift class MainViewModel { - private var disposeBag = DisposeBag() - private let repository = StrategyRepository() // TODO dependency inject + private let repository = StrategyRepository() // TODO: dependency inject func clear() { disposeBag = DisposeBag() } - func judgePayment(_ payment: Payment, ignoreNative: Bool = false) { - + func judgePayment(_ payment: IamportRequest, ignoreNative: Bool = false) { subscribe() DispatchQueue.main.async { [weak self] in - - Payment.validator(payment) { valid, desc in + IamportRequest.validator(payment) { valid, desc in print("one more Payment validator valid :: \(valid), valid :: \(desc)") - if (!valid) { - IamPortResponse.makeFail(payment: payment, msg: desc).do { it in + if !valid { + IamportResponse.makeFail(payment: payment, msg: desc).do { it in self?.clear() EventBus.shared.impResponseRelay.accept(it) } @@ -48,10 +45,9 @@ class MainViewModel { }.disposed(by: disposeBag) } - // 판단 결과 처리 - private func judgeProcess(_ judge: (JudgeStrategy.JudgeKinds, UserData?, Payment)) { - dlog("JudgeEvent \(judge)") + private func judgeProcess(_ judge: (JudgeStrategy.JudgeKinds, UserData?, IamportRequest)) { + debug_log("JudgeEvent \(judge)") switch judge.0 { case .CHAI: judge.1?.do { userData in @@ -66,7 +62,6 @@ class MainViewModel { } } - /** * 차이 최종 결제 요청 */ @@ -82,5 +77,4 @@ class MainViewModel { print("차이 앱 없으므로 폴링 stop") repository.chaiStrategy.clear() } - } diff --git a/Sources/iamport-ios/Classes/Presentation/WebViewController.swift b/Sources/iamport-ios/Classes/Presentation/WebViewController.swift index 94daec3..4d0a46c 100644 --- a/Sources/iamport-ios/Classes/Presentation/WebViewController.swift +++ b/Sources/iamport-ios/Classes/Presentation/WebViewController.swift @@ -1,11 +1,10 @@ -import UIKit -import WebKit import RxBusForPort -import RxSwift import RxRelay +import RxSwift +import UIKit +import WebKit class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate { - // for communicate WebView enum JsInterface: String, CaseIterable { case RECEIVED = "received" @@ -14,8 +13,8 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate case DEBUG_CONSOLE_LOG = "debugConsoleLog" static func convertJsInterface(s: String) -> JsInterface? { - for value in self.allCases { - if (s == value.rawValue) { + for value in allCases { + if s == value.rawValue { return value } } @@ -27,8 +26,8 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate let viewModel = WebViewModel() var webView: WKWebView? - var popupWebView: WKWebView?//window.open()으로 열리는 새창 - var payment: Payment? + var popupWebView: WKWebView? // window.open()으로 열리는 새창 + var request: IamportRequest? var useNaviButton = false var naviHeight: CGFloat = 0 @@ -37,25 +36,24 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate // Disappear override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - dlog("viewWillDisappear") + debug_log("viewWillDisappear") // clearAll() } override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) - dlog("viewDidDisappear") + debug_log("viewDidDisappear") clearAll() } - // loaded override func viewDidLoad() { super.viewDidLoad() - dlog("WebViewController 어서오고") + debug_log("WebViewController 어서오고") view.backgroundColor = UIColor.white - if (useNaviButton) { + if useNaviButton { setTopNaviBar() } @@ -78,14 +76,14 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate navItem.leftBarButtonItem = UIBarButtonItem(title: "Back", style: .plain, target: self, action: #selector(buttonClose(sender:))) navbar.items = [navItem] - dlog("safeArea \(safeArea)") - dlog("navbar.frame.height \(navbar.frame.height)") + debug_log("safeArea \(safeArea)") + debug_log("navbar.frame.height \(navbar.frame.height)") view.addSubview(navbar) } @objc - private func buttonClose(sender: UIBarButtonItem) { + private func buttonClose(sender _: UIBarButtonItem) { navigationController?.popViewController(animated: false) dismiss(animated: true) } @@ -109,7 +107,7 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate private func clearAll() { // clearWebView() // view.removeFromSuperview() - payment = nil + request = nil disposeBag = DisposeBag() } @@ -119,10 +117,9 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate } private func setupWebView() { - clearWebView() - let config = WKWebViewConfiguration.init().then { configuration in + let config = WKWebViewConfiguration().then { configuration in configuration.userContentController = WKUserContentController().then { controller in for value in JsInterface.allCases { controller.add(self, name: value.rawValue) @@ -130,12 +127,12 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate } configuration.preferences.javaScriptCanOpenWindowsAutomatically = true } - webView = WKWebView.init(frame: view.frame, configuration: config).then { (wv: WKWebView) in + webView = WKWebView(frame: view.frame, configuration: config).then { (wv: WKWebView) in wv.backgroundColor = UIColor.white // navi top bar 쓸 때 - if (useNaviButton) { - wv.frame = CGRect(x: 0, y: safeArea + naviHeight, width: UIScreen.main.bounds.width, height: (UIScreen.main.bounds.height - naviHeight - safeArea)) + if useNaviButton { + wv.frame = CGRect(x: 0, y: safeArea + naviHeight, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height - naviHeight - safeArea) } else { wv.frame = view.bounds } @@ -157,30 +154,30 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate return } - dlog("PaymentEvent 있음!") + debug_log("PaymentEvent 있음!") self?.subscribe(pay) }.disposed(by: disposeBag) // 외부 종료 시그널 // eventBus.clearBus.subscribe { [weak self] in // print("clearBus") -//// self?.sdkFinish(nil) + //// self?.sdkFinish(nil) // self?.clearAll() // }.disposed(by: disposeBag) } // isCertification 에 따라 bind 할 항목이 달라짐 - private func subscribe(_ payment: Payment) { - if (payment.isCertification()) { - subscribeCertification(payment) + private func subscribe(_ request: IamportRequest) { + if request.isCertification { + subscribeCertification(request) } else { - subscribePayment(payment) + subscribePayment(request) } } // 결제 데이터가 있을때 처리 할 이벤트들 - private func subscribeCertification(_ payment: Payment) { - self.payment = payment + private func subscribeCertification(_ request: IamportRequest) { + self.request = request let bus = RxBus.shared let webViewEvents = EventBus.WebViewEvents.self @@ -191,12 +188,12 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate return } - dlog("receive ImpResponse") + debug_log("receive ImpResponse") self?.sdkFinish(el.impResponse) }.disposed(by: disposeBag) bus.asObservable(event: webViewEvents.OpenWebView.self).subscribe { [weak self] event in - guard nil != event.element else { + guard event.element != nil else { print("Error not found OpenWebView") return } @@ -211,14 +208,14 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate self?.openThirdPartyApp(el.thirdPartyUri) }.disposed(by: disposeBag) - requestCertification(payment) + requestCertification(request) } // 결제 데이터가 있을때 처리 할 이벤트들 - private func subscribePayment(_ payment: Payment) { - dlog("subscribePayment vc") + private func subscribePayment(_ request: IamportRequest) { + debug_log("subscribePayment vc") - self.payment = payment + self.request = request let bus = RxBus.shared let webViewEvents = EventBus.WebViewEvents.self @@ -228,12 +225,12 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate return } - dlog("receive ImpResponse") + debug_log("receive ImpResponse") self?.sdkFinish(el.impResponse) }.disposed(by: disposeBag) bus.asObservable(event: webViewEvents.OpenWebView.self).subscribe { [weak self] event in - guard nil != event.element else { + guard event.element != nil else { print("Error not found OpenWebView") return } @@ -249,11 +246,10 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate }.disposed(by: disposeBag) subscribeForBankPay() - requestPayment(payment) + requestPayment(request) } private func subscribeForBankPay() { - let bus = RxBus.shared let events = EventBus.WebViewEvents.self @@ -290,9 +286,9 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate /** * 결제 요청 실행 */ - private func requestPayment(_ it: Payment) { - if (!Utils.isInternetAvailable()) { - sdkFinish(IamPortResponse.makeFail(payment: it, msg: "네트워크 연결 안됨")) + private func requestPayment(_ it: IamportRequest) { + if !Utils.isInternetAvailable() { + sdkFinish(IamportResponse.makeFail(payment: it, msg: "네트워크 연결 안됨")) return } @@ -302,22 +298,21 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate /** * 본인인증 요청 실행 */ - private func requestCertification(_ it: Payment) { - if (!Utils.isInternetAvailable()) { - sdkFinish(IamPortResponse.makeFail(payment: it, msg: "네트워크 연결 안됨")) + private func requestCertification(_ it: IamportRequest) { + if !Utils.isInternetAvailable() { + sdkFinish(IamportResponse.makeFail(payment: it, msg: "네트워크 연결 안됨")) return } viewModel.requestCertification(it) } - /* 모든 결과 처리 및 SDK 종료 */ - func sdkFinish(_ iamPortResponse: IamPortResponse?) { + func sdkFinish(_ iamPortResponse: IamportResponse?) { print("명시적 sdkFinish") - ddump(iamPortResponse) + debug_dump(iamPortResponse) clearAll() navigationController?.popViewController(animated: false) @@ -330,7 +325,7 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate * 뱅크페이 결과 처리 viewModel 에 요청 */ func processBankPayPayment(_ url: URL) { - if let it = payment { + if let it = request { // 나이스 PG 의 뱅크페이만 동작 // 이니시스 PG 의 뱅크페이의 경우 페이지 전환 후 m_redirect_url 이 내려오므로 그걸 이용 viewModel.processBankPayPayment(it, url) @@ -341,7 +336,7 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate * 나이스 뱅크페이 결과 처리 viewModel 에 요청 */ func finalProcessBankPayPayment(_ url: URL) { - dlog("finalProcessBankPayPayment :: \(url)") + debug_log("finalProcessBankPayPayment :: \(url)") var request = URLRequest(url: url) request.httpMethod = "POST" DispatchQueue.main.async { [weak self] in @@ -358,20 +353,19 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate } } - func openThirdPartyApp(_ url: URL) { - dlog("openThirdPartyApp \(url)") + debug_log("openThirdPartyApp \(url)") let result = Utils.openAppWithCanOpen(url) // 앱 열기 - if (!result) { - + if !result { // 한번 더 열어보고 취소시 앱스토어 이동 Utils.justOpenApp(url) { [weak self] in if let scheme = url.scheme, let urlString = AppScheme.getAppStoreUrl(scheme: scheme), - let url = URL(string: urlString) { + let url = URL(string: urlString) + { Utils.justOpenApp(url) // 앱스토어로 이동 } else { - guard (self?.payment) != nil else { + guard (self?.request) != nil else { self?.sdkFinish(nil) return } @@ -386,33 +380,21 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate private func openWebView() { print("오픈! 웹뷰 vc") - let myPG = payment?.iamPortRequest?.pgEnum - -// let bundle = Bundle(for: type(of: self)) -// func bundle() -> Bundle { -// let spmBundle = Bundle.module // spm 에서 리소스 가져오는 방법임, 에러처럼 보이지만 xcode 빌드시 정상 동작(cmd + b) -// guard let _ = spmBundle.url(forResource: CONST.CDN_FILE_NAME, withExtension: CONST.CDN_FILE_EXTENSION) else { -// return Bundle(for: type(of: self)) // use for cocoapods -// } -// return spmBundle // use for swift package manager -// } - -// let bundle = bundle() let bundle = Bundle.module - var urlRequest: URLRequest? = nil // for webView load - var htmlContents: String? = nil // for webView loadHtml(smilepay 자동 로그인) + var urlRequest: URLRequest? // for webView load + var htmlContents: String? // for webView loadHtml(smilepay 자동 로그인) - if (myPG == PG.smilepay) { - if let filepath = bundle.path(forResource: CONST.CDN_FILE_NAME, ofType: CONST.CDN_FILE_EXTENSION) { + if case let .payment(payment) = request?.payload, payment.pgEnum == PG.smilepay { + if let filepath = bundle.path(forResource: Constant.CDN_FILE_NAME, ofType: Constant.CDN_FILE_EXTENSION) { htmlContents = try? String(contentsOfFile: filepath, encoding: .utf8) } } else { - guard let url = bundle.url(forResource: CONST.CDN_FILE_NAME, withExtension: CONST.CDN_FILE_EXTENSION) else { + guard let url = bundle.url(forResource: Constant.CDN_FILE_NAME, withExtension: Constant.CDN_FILE_EXTENSION) else { print("html file url 비정상") return } - ddump(url) + debug_dump(url) urlRequest = URLRequest(url: url) } @@ -423,9 +405,10 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate return } - if (myPG == PG.smilepay) { - if let base = URL(string: CONST.SMILE_PAY_BASE_URL), - let contents = htmlContents { + if case let .payment(payment) = self?.request?.payload, payment.pgEnum == PG.smilepay { + if let base = URL(string: Constant.SMILE_PAY_BASE_URL), + let contents = htmlContents + { wv.loadHTMLString(contents, baseURL: base) } } else { @@ -438,8 +421,7 @@ class WebViewController: UIViewController, WKUIDelegate, UINavigationBarDelegate } extension WebViewController: WKNavigationDelegate { - - func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? { + func webView(_: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for _: WKNavigationAction, windowFeatures _: WKWindowFeatures) -> WKWebView? { let frame = UIScreen.main.bounds popupWebView = WKWebView(frame: frame, configuration: configuration) if let popup = popupWebView { @@ -461,11 +443,10 @@ extension WebViewController: WKNavigationDelegate { } @available(iOS 8.0, *) - func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { + func webView(_: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { // url 변경 시점 if let url = navigationAction.request.url { - RxBus.shared.post(event: EventBus.WebViewEvents.UpdateUrl(url: url)) let policy = Utils.getActionPolicy(url) @@ -476,17 +457,15 @@ extension WebViewController: WKNavigationDelegate { } } - func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { + func webView(_: WKWebView, didFail _: WKNavigation!, withError error: Error) { print("didFail \(error.localizedDescription)") -// failFinish(errMsg: "탐색중 에러가 발생하였습니다 :: \(error.localizedDescription)") } - func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { + func webView(_: WKWebView, didFailProvisionalNavigation _: WKNavigation!, withError error: Error) { print("didFailProvisionalNavigation \(error.localizedDescription)") -// failFinish(errMsg: "컨텐츠 로드중 에러가 발생하였습니다 :: \(error.localizedDescription)") } - func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) { + func webView(_: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame _: WKFrameInfo, completionHandler: @escaping () -> Void) { let alertController = UIAlertController(title: message, message: nil, preferredStyle: .alert) let okAction = UIAlertAction(title: "확인", style: .default) { _ in completionHandler() @@ -498,7 +477,7 @@ extension WebViewController: WKNavigationDelegate { } // for Alert(for 주로 모빌리언스 + 휴대폰 소액결제 Pair) - func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) { + func webView(_: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame _: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) { let alertController = UIAlertController(title: message, message: nil, preferredStyle: .alert) let cancelAction = UIAlertAction(title: "취소", style: .cancel) { _ in completionHandler(false) @@ -514,49 +493,38 @@ extension WebViewController: WKNavigationDelegate { } func failFinish(errMsg: String) { - if let pay = payment { - IamPortResponse.makeFail(payment: pay, prepareData: nil, msg: errMsg).do { it in + if let pay = request { + IamportResponse.makeFail(payment: pay, prepareData: nil, msg: errMsg).do { it in sdkFinish(it) } } else { sdkFinish(nil) } } - } extension WebViewController: WKScriptMessageHandler { - func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { - dlog("body \(message.body)") + func userContentController(_: WKUserContentController, didReceive message: WKScriptMessage) { + debug_log("body \(message.body)") if let jsMethod = JsInterface.convertJsInterface(s: message.name) { switch jsMethod { case .START_WORKING_SDK: print("JS SDK 통한 결제 시작 요청") - guard let pay = payment else { + guard let request = request else { print(".START_WORKING_SDK payment 를 찾을 수 없음") return } - ddump(pay) + debug_dump(request) - initSDK(userCode: pay.userCode, tierCode: pay.tierCode) + initSDK(userCode: request.userCode, tierCode: request.tierCode) - if (pay.isCertification()) { - - guard let iamPortCertification = pay.iamPortCertification else { - print("iamPortCertification 를 찾을 수 없습니다.") - return - } - - let jsonData = try? JSONEncoder().encode(iamPortCertification) - certification(impCertificationJsonData: jsonData) - } else { - guard let iamPortRequest = pay.iamPortRequest else { - print("iamPortRequest 를 찾을 수 없습니다.") - return - } - requestPay(iamPortRequest: iamPortRequest) + switch request.payload { + case let .payment(payment): + requestPay(payment: payment) + case let .certification(certification): + requestCertification(certification: certification) } case .RECEIVED: @@ -565,117 +533,121 @@ extension WebViewController: WKScriptMessageHandler { case .CUSTOM_CALL_BACK: print("Received payment callback") if let data = (message.body as? String)?.data(using: .utf8), - let impStruct = try? JSONDecoder().decode(IamPortResponseStruct.self, from: data) { - let response = IamPortResponse.structToClass(impStruct) + let impStruct = try? JSONDecoder().decode(IamPortResponseStruct.self, from: data) + { + let response = IamportResponse.structToClass(impStruct) sdkFinish(response) } case .DEBUG_CONSOLE_LOG: - dlog("DEBUG_CONSOLE_LOG :: \(message.body)") + debug_log("DEBUG_CONSOLE_LOG :: \(message.body)") } } } - private func evaluateJS(method: String) { + private func evaluateJavaScript(method: String) { webView?.evaluateJavaScript(method) } private func initSDK(userCode: String, tierCode: String? = nil) { - dlog("userCode : '\(userCode)', tierCode : '\(tierCode)'") + debug_log("userCode : '\(userCode)', tierCode : '\(tierCode)'") var jsInitMethod = "init('\(userCode)');" // IMP.init - if (!tierCode.nilOrEmpty) { + if !tierCode.nilOrEmpty { jsInitMethod = "agency('\(userCode)', '\(String(describing: tierCode))');" // IMP.agency } - evaluateJS(method: jsInitMethod) + evaluateJavaScript(method: jsInitMethod) } - private func requestPay(iamPortRequest: IamPortRequest) { - - guard let impRequestJsonData = try? JSONEncoder().encode(iamPortRequest) else { - print("requestPay :: iamPortRequest 을 JSONEncoder encode 할 수 없습니다.") + private func requestPay(payment: IamportPayment) { + guard let impRequestJsonData = try? JSONEncoder().encode(payment) else { + print("requestPay :: payment 데이터를 JSONEncoder encode 할 수 없습니다.") return } - if let customData = iamPortRequest.custom_data { - requestPayWithCustomData(impRequestJsonData: impRequestJsonData, customData: customData) + if let customData = payment.custom_data { + requestPayWithCustomData(payloadJsonData: impRequestJsonData, customData: customData) } else { - requestPayNormal(impRequestJsonData: impRequestJsonData) + requestPayNormal(payloadJsonData: impRequestJsonData) } } - - private func requestPayNormal(impRequestJsonData: Data) { - - guard let request = String(data: impRequestJsonData, encoding: .utf8) else { + private func requestPayNormal(payloadJsonData: Data) { + guard let request = String(data: payloadJsonData, encoding: .utf8) else { print("requestPayNormal :: impRequestJsonData 을 String 화 할 수 없습니다.") return } - dlog("requestPay request : '\(request)'") - evaluateJS(method: "requestPay('\(request)');") + debug_log("requestPay request : '\(request)'") + evaluateJavaScript(method: "requestPay('\(request)');") } - private func requestPayWithCustomData(impRequestJsonData: Data, customData: String) { - - guard let request = String(data: impRequestJsonData, encoding: .utf8) else { + private func requestPayWithCustomData(payloadJsonData: Data, customData: String) { + guard let request = String(data: payloadJsonData, encoding: .utf8) else { print("requestPayWithCustomData :: impRequestJsonData 을 String 화 할 수 없습니다.") return } guard let encodedCustomData = customData.getBase64Encode() else { print("requestPayWithCustomData :: getBase64Encode 를 가져올 수 없어 requestPayNormal 실행") - requestPayNormal(impRequestJsonData: impRequestJsonData) + requestPayNormal(payloadJsonData: payloadJsonData) return } - dlog("requestPayWithCustomData request : '\(request)', encodedCustomData : '\(encodedCustomData)'") - evaluateJS(method: "requestPayWithCustomData('\(request)', '\(encodedCustomData)');") + debug_log("requestPayWithCustomData request : '\(request)', encodedCustomData : '\(encodedCustomData)'") + evaluateJavaScript(method: "requestPayWithCustomData('\(request)', '\(encodedCustomData)');") } - private func certification(impCertificationJsonData: Data?) { - if let json = impCertificationJsonData, - let request = String(data: json, encoding: .utf8) { - dlog("certification request : '\(request)'") - evaluateJS(method: "certification('\(request)');") + private func requestCertification(certification: IamportCertification) { + guard let impCertificationJsonData = try? JSONEncoder().encode(certification) else { + print("requestPay :: certification 데이터를 JSONEncoder encode 할 수 없습니다.") + return } + + requestCertification(payloadJsonData: impCertificationJsonData) } + private func requestCertification(payloadJsonData: Data?) { + if let json = payloadJsonData, + let request = String(data: json, encoding: .utf8) + { + debug_log("certification request : '\(request)'") + evaluateJavaScript(method: "certification('\(request)');") + } + } } - /** - 쿠키 처리 필요시.. - let policy = Utils.getActionPolicy(url) - if (!policy) { -// let cookies = HTTPCookieStorage.shared.cookies ?? [] -// for cookie in cookies { -// if #available(iOS 11.0, *) { -// dump(cookie) -// if (cookie.domain.contains(".mysmilepay.com")) { -// webView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie) -// } -// } else { -// // Fallback on earlier versions -// } -// } - - -// if #available(iOS 11.0, *) { -// webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { (cookies) in -// for cookie in cookies { -// print("@@@ cookie ==> \(cookie.name) : \(cookie.value)") -// if cookie.name.contains("sp_") { -//// UserDefaults.standard.set(cookie.value, forKey: "PHPSESSID") -// webView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie) -// print("@@@ PHPSESSID 저장하기: \(cookie.value)") -// } -// } -// } -// } else { -// // Fallback on earlier versions -// } - - } - */ + 쿠키 처리 필요시.. + let policy = Utils.getActionPolicy(url) + if (!policy) { + // let cookies = HTTPCookieStorage.shared.cookies ?? [] + // for cookie in cookies { + // if #available(iOS 11.0, *) { + // dump(cookie) + // if (cookie.domain.contains(".mysmilepay.com")) { + // webView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie) + // } + // } else { + // // Fallback on earlier versions + // } + // } + + // if #available(iOS 11.0, *) { + // webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { (cookies) in + // for cookie in cookies { + // print("@@@ cookie ==> \(cookie.name) : \(cookie.value)") + // if cookie.name.contains("sp_") { + //// UserDefaults.standard.set(cookie.value, forKey: "PHPSESSID") + // webView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie) + // print("@@@ PHPSESSID 저장하기: \(cookie.value)") + // } + // } + // } + // } else { + // // Fallback on earlier versions + // } + + } + */ diff --git a/Sources/iamport-ios/Classes/Presentation/WebViewModel.swift b/Sources/iamport-ios/Classes/Presentation/WebViewModel.swift index 2afd03b..abdf8a5 100644 --- a/Sources/iamport-ios/Classes/Presentation/WebViewModel.swift +++ b/Sources/iamport-ios/Classes/Presentation/WebViewModel.swift @@ -2,53 +2,38 @@ // Created by BingBong on 2021/01/05. // +import Foundation import RxBusForPort import RxSwift -import Foundation internal class WebViewModel { - let repository = StrategyRepository() let iamPortWKWebViewDelegate = IamPortWKWebViewDelegate() -// func clear() { -// repository.clear() -// } - /** * 뱅크페이 결과 처리 */ - func processBankPayPayment(_ payment : Payment, _ url : URL) { + func processBankPayPayment(_ payment: IamportRequest, _ url: URL) { repository.processBankPayPayment(payment, url) } /** * 결제 요청 */ - func requestPayment(payment: Payment) { - dlog("뷰모델에 결제 요청했니") + func requestPayment(payment: IamportRequest) { + debug_log("뷰모델에 결제 요청했니") DispatchQueue.main.async { self.repository.getWebViewStrategy(payment).doWork(payment) } } -// /** -// * WebMode Only 결제 요청 -// */ -// func requestPaymentIgnoreNativePG(payment: Payment) { -// dlog("뷰모델에 결제 요청했니 IgnoreNativePG ") -// DispatchQueue.main.async { -// self.repository.getWebViewStrategy(payment).doWork(payment) -// } -// } - /** * 본인인증 요청 */ - func requestCertification(_ payment: Payment) { - dlog("뷰모델에 본인인증 요청했니") + func requestCertification(_ payment: IamportRequest) { + debug_log("뷰모델에 본인인증 요청했니") DispatchQueue.main.async { self.repository.requestCertification(payment) } } -} \ No newline at end of file +}