플러터 라이브러리 : toss_payment | Flutter Package
토스 개발자센터 : 시작하기 | 토스페이먼츠 개발자센터
*pub-dev의 사용법을 따라서 차근차근 해보자!
라이브러리 자체가 토스페이먼츠가 지원해준건 아니지만, Flutter Webview를 활용해서 결제 연동이 가능하게 만들어주기 때문에 매우 유용하다.
defaultConfig {
...
**minSdkVersion 20 //20이상이면 더 높아도 괜찮음**
...
}
```xml
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<queries>
<!-- 토스 -->
<package android:name="viva.republica.toss" />
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="supertoss" />
</intent>
<!-- 삼성카드 -->
<package android:name="kr.co.samsungcard.mpocket" />
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="mpocket.online.ansimclick" />
</intent>
<!-- 현대카드 -->
<package android:name="com.hyundaicard.appcard" />
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="hdcardappcardansimclick" />
</intent>
<!-- 현대카드공인인증서 -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="smhyundaiansimclick" />
</intent>
<!-- 우리카드앱카드 -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="wooripay" />
</intent>
<!-- 신한카드앱카드 -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="shinhan-sr-ansimclick" />
</intent>
<!-- 신한카드공인인증서 -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="smshinhanansimclick" />
</intent>
<!-- 국민카드앱카드 -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="kb-acp" />
</intent>
<!-- 롯데카드모바일결제 -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="lottesmartpay" />
</intent>
<!-- 롯데카드앱카드 -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="lotteappcard" />
</intent>
<!-- 하나카드앱카드 -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="cloudpay" />
</intent>
<!-- 농협카드-앱카드 -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="nhappvardansimclick" />
</intent>
<!-- 농협카드공인인증서 -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="nonghyupcardansimclick" />
</intent>
<!-- 씨티카드공인인증서 -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="citicardappkr" />
</intent>
<!-- ISP모바일 -->
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="ispmobile" />
</intent>
</queries>
```
- 라이브러리에서 제공하는 추가팁
1. 안드로이드 웹에 접근이 안 될때
매니페스트에 아래 코드를 추가
```xml
<application
...
android:usesCleartextTraffic="true">
...
</application>
```
2. 안드로이드 12 이상에서 설치/실행이 안될 때
```xml
<activity
android:name=".MainActivity"
...
android:exported="true">
...
</activity>
```
- 추가해야하는 코드
```
<key>LSApplicationQueriesSchemes</key>
<array>
<string>supertoss</string> <!-- 토스페이 -->
<string>mpocket.online.ansimclick</string> <!-- 삼성카드앱카드 -->
<string>hdcardappcardansimclick</string> <!-- 현대카드앱카드 -->
<string>smhyundaiansimclick</string> <!-- 현대카드공인인증서 -->
<string>wooripay</string> <!-- 우리카드앱카드 -->
<string>shinhan-sr-ansimclick</string> <!-- 신한카드앱카드 -->
<string>smshinhanansimclick</string> <!-- 신한카드공인인증서 -->
<string>kb-acp</string> <!-- 국민카드앱카드 -->
<string>lottesmartpay</string> <!-- 롯데카드모바일결제 -->
<string>lotteappcard</string> <!-- 롯데카드앱카드 -->
<string>cloudpay</string> <!-- 하나카드앱카드 -->
<string>nhappvardansimclick</string> <!-- 농협카드-앱카드 -->
<string>nonghyupcardansimclick</string> <!-- 농협카드공인인증서 -->
<string>citispay</string> <!-- 씨티카드앱카드 -->
<string>citicardappkr</string> <!-- 씨티카드공인인증서 -->
<string>ispmobile</string> <!-- ISP모바일 -->
</array>
```
flutter pub add url_launcher
를 입력하고 info.plist에 아래 코드를 추가로 넣어둔다.<dict>
...
<key>LSApplicationQueriesSchemes</key> //이미 위에서 넣음!
<array> //그 밑 어레이 안애 아래 2줄만 추가하면 된다.
<string>https</string>
<string>http</string>
</array>
</dict>
//그냥 아래 코드대로 터미널 입력하거나
flutter pub add toss_payment
//pubspec.yaml에 아래 버젼을 추가후 pub get
dependencies:
toss_payment: ^0.2.6
토스 페이먼츠에 필요한 위젯과 mock-server를 직접 만들거나, 🔗 토스 페이먼츠 깃허브로 들어가서 파일들을 따온다.
출처 : https://docs.tosspayments.com/guides/windows/card
PaymentRequest
라는 모델 클래스를 사용해서 정보를 담고 jsonParse를 했다.PaymentRequest request = PaymentRequest( //모델 클래스 PaymentRequest
payBy: "카드"
amount: {price},
orderId: {id}, //"8pk23f" 같이 6자리 문자열로 랜덤 생성
orderName: {name}, //"생수 외 2건" 같은 식으로
customerName: {userName},
);
extension
을 사용해서 url을 덧붙이고 있고, localhost 8080번을 사용했다.extension PaymentRequestExtension on PaymentRequest {
Uri get url {
// TODO 토스페이를 위해 만든 Web 주소를 넣어주세요. 아래는 예시입니다.
return Uri.http("localhost:8080", "payment", json);
}
잘 호출했다면 토스 API를 통해 카드결제창이 웹뷰에 출력된다.
그리고 이 웹뷰창에서 결제를 완료하면, 위에서 미리 설정해둔 success 혹은 fail url이 전달되고,
서버는 우리에게 그 url을 response로 준다.
성공시 url 구성은 아래와 같다.
https://{ORIGIN}/success?paymentKey={PAYMENT_KEY}&orderId={ORDER_ID}&amount={AMOUNT}
- `paymentKey`: 결제 건에 대한 고유한 키 값
- `orderId`: 쇼핑몰에서 주문 건을 구분하기 위해 발급한 고유 ID,
결제창을 열 때 [requestPayment]에 담아 보낸 값
- `amount`: 실제로 결제된 금액
이 3개의 쿼리 파라미터를 가지고 결제 완료 validation을 진행해야 한다.
requestPayment
메서드에 담아 보냈던 amount
값과amount
값이 같은지 확인하고,var temp = url.split('success?')[1];
Map<String, String> params = {};
temp.split('&').forEach((e) {
var data = e.split('=');
params[data[0]] = data[1];
});
if(request.amont == params['amount']){
//다음 결제 승인 API 호출
}
현재 라이브러리는 결제 요청을 보내고 응답을 받는 화면까지만 구현되어 있다.
*2022년 11월 10일 기준
그러므로 우리는 현재 라이브러리와 깃허브 코드로 구현되어 있는 PaymentWebView
위젯의 onPageFinished 파라미터에 결제 금액이 맞게 들어온 후의 결제 승인 api호출을 구현해야 한다.
결제는 onPageStarted, onPageFinished에 여러 주소가 계속 꽂히기 때문에, if문으로 우리 successUrl을 onPageFinished가 받았는지 체크해주고, true면 이제 결제 승인 api호출을 하도록 만들어두자.
리다이렉트 URL로 받은 [paymentKey]
, [orderId]
, [amount]
를 요청 본문으로 함께 보내야 한다.
Dio dio = new Dio(); //dio(http통신 라이브러리의 인스턴스 준비)
if (request.amount.toString() == params['amount'].toString()) {
dio.options.headers['content-Type'] = 'application/json';
dio.options.headers['authorization'] =
'Basic dGVzdF9za196WExrS0V5cE5BcldtbzUwblgzbG1lYXhZRzVSOg';
//이부분은 내 토스페이먼츠 시크릿키를 콜론( : ) 을 뒤에 더해서 base64로 인코딩한 것이다.
//'Basic ${시크릿키+: 를 인코딩한 값}'
try{
var response = await dio.post(
'https://api.tosspayments.com/v1/payments/confirm',
data: params,
);
//성공후 어떻게 할건지 구현 필요
Navigator.of(context).pop(true);
}catch(e){
//실패부분 구현 필요
Navigator.of(context).pop(false);
}
}
{ mId: tvivarepublica,
transactionKey: [transactionKey],
lastTransactionKey: {lastTransactionKey},
paymentKey: {paymentKey},
orderId: BwcHAgIC,
orderName: 토스 티셔츠,
taxExemptionAmount: 0,
status: DONE,
requestedAt: 2022-11-11T14:28:29+09:00,
approvedAt: 2022-11-11T14:28:51+09:00,
useEscrow: false,
cultureExpense: false,
card: {
company: 신한,
issuerCode: {issuerCode},
acquirerCode: {acquireCode},
number: {number},
installmentPlanMonths: 0,
isInterestFree: false,
interestPayer: null,
approveNo: 00000000,
useCardPoint: false,
cardType: 신용,
ownerType: 개인,
acquireStatus: READY,
receiptUrl: https://dashboard.tosspayments.com/sales-slip?
transactionId=aGIScxIQzHzn9hcbBAlB8O568wgUN%2FNHfTGNLX9XXEE5Q9d1aPc5j2S%2BtDaF0J%2B6&
ref=PX
,
provider: null,
amount: 100 //totalAmount와 비교 필요
},
virtualAccount: null,
transfer: null,
mobilePhone: null,
giftCertificate: null,
cashReceipt: null,
discount: null,
cancels: null,
secret: {secret},
type: NORMAL,
easyPay: 네이버페이,
easyPayAmount: 0,
easyPayDiscountAmount: 0,
country: KR,
failure: null,
isPartialCancelable: true,
receipt: {
url: https://dashboard.tosspayments.com/sales-slip?transactionId=XL9Xc9DM2EziXHrhUDjITWhnCAXJ8TfN%2BTKwTJo8RHH7QUR8ITR5OhfFZI%2FUeFRs&ref=PX
},
checkout: {
url: https://api.tosspayments.com/v1/payments/p5EnNZRJGvaBX7zk2yd8yP2GAzyBXrx9POLqKQjmAw4b0e1Y/checkout
},
currency: KRW,
totalAmount: 100,
balanceAmount: 100,
suppliedAmount: 91,
vat: 9,
taxFreeAmount: 0,
method: 카드,
version: 1.4 }