iOS ๋ค์ดํฐ๋ธ ์ฑ์์ ๊ฒฐ์ ๊ฐ๋ฐ์ ๊ฐํธํ๊ฒ ๋์์ฃผ๋ ์์ํฌํธ SDK ์ ๋๋ค.
-
CHAI ๊ฐํธ๊ฒฐ์ ๋ Native ์ฐ๋๋์ด ์์ต๋๋ค.
-
์ฌ๋ฌ PG ๋ค์ WebView ๊ธฐ๋ฐ์ผ๋ก ๊ฒฐ์ ํ ์ ์์ต๋๋ค.
-
์ถํ ์์ฐจ์ ์ผ๋ก ํ ๊ฐํธ๊ฒฐ์ ๋ค๋ ๋ค์ดํฐ๋ธ ์ฐ๋ ์์ ์ ๋๋ค.
iOS ์ค์ ํผ์ณ๋ณด๊ธฐ
iOS์์ ์์ํฌํธ ๊ฒฐ์ ์ฐ๋ ๋ชจ๋์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์๋ 3๊ฐ์ง ํญ๋ชฉ์ ์ค์ ํด์ฃผ์ ์ผ ํฉ๋๋ค.
์ธ๋ถ ๊ฒฐ์ ์ฑ(์) ํ์ด์ฝ, ์ ํ ํ ํ์ด)์์ ๊ฒฐ์ ํ ๋์์ฌ ๋ ์ฌ์ฉํ URL identifier๋ฅผ ์ค์ ํด์ผํฉ๋๋ค.
[ํ๋ก์ ํธ ํด๋]/ios/[ํ๋ก์ ํธ ์ด๋ฆ]/Info.plist
ํ์ผ์ ์ฐ ํURL types
์์ฑ์ ์ถ๊ฐํฉ๋๋ค.- item
0
๋ฅผ ํ์ฅํ์ฌURL schemes
๋ฅผ ์ ํํฉ๋๋ค. - item
0
์ App Scheme์ ์์ฑํฉ๋๋ค.
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>
[ํ๋ก์ ํธ ํด๋]/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>
To run the example project, clone the repo, and run pod install
from the Example directory first.
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.1'
- Swift Package Manager ์ด์ฉ์ (RxSwift 6.x ์ฌ์ฉ)
iamport-ios 1.1.0 ๋ถํฐ ์ง์
- 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
}
ํผ์ณ๋ณด๊ธฐ
๋ณธ sdk ์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๊ฒฐ์ ์ฐ๋์ ํธ์๋ฅผ ์ ๊ณตํ๊ณ ์
Iamport.payment ๋ฅผ ํตํด ๊ฒฐ์ ์์ฒญ์ ์๋ก์ด UIViewController ๊ฐ ์ด๋ฆฌ๊ณ ,
๋ด๋ถ์ ์ผ๋ก WebView ๋ฅผ ์์ฑํ์ฌ ์ ๋ฌํด์ฃผ์ parameters ๋ฅผ ํตํด ๊ฒฐ์ ์ฐฝ์ ์ด๊ณ ์์ต๋๋ค.
๊ทธ๋ฌ๋ ์์ฒญ์ ๋ฐ๋ผ ๊ฐ๋ฐ์ ์์ ๋๋ฅผ ๋๋ฆฌ๊ธฐ ์ํด WebView Mode, MobileWeb Mode ๋๊ฐ์ง๊ฐ ์ถ๊ฐ๋์์ต๋๋ค. ( <= 1.0.0-dev08 )
์ค๋ช
: ๊ฒฐ์ ํ์ด์ง๋ฅผ ์ง์ ์์ฑํ์๊ณ iamport-sdk ์ WKWebView ๋ฅผ ๋๊ฒจ ๊ฒฐ์ ๋ฅผ ์งํํฉ๋๋ค.
ex) ์ง์ ๊ฒฐ์ ํ์ด์ง๋ฅผ ๊พธ๋ฏธ๊ธฐ ์ํ๋ ๋ถ.
- ๋ฐ์๋ฐฉ๋ฒ : ๊ธฐ์กด ์์ [Usage] ์ฌํญ ๊ณผ ๊ฐ์ด iamport-sdk ์ธํ
์ ํฉ๋๋ค.
Iamport.shared.paymentWebView ํธ์ถ ํ๋ผ๋ฏธํฐ ์ค webview ์ WKWebView ๋ฅผ ๋ฃ์ด์ฃผ์๋ฉด ๋ฉ๋๋ค. ๊ทธ ์ธ๋ ๊ธฐ์กด์ ๋์๊ณผ ๊ฐ์ต๋๋ค.
Iamport.shared.paymentWebView(webViewMode: wkWebView, /*์ดํ ๋์ผ*/)
-
์ค๋ช : ์์ํฌํธ๋ฅผ ์ฌ์ฉํ๋ 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)
}
}
ํผ์ณ๋ณด๊ธฐ
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" // ๊ฒฐ์ ํ ๋์์ฌ ์ฑ์คํด
}
}
}
ํผ์ณ๋ณด๊ธฐ
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
PortOne ๊ธฐ์ ์ง์, support@portone.io
iamport-ios is available under the MIT license. See the LICENSE file for more info.