๐ฑ I'mport iOS SDK ๐ฑ
iamport-ios
์ค๋ช
iOS ๋ค์ดํฐ๋ธ ์ฑ์์ ๊ฒฐ์ ๊ฐ๋ฐ์ ๊ฐํธํ๊ฒ ๋์์ฃผ๋ ์์ํฌํธ SDK ์ ๋๋ค.
-
CHAI ๊ฐํธ๊ฒฐ์ ๋ Native ์ฐ๋๋์ด ์์ต๋๋ค.
-
์ฌ๋ฌ PG ๋ค์ WebView ๊ธฐ๋ฐ์ผ๋ก ๊ฒฐ์ ํ ์ ์์ต๋๋ค.
-
์ถํ ์์ฐจ์ ์ผ๋ก ํ ๊ฐํธ๊ฒฐ์ ๋ค๋ ๋ค์ดํฐ๋ธ ์ฐ๋ ์์ ์ ๋๋ค.
iOS plist ์ค์ ๋ฐฉ๋ฒ
iOS ์ค์ ํผ์ณ๋ณด๊ธฐ
iOS ์ค์ ํ๊ธฐ
iOS์์ ์์ํฌํธ ๊ฒฐ์ ์ฐ๋ ๋ชจ๋์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์๋ 3๊ฐ์ง ํญ๋ชฉ์ ์ค์ ํด์ฃผ์ ์ผ ํฉ๋๋ค.
1. App Scheme ๋ฑ๋ก
์ธ๋ถ ๊ฒฐ์ ์ฑ(์) ํ์ด์ฝ, ์ ํ ํ ํ์ด)์์ ๊ฒฐ์ ํ ๋์์ฌ ๋ ์ฌ์ฉํ URL identifier๋ฅผ ์ค์ ํด์ผํฉ๋๋ค.
[ํ๋ก์ ํธ ํด๋]/ios/[ํ๋ก์ ํธ ์ด๋ฆ]/Info.plist
ํ์ผ์ ์ฐ ํURL types
์์ฑ์ ์ถ๊ฐํฉ๋๋ค.- item
0
๋ฅผ ํ์ฅํ์ฌURL schemes
๋ฅผ ์ ํํฉ๋๋ค. - item
0
์ App Scheme์ ์์ฑํฉ๋๋ค.
2. ์ธ๋ถ ์ฑ ๋ฆฌ์คํธ ๋ฑ๋ก
3rd party์ฑ(์) ๊ฐํธ๊ฒฐ์ ์ฑ)์ ์คํํ ์ ์๋๋ก ์ธ๋ถ ์ฑ ๋ฆฌ์คํธ๋ฅผ ๋ฑ๋กํด์ผํฉ๋๋ค.
[ํ๋ก์ ํธ ํด๋]/ios/[ํ๋ก์ ํธ ์ด๋ฆ]/Info.plist
ํ์ผ์ ์คํํฉ๋๋ค.- LSApplicationQueriesSchemes ์์ฑ์ ์ถ๊ฐํ๊ณ ์๋์ ์ธ๋ถ ์ฑ ๋ฆฌ์คํธ๋ฅผ ๋ฑ๋กํฉ๋๋ค.
<key>LSApplicationQueriesSchemes</key>
<array>
<string>kftc-bankpay</string> <!-- ๊ณ์ข์ด์ฒด -->
<string>ispmobile</string> <!-- ISP๋ชจ๋ฐ์ผ -->
<string>itms-apps</string> <!-- ์ฑ์คํ ์ด -->
<string>hdcardappcardansimclick</string> <!-- ํ๋์นด๋-์ฑ์นด๋ -->
<string>smhyundaiansimclick</string> <!-- ํ๋์นด๋-๊ณต์ธ์ธ์ฆ์ -->
<string>shinhan-sr-ansimclick</string> <!-- ์ ํ์นด๋-์ฑ์นด๋ -->
<string>smshinhanansimclick</string> <!-- ์ ํ์นด๋-๊ณต์ธ์ธ์ฆ์ -->
<string>kb-acp</string> <!-- ๊ตญ๋ฏผ์นด๋-์ฑ์นด๋ -->
<string>mpocket.online.ansimclick</string> <!-- ์ผ์ฑ์นด๋-์ฑ์นด๋ -->
<string>ansimclickscard</string> <!-- ์ผ์ฑ์นด๋-์จ๋ผ์ธ๊ฒฐ์ -->
<string>ansimclickipcollect</string> <!-- ์ผ์ฑ์นด๋-์จ๋ผ์ธ๊ฒฐ์ -->
<string>vguardstart</string> <!-- ์ผ์ฑ์นด๋-๋ฐฑ์ -->
<string>samsungpay</string> <!-- ์ผ์ฑ์นด๋-์ผ์ฑํ์ด -->
<string>scardcertiapp</string> <!-- ์ผ์ฑ์นด๋-๊ณต์ธ์ธ์ฆ์ -->
<string>lottesmartpay</string> <!-- ๋กฏ๋ฐ์นด๋-๋ชจ๋ฐ์ผ๊ฒฐ์ -->
<string>lotteappcard</string> <!-- ๋กฏ๋ฐ์นด๋-์ฑ์นด๋ -->
<string>cloudpay</string> <!-- ํ๋์นด๋-์ฑ์นด๋ -->
<string>nhappcardansimclick</string> <!-- ๋ํ์นด๋-์ฑ์นด๋ -->
<string>nonghyupcardansimclick</string> <!-- ๋ํ์นด๋-๊ณต์ธ์ธ์ฆ์ -->
<string>citispay</string> <!-- ์จํฐ์นด๋-์ฑ์นด๋ -->
<string>citicardappkr</string> <!-- ์จํฐ์นด๋-๊ณต์ธ์ธ์ฆ์ -->
<string>citimobileapp</string> <!-- ์จํฐ์นด๋-๊ฐํธ๊ฒฐ์ -->
<string>kakaotalk</string> <!-- ์นด์นด์คํก -->
<string>payco</string> <!-- ํ์ด์ฝ -->
<string>lpayapp</string> <!-- (๊ตฌ)๋กฏ๋ฐ Lํ์ด -->
<string>hanamopmoasign</string> <!-- ํ๋์นด๋ ๊ณต์ธ์ธ์ฆ์ฑ -->
<string>wooripay</string> <!-- (๊ตฌ) ์ฐ๋ฆฌํ์ด -->
<string>nhallonepayansimclick</string> <!-- NH ์ฌ์ํ์ด -->
<string>hanawalletmembers</string> <!-- ํ๋์นด๋(ํ๋๋ฉค๋ฒ์ค ์๋ ) -->
<string>chaipayment</string> <!-- ์ฐจ์ด -->
<string>kb-auth</string> <!-- ๊ตญ๋ฏผ -->
<string>hyundaicardappcardid</string> <!-- ํ๋์นด๋ -->
<string>com.wooricard.wcard</string> <!-- ์ฐ๋ฆฌwonํ์ด -->
<string>lmslpay</string> <!-- ๋กฏ๋ฐ Lํ์ด -->
<string>lguthepay-xpay</string> <!-- ํ์ด๋์ฐ -->
<string>liivbank</string> <!-- Liiv ๊ตญ๋ฏผ -->
<string>supertoss</string> <!-- ํ ์ค -->
<string>newsmartpib</string> <!-- ์ฐ๋ฆฌWON๋ฑ
ํน -->
</array>
3. App Transport Security ์ค์
[ํ๋ก์ ํธ ํด๋]/ios/[ํ๋ก์ ํธ ์ด๋ฆ]/Info.plist
ํ์ผ์ ์คํํฉ๋๋ค.App Transport Security
์์ฑ์ ์ถ๊ฐํฉ๋๋ค.- ํ๋ถ ์์ฑ์
Allow Arbitrary Loads in Web Content
,Allow Arbitrary Loads
์์ฑ์ ์ถ๊ฐํ๊ณ ๊ฐ๊ฐ์ ๊ฐ(value)์YES
๋ก ๋ณ๊ฒฝํฉ๋๋ค.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Example
To run the example project, clone the repo, and run pod install
from the Example directory first.
Requirements
Installation
iamport-ios is available through CocoaPods. To install it, simply add the following line to your Podfile:
- cocoapods ์ด์ฉ์ (RxSwift 5.x ์ฌ์ฉ)
pod 'iamport-ios', '~> 1.4.0'
- Swift Package Manager ์ด์ฉ์ (RxSwift 6.x ์ฌ์ฉ)
iamport-ios 1.1.0 ๋ถํฐ ์ง์
Usage
- UINavigationController ์ฌ์ฉ์ ๊ฒฝ์ฐ.
storyboard ์ root view controller ์์ Xcode ์๋จ -> Editor -> Embed in -> Navigation Controller.- UIViewController, WKWebView ์ง์.
// ๊ฒฐ์ ์์ฒญ ๋ฐ์ดํฐ ๊ตฌ์ฑ
let payment = IamportPayment(
pg: PG.html5_inicis.getPgSting(pgId: ""), // PG ์ฌ
merchant_uid: "mid_123456", // ์ฃผ๋ฌธ๋ฒํธ
amount: "1000").then { // ๊ฐ๊ฒฉ
$0.pay_method = "card" // ๊ฒฐ์ ์๋จ
$0.name = "์ํ ๋จธ์ฒํธ์์ ์ฃผ๋ฌธ~" // ์ฃผ๋ฌธ๋ช
$0.buyer_name = "๋
๊ณ ๋
"
$0.app_scheme = "iamport" // ๊ฒฐ์ ํ ์ฑ์ผ๋ก ๋ณต๊ท ์ํ app scheme
}
// I'mport SDK ์ ๊ฒฐ์ ์์ฒญ
// case1 : UINavigationController ์ฌ์ฉ
Iamport.shared.payment(navController: navigationController, // ๋ค๋น๊ฒ์ด์
์ปจํธ๋กค๋ฌ
userCode: userCode, // ๋จธ์ฒํธ ์ ์ ์๋ณ ์ฝ๋
payment: payment) // ๊ฒฐ์ ์์ฒญ ๋ฐ์ดํฐ
{ [weak self] iamportResponse in
// ๊ฒฐ์ ์ข
๋ฃ ์ฝ๋ฐฑ
}
// case2 : UIViewController ์ฌ์ฉ
Iamport.shared.payment(viewController: viewController, /* ์ดํ๋์ผ.. */)
// case3 : WebView ๋ฅผ ๋ฐ๋ก ๋๊ฒจ ๊ฒฐ์ ๋ฅผ ์ํ๋ฉด, ์๋ [Optional ๊ตฌํ์ฌํญ WebView Mode ์ MobileWeb Mode] ์ฐธ์กฐํ์ธ์.
Iamport.shared.close() // sdk ์ข
๋ฃ ์ํ ์ ํธ์ถ
// AppDelegate.swift ์ค์
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
Iamport.shared.receivedURL(url)
return true
}
Optional ๊ตฌํ์ฌํญ WebView Mode ์ MobileWeb Mode
ํผ์ณ๋ณด๊ธฐ
๋ณธ sdk ์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๊ฒฐ์ ์ฐ๋์ ํธ์๋ฅผ ์ ๊ณตํ๊ณ ์
Iamport.payment ๋ฅผ ํตํด ๊ฒฐ์ ์์ฒญ์ ์๋ก์ด UIViewController ๊ฐ ์ด๋ฆฌ๊ณ ,
๋ด๋ถ์ ์ผ๋ก WebView ๋ฅผ ์์ฑํ์ฌ ์ ๋ฌํด์ฃผ์ parameters ๋ฅผ ํตํด ๊ฒฐ์ ์ฐฝ์ ์ด๊ณ ์์ต๋๋ค.
๊ทธ๋ฌ๋ ์์ฒญ์ ๋ฐ๋ผ ๊ฐ๋ฐ์ ์์ ๋๋ฅผ ๋๋ฆฌ๊ธฐ ์ํด WebView Mode, MobileWeb Mode ๋๊ฐ์ง๊ฐ ์ถ๊ฐ๋์์ต๋๋ค. ( <= 1.0.0-dev08 )
1. WebView Mode
์ค๋ช
: ๊ฒฐ์ ํ์ด์ง๋ฅผ ์ง์ ์์ฑํ์๊ณ iamport-sdk ์ WKWebView ๋ฅผ ๋๊ฒจ ๊ฒฐ์ ๋ฅผ ์งํํฉ๋๋ค.
ex) ์ง์ ๊ฒฐ์ ํ์ด์ง๋ฅผ ๊พธ๋ฏธ๊ธฐ ์ํ๋ ๋ถ.
- ๋ฐ์๋ฐฉ๋ฒ : ๊ธฐ์กด ์์ [Usage] ์ฌํญ ๊ณผ ๊ฐ์ด iamport-sdk ์ธํ
์ ํฉ๋๋ค.
Iamport.shared.paymentWebView ํธ์ถ ํ๋ผ๋ฏธํฐ ์ค webview ์ WKWebView ๋ฅผ ๋ฃ์ด์ฃผ์๋ฉด ๋ฉ๋๋ค. ๊ทธ ์ธ๋ ๊ธฐ์กด์ ๋์๊ณผ ๊ฐ์ต๋๋ค.
Iamport.shared.paymentWebView(webViewMode: wkWebView, /*์ดํ ๋์ผ*/)
2. MobileWeb Mode
-
์ค๋ช : ์์ํฌํธ๋ฅผ ์ฌ์ฉํ๋ Mobile ์นํ์ด์ง๊ฐ load ๋ webview ๋ฅผ ๋๊ฒจ ๊ฒฐ์ ์งํ์ ์ํฌํธ ํฉ๋๋ค.
ex) ์ด๋ฏธ ์น์ฌ์ดํธ์์ ์์ํฌํธ js sdk ๋ฅผ ์ด์ฉํ๊ณ ์๊ณ , ๋ณธ์ธ ์๋น์ค๋ฅผ app ์ผ๋ก๋ง ๊ฐ์ธ์ ์ถ์ ํ๊ณ ์ ํ์๋ ๋ถ. -
๋ฐ์๋ฐฉ๋ฒ Step1 : ios ์ฑ์์ ๊ธฐ์กด ์์ [Usage] ์ฌํญ ๊ณผ ๊ฐ์ด iamport-sdk ์ธํ ์ ํฉ๋๋ค.
์ถ๊ฐ๋ก Iamport.shared.pluginMobileWebSupporter(webview) ๋ฅผ ํธ์ถํ์ฌ ํ๋ผ๋ฏธํฐ๋ก webview ๋ฅผ ์ ๋ฌํฉ๋๋ค.
์ค์ ๊ฒฐ์ ์งํ์ ๊ณ ๊ฐ๋์ ์น์ฌ์ดํธ ๋ด์์ ์งํ๋ฉ๋๋ค.
mobileweb.html ์ฐธ์กฐ (์์์ด๋ฉฐ ์ค์ ๋ก๋ ๊ณ ๊ฐ๋์ Front-End ๊ฐ ๋ฉ๋๋ค.)
PaymentMobileWebMode.swift ์ฐธ์กฐ
Iamport.shared.pluginMobileWebSupporter(mobileWebMode: wkWebView)
-
๋ฐ์๋ฐฉ๋ฒ Step2 : ๊ธฐ์กด js sdk ๋ฅผ ์ฌ์ฉํ๋ ์น ํ๋ก ํธ์๋(html) ์
IMP.request_pay
,IMP.certification
๋ฅผ ํธ์ถํ๋ ๊ณณ ์์์, ์๋์ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค. -
์ ๋ฌํ๋ ๋ฐ์ดํฐ ํ์
// 1. `IMP.request_pay`๋ฅผ ํตํ ๊ฒฐ์ ์ ๊ฒฝ์ฐ
const params = {
userCode: userCode, // ๊ฐ๋งน์ ์๋ณ์ฝ๋
payment: payment, // ๊ฒฐ์ ๋ฐ์ดํฐ
};
// 2. `IMP.certification`๋ฅผ ํตํ ๋ณธ์ธ์ธ์ฆ์ ๊ฒฝ์ฐ
const params = {
userCode: userCode, // ๊ฐ๋งน์ ์๋ณ์ฝ๋
certification: certification, // ๋ณธ์ธ์ธ์ฆ ๋ฐ์ดํฐ
};
- ์์์ฝ๋
// ์์
// start of ์ถ๊ฐ๋๋ ๋ถ๋ถ
const isIOS = (/iphone|ipad|ipod/i.test(navigator.userAgent.toLowerCase()));
if(isIOS) {
try {
const params = {
userCode : userCode, // ๊ฐ๋งน์ ์๋ณ์ฝ๋
iamportRequest : data, // ๊ฒฐ์ ๋ฐ์ดํฐ
};
window.webkit.messageHandlers.iamportmobilewebmode.postMessage(params)
} catch (error) {
console.error(error);
}
}
// End of ์ถ๊ฐ๋๋ ๋ถ๋ถ
// ๊ธฐ์กด์ js IMP.request_pay
IMP.request_pay(data, ... // ์๋ต
- Custom WKWebViewDelegate ์ ์ฌ์ฉ
/**
webview url ์ ํตํด ์ฒ๋ฆฌํ๋ ๋ก์ง์ด ์์ ๊ฒฝ์ฐ์
[IamportWKWebViewDelegate] ์์ํ์ฌ ์ฌ์ฉ ํ์๊ฑฐ๋,
[Iamport.shared.updateWebViewUrl] ์ subscribe ์ ํตํด ๋ณ๊ฒฝ๋๋ url ์ ์ฒดํฌ ๊ฐ๋ฅํฉ๋๋ค.
*/
// CASE1 : IamportWKWebViewDelegate ์์
class MyWKWebViewDelegate: IamportWKWebViewDelegate {
override func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url {
// TODO : write your logic
print("MyWKNavigationDelegate received url : \(url)")
}
super.webView(webView, decidePolicyFor: navigationAction, decisionHandler: decisionHandler)
}
}
let webViewDelegate = MyWKWebViewDelegate()
class MyView: UIViewController {
override func viewDidAppear(_ animated: Bool) {
..
// IamportWKWebViewDelegate ์ฌ์ฉ
wkWebView.navigationDelegate = webViewDelegate as WKNavigationDelegate
// CASE2 : [Iamport.shared.updateWebViewUrl] ์ฌ์ฉ
Iamport.shared.updateWebViewUrl.subscribe { [weak self] url in
print("updateWebViewUrl received url : \(url.element)")
}.disposed(by: disposeBag)
}
}
Optional ๊ตฌํ์ฌํญ SwiftUI ์์์ ์ฌ์ฉ
ํผ์ณ๋ณด๊ธฐ
SwiftUI ๋ฅผ ์ฌ์ฉํ์๋ ๋ถ๋ค์ ์์ WebViewMode ๋ฅผ ์ฌ์ฉํ์๊ฑฐ๋,
์๋ ์ฝ๋๋ฅผ ์ฐธ์กฐํ์์ด UIViewContorller ๋ฅผ ๊ตฌ์ฑํด ์ฌ์ฉํ์๊ธฐ ๋ฐ๋๋๋ค.
๋ํ Example app ์ ๋ฐ์๋์ด ์์ผ๋ ์ฐธ๊ณ ํ์๊ธฐ ๋ฐ๋๋๋ค.
PaymentView.swift ์ฐธ์กฐ
struct IamportPaymentView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIViewController {
let view = IamportPaymentViewController()
return view
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {}
}
class IamportPaymentViewController: UIViewController {
// ์์ํฌํธ SDK ๊ฒฐ์ ์์ฒญ
func requestIamportPayment() {
let userCode = "iamport" // iamport ์์ ๋ถ์ฌ๋ฐ์ ๊ฐ๋งน์ ์๋ณ์ฝ๋
let payment = createPaymentData()
Iamport.shared.payment(viewController: self,
userCode: userCode, payment: payment) { [weak self] response in
print("๊ฒฐ๊ณผ : \(response)")
}
}
// ์์ํฌํธ ๊ฒฐ์ ๋ฐ์ดํฐ ์์ฑ
func createPaymentData() -> IamportPayment {
return IamportPayment(
pg: PG.html5_inicis.makePgRawName(pgId: ""),
merchant_uid: "swiftui_ios_\(Int(Date().timeIntervalSince1970))",
amount: "1000").then {
$0.pay_method = "card"
$0.name = "SwiftUI ์์ ์ฃผ๋ฌธ์
๋๋ค"
$0.buyer_name = "SwiftUI"
$0.app_scheme = "iamporttest" // ๊ฒฐ์ ํ ๋์์ฌ ์ฑ์คํด
}
}
}
Optional ๊ตฌํ์ฌํญ SceneDelegate ์์์ ์ฌ์ฉ (target iOS13)
ํผ์ณ๋ณด๊ธฐ
iOS 13 ๋ถํฐ๋ ๊ธฐ์กด์ AppDelegate ์ผ๋ก ๋ถํฐ UILifecycle ๊ด๋ฆฌ๊ฐ ๋ถ๋ฆฌ๋๋ฉด์
SceneDelegate ๊ฐ ์ถ๊ฐ๋์์ต๋๋ค.
AppDelegate ์ฌ์ฉ ์ฝ๋ ๋์ ์๋ ์ฝ๋๋ฅผ ์ฐธ์กฐํด์ ๋ฐ์ํ์๊ธฐ ๋ฐ๋๋๋ค.
SceneDelegate.swift ์ฐธ์กฐ
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
..
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
if let url = URLContexts.first?.url {
Iamport.shared.receivedURL(url)
}
}
}
๐ก ์ํ์ฑ
- SwiftUI ๋ก ์์ฑ(Target iOS 13)
์คํ๋ฐฉ๋ฒ
- git clone
- Xcode project open
- connect iPhone via USB Cable(or use Simulator, Simulator ์ฌ์ฉ์ ๊ฒฐ์ ํ์ธ์ ๋ถ๊ฐ๋ฅ ํฉ๋๋ค.)
- build Example app
Support
PortOne ๊ธฐ์ ์ง์, [email protected]
License
iamport-ios is available under the MIT license. See the LICENSE file for more info.