Repository files navigation

bootpay 플러터 라이브러리

부트페이에서 지원하는 공식 Flutter 라이브러리 입니다

  • Android, iOS, Web 을 지원합니다.
  • Android SDK 16, iOS OS 13 부터 사용 가능합니다.

Bootpay 버전안내

이 모듈의 4.0.0 이상 버전부터는 Bootpay V2 이며, 그 이하 버전은 Bootpay V1에 해당합니다.

Bootpay V1, V2에 대한 특이점은 개발매뉴얼을 참고해주세요.

기능

  1. web/ios/android 지원
  2. 국내 주요 PG사 지원
  3. 주요 결제수단 지원
  4. 카드/계좌 자동결제 지원
  5. 위젯 지원
  6. 본인인증 지원

설치하기

pubspec.yaml 파일에 아래 모듈을 추가해주세요

...
dependencies:
...bootpay: last_version
...

설정하기

Android

따로 설정하실 것이 없습니다.

iOS

{your project root}/ios/Runner/Info.plist

CFBundleURLNameCFBundleURLSchemes의 값은 개발사에서 고유값으로 지정해주셔야 합니다. 외부앱(카드사앱)에서 다시 기존 앱으로 돌아올 때 필요한 스키마 값입니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPEplist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plistversion="1.0">
<dict>
...
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>kr.co.bootpaySample</string> <key>CFBundleURLSchemes</key>
<array>
<string>bootpaySample</string> </array>
</dict>
</array> </dict>
</plist>

Web

flutter web 빌드하면 web/index.html 파일이 생성됩니다. 해당 파일 header에 아래 script를 추가해주세요.

<!-- bootpay-최신버전-js 를 참조하여 추가합니다 --><scriptsrc="https://js.bootpay.co.kr/bootpay-5.3.0.min.js"></script><scriptsrc="bootpay_api.js" defer></script>

bootpay_api 파일을 프로젝트에 추가합니다.

위 설정을 완료하면 flutter web에서도 동일한 문법으로 bootpay를 사용할 수 있습니다.

iOS WebView 프리워밍 (자동)

iOS의 WKWebView는 첫 로딩 시 GPU, Networking, WebContent 프로세스 초기화로 4-6초 지연이 발생할 수 있습니다.

Bootpay Flutter SDK는 플러그인 등록 시 자동으로 프리워밍이 시작됩니다. 별도의 설정 없이도 첫 결제 화면 로딩 속도가 개선됩니다.

수동 호출 (선택사항)

특별한 타이밍에 프리워밍을 시작하고 싶다면 수동으로 호출할 수 있습니다:

import'package:bootpay/bootpay_warmup.dart';
// 기본 호출 (0.1초 딜레이)awaitBootpayWarmUp.warmUp();
// UI가 버벅이면 딜레이 증가awaitBootpayWarmUp.warmUp(delay:0.5);
// 프리워밍 상태 확인bool isReady =awaitBootpayWarmUp.checkIsWarmedUp();
// 메모리 부족 시 리소스 해제awaitBootpayWarmUp.releaseWarmUp();
API설명
BootpayWarmUp.warmUp()WebView 프로세스 미리 초기화 (자동 실행됨)
BootpayWarmUp.warmUp(delay: 0.5)커스텀 딜레이로 프리워밍
BootpayWarmUp.checkIsWarmedUp()프리워밍 완료 여부 확인
BootpayWarmUp.releaseWarmUp()프리워밍 리소스 해제

참고: Android와 Web에서는 이 기능이 no-op으로 동작합니다 (iOS/macOS 전용).

위젯 설정

부트페이 관리자에서 위젯을 생성하셔야만 사용이 가능합니다.

위젯 렌더링

Payload _payload =Payload();
BootpayWidgetController _controller =BootpayWidgetController();
@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
_payload.orderName ='5월 수강료';
_payload.orderId =DateTime
.now()
.millisecondsSinceEpoch
.toString();
_payload.webApplicationId = webApplicationId;
_payload.androidApplicationId = androidApplicationId;
_payload.iosApplicationId = iosApplicationId;
_payload.price =1000;
_payload.taxFree =0;
_payload.widgetKey ='default-widget';
_payload.widgetSandbox =true;
_payload.widgetUseTerms =true;
// _payload.userToken = "6667b08b04ab6d03f274d32e";
_payload.extra?.displaySuccessResult =true;
}
@overrideWidgetbuild(BuildContext context) {
returnContainer(
//하위로 위젯 정의 
child:BootpayWidget(
payload: _payload,
controller: _controller,
)
);
}

위젯 이벤트 처리

@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
// BootpayWidgetController _controller = BootpayWidgetController();//위젯 사이즈 변경 이벤트 
_controller.onWidgetResize = (height) {
print('onWidgetResize : $height');
//예제에서는 높이가 변경되면 스크롤을 내립니다.if(_widgetHeight == height) return;
if(_widgetHeight < height) {
scrollDown(height - _widgetHeight);
}
setState(() {
_widgetHeight = height;
});
};
//선택된 결제수단 변경 이벤트 
_controller.onWidgetChangePayment = (widgetData) {
print('onWidgetChangePayment22 : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//선택된 약관 변경 이벤트
_controller.onWidgetChangeAgreeTerm = (widgetData) {
print('onWidgetChangeAgreeTerm : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//위젯이 렌더링되면 호출되는 이벤트
_controller.onWidgetReady = () {
print('onWidgetReady');
};
}

위젯으로 결제하기

이 방법은 위젯을 사용하여 결제하는 방법입니다. 위젯을 사용하지 않고 결제를 요청하는 방법은 별도로 제공합니다.

// BootpayWidgetController _controller = BootpayWidgetController();
_controller.requestPayment(
context: context,
payload: _payload,
onCancel: (String data) {
print('------- onCancel 2 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onConfirm: (String data) {
print('------- onConfirm: $data');
returntrue; //결제를 승인합니다 
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onDone: (String data) {
print('------- onDone: $data');
// FlutterToast.showToast(msg: '결제가 완료되었습니다.');
},
);

결제하기

이 방법은 위젯을 사용하지 않고 결제하는 방법입니다.

//결제 정보를 초기화합니다.voidbootpayReqeustDataInit() {
Item item1 =Item();
item1.name ="미키 '마우스"; // 주문정보에 담길 상품명
item1.qty =1; // 해당 상품의 주문 수량
item1.id ="ITEM_CODE_MOUSE"; // 해당 상품의 고유 키
item1.price =500; // 상품의 가격Item item2 =Item();
item2.name ="키보드"; // 주문정보에 담길 상품명
item2.qty =1; // 해당 상품의 주문 수량
item2.id ="ITEM_CODE_KEYBOARD"; // 해당 상품의 고유 키
item2.price =500; // 상품의 가격List<Item> itemList = [item1, item2];
payload.webApplicationId = webApplicationId; // web application id
payload.androidApplicationId = androidApplicationId; // android application id
payload.iosApplicationId = iosApplicationId; // ios application id
payload.pg ='다날';
payload.method ='카드';
// payload.methods = ['카드', '휴대폰', '가상계좌', '계좌이체', '카카오페이'];
payload.orderName ="테스트 상품"; //결제할 상품명
payload.price =1000.0; //정기결제시 0 혹은 주석
payload.orderId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값
payload.items = itemList; // 상품정보 배열User user =User(); // 구매자 정보
user.id ="12341234";
user.username ="사용자 이름";
user.email ="user1234@gmail.com";
user.area ="서울";
user.phone ="010-0000-0000";
user.addr ='null';
Extra extra =Extra(); // 결제 옵션
extra.appScheme ='bootpayFlutter'; //결제 후 돌아갈 ios 앱 스키마를 설정합니다 
payload.user = user;
payload.items = itemList;
payload.extra = extra; }
voidgoBootpayPayment(BuildContext context) {
Bootpay().requestPayment(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 1 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { // checkQtyFromServer(data);returntrue;
},
// onConfirmAsync: (String data) async {// onConfirm 대신 사용하는 이벤트 처리 함수입니다. 내부에서 Future 문법을 사용할 수 있습니다.// print('------- onConfirmAsync: $data');// return true;// },
onDone: (String data) {
print('------- onDone: $data');
},
);
}

Bootpay 승인 요청

onConfirm, onConfirmAsync에서 승인 요청시 사용하는 함수입니다. 이 함수는 return false 로 리턴할 경우 사용합니다.

Bootpay().transactionConfirm();
returnfalse; 

Bootpay 창 닫기

onConfirm, onConfirmAsync등에서 진행중인 결제창을 닫을 때 사용하는 함수입니다. 서버인증으로 승인이 되었을 경우에, 클라이언트에서 창을 닫을 때 사용합니다.

Bootpay().dismiss(context);
returnfalse; 

자동결제 - 빌링키 발급 요청하기

voidgoBootpaySubscriptionUITest(BuildContext context) {
payload.subscriptionId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.pg ="키움페이";
payload.method ="카드자동"; // payload.price = 1000; 금액이 0 이상일 경우 빌링키 발급 후 결제가 진행됩니다.
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값Bootpay().requestSubscription(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 3: $data');
},
onError: (String data) {
print('------- onError 3: $data');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
//TODO - 원하시는 라우터로 페이지 이동
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);
}

본인인증

payload.pg ="다날";
payload.method ="본인인증";
payload.authenticationId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.extra =Extra();
payload.extra?.openType ='iframe';
payload.items =null;
Bootpay().requestAuthentication(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel: $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);

결제 진행 상태에 따라 LifeCycle 함수가 실행됩니다. 각 함수에 대한 상세 설명은 아래를 참고하세요.

onError 함수

결제 진행 중 오류가 발생된 경우 호출되는 함수입니다. 진행중 에러가 발생되는 경우는 다음과 같습니다.

  1. 부트페이 관리자에서 활성화 하지 않은 PG, 결제수단을 사용하고자 할 때
  2. PG에서 보내온 결제 정보를 부트페이 관리자에 잘못 입력하거나 입력하지 않은 경우
  3. 결제 진행 도중 한도초과, 카드정지, 휴대폰소액결제 막힘, 계좌이체 불가 등의 사유로 결제가 안되는 경우
  4. PG에서 리턴된 값이 다른 Client에 의해 변조된 경우

에러가 난 경우 해당 함수를 통해 관련 에러 메세지를 사용자에게 보여줄 수 있습니다.

data 포맷은 아래와 같습니다.

{
action: "BootpayError",
message: "카드사 거절",
receipt_id: "5fffab350c20b903e88a2cff"
}

onCancel 함수

결제 진행 중 사용자가 PG 결제창에서 취소 혹은 닫기 버튼을 눌러 나온 경우 입니다. ****

data 포맷은 아래와 같습니다.

{
action: "BootpayCancel",
message: "사용자가 결제를 취소하였습니다.",
receipt_id: "5fffab350c20b903e88a2cff"
}

onIssued 함수

가상계좌 발급이 완료되면 호출되는 함수입니다(가상계좌를 위한 Done). 가상계좌는 다른 결제와 다르게 입금할 계좌 번호 발급 이후 입금 후에 Feedback URL을 통해 통지가 됩니다. 발급된 가상계좌 정보를 issued 함수를 통해 확인하실 수 있습니다.

data 포맷은 아래와 같습니다.

{
account: "T0309260001169"
accounthodler: "한국사이버결제"
action: "BootpayBankReady"
bankcode: "BK03"
bankname: "기업은행"
expiredate: "2021-01-17 00:00:00"
item_name: "테스트 아이템"
method: "vbank"
method_name: "가상계좌"
order_id: "1610591554856"
metadata: null
payment_group: "vbank"
payment_group_name: "가상계좌"
payment_name: "가상계좌"
pg: "kcp"
pg_name: "KCP"
price: 3000
purchased_at: null
ready_url: "https://dev-app.bootpay.co.kr/bank/7o044QyX7p"
receipt_id: "5fffad430c20b903e88a2d17"
requested_at: "2021-01-14 11:32:35"
status: 2
tax_free: 0
url: "https://d-cdn.bootapi.com"
username: "홍길동"
}

onConfirm 함수

결제 승인이 되기 전 호출되는 함수입니다. 승인 이전 관련 로직을 서버 혹은 클라이언트에서 수행 후 결제를 승인해도 될 경우BootPay.transactionConfirm(data); 또는 return true;

코드를 실행해주시면 PG에서 결제 승인이 진행이 됩니다.

* 페이앱, 페이레터 PG는 이 함수가 실행되지 않고 바로 결제가 승인되는 PG 입니다. 참고해주시기 바랍니다.

data 포맷은 아래와 같습니다.

{
receipt_id: "5fffc0460c20b903e88a2d2c",
action: "BootpayConfirm"
}

onDone 함수

PG에서 거래 승인 이후에 호출 되는 함수입니다. 결제 완료 후 다음 결제 결과를 호출 할 수 있는 함수 입니다.

이 함수가 호출 된 후 반드시 REST API를 통해 결제검증을 수행해증야합니다. data 포맷은 아래와 같습니다.

{
action: "BootpayDone"
card_code: "CCKM",
card_name: "KB국민카드",
card_no: "0000120000000014",
card_quota: "00",
item_name: "테스트 아이템",
method: "card",
method_name: "카드결제",
order_id: "1610596422328",
payment_group: "card",
payment_group_name: "신용카드",
payment_name: "카드결제",
pg: "kcp",
pg_name: "KCP",
price: 100,
purchased_at: "2021-01-14 12:54:53",
receipt_id: "5fffc0460c20b903e88a2d2c",
receipt_url: "https://app.bootpay.co.kr/bill/UFMvZzJqSWNDNU9ERWh1YmUycU9hdnBkV29DVlJqdzUxRzZyNXRXbkNVZW81%0AQT09LS1XYlNJN1VoMDI4Q1hRdDh1LS10MEtZVmE4c1dyWHNHTXpZTVVLUk1R%0APT0%3D%0A",
requested_at: "2021-01-14 12:53:42",
status: 1,
tax_free: 0,
url: "https://d-cdn.bootapi.com"
}

WebView 프리워밍 (iOS/macOS)

iOS에서 WKWebView는 처음 로딩 시 GPU, Networking, WebContent 프로세스를 생성하는데 3-7초가 소요됩니다. Bootpay SDK는 자동으로 앱 시작 시 백그라운드에서 프로세스를 미리 생성하여 첫 결제 화면 로딩 속도를 개선합니다.

자동 프리워밍

SDK 초기화 시(첫 번째 Bootpay() 호출 시) 자동으로 프리워밍이 수행됩니다. 개발자가 별도로 호출할 필요가 없습니다.

메모리 관리 (선택사항)

메모리 부족 시 프리워밍된 리소스를 해제할 수 있습니다:

// 메모리 경고 수신 시 (선택사항)Bootpay.releaseWarmUp();

iOS AppDelegate에서 메모리 경고 시 자동 해제하도록 설정할 수도 있습니다:

// AppDelegate.swift
import bootpay_webview_flutter_wkwebview
overridefunc applicationDidReceiveMemoryWarning(_ application:UIApplication){
super.applicationDidReceiveMemoryWarning(application)BootpayWarmUpManager.shared.releaseWarmUp()}

효과

항목개선 효과
GPU 프로세스 초기화1-2초 단축
Networking 프로세스 초기화1-2초 단축
WebContent 프로세스 초기화1-3초 단축
총 개선 효과3-7초 단축

참고사항

  • iOS/macOS에서만 동작합니다. Android와 Web에서는 자동으로 무시됩니다.
  • 프리워밍은 자동으로 수행되므로 별도 설정이 필요 없습니다.
  • 두 번째 결제부터는 ProcessPool 공유로 자동으로 빠릅니다.

팝업 닫기(✕) 버튼 (iOS/Android)

결제창 안에서 window.open 또는 target="_blank" 로 열리는 팝업(주로 광고)은 앱 안에서 그대로 표시됩니다. 이런 팝업은 우측 상단에 뜨는 반투명 ✕ 버튼으로 사용자가 직접 닫을 수 있습니다.

광고는 차단되지 않습니다. 광고는 항상 인앱에 그대로 노출되며, 아래 설정은 "✕ 버튼을 언제 보여줄지"와 "팝업을 코드로 닫는 방법"만 제어합니다. 결제 PG 팝업은 window.close() 로 스스로 닫히므로 기본적으로 ✕ 가 붙지 않습니다.

import 'package:bootpay/bootpay.dart'; 후 아래 정적 메서드를 사용합니다.

✕ 버튼 노출 모드 설정

// 기본값(auto): 광고 도메인으로 분류된 팝업에만 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.auto);
// 모든 팝업에 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.always);
// ✕ 를 절대 노출하지 않음 (window.close 또는 closePopupWebView 로만 닫기)Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.never);
모드동작
BootpayPopupCloseButtonMode.auto기본값. 광고 도메인(addPopupAdHosts 목록)으로 분류된 팝업에만 ✕ 노출
BootpayPopupCloseButtonMode.always모든 팝업에 ✕ 노출
BootpayPopupCloseButtonMode.never✕ 를 노출하지 않음

광고 도메인 추가 (auto 모드용)

auto 모드에서 ✕ 를 띄울 광고 도메인을 런타임에 추가합니다. SDK 는 doubleclick.net / googleadservices.com / googlesyndication.com 등 주요 광고 네트워크 도메인을 기본 내장하고 있으며, 그 외 도메인을 더 넣고 싶을 때 사용합니다.

// host 의 부분 문자열로 대소문자 구분 없이 매칭됩니다.Bootpay.addPopupAdHosts(['ads.example.com', 'partner-ad.net']);

팝업을 코드로 닫기

광고 SDK 의 "광고 종료" 이벤트 등을 받았을 때, 사용자가 ✕ 를 누르지 않아도 현재 떠 있는 팝업을 닫을 수 있습니다. 메인 결제 WebView 에는 영향이 없으며, 열린 팝업이 없으면 아무 동작도 하지 않습니다.

Bootpay.closePopupWebView();
API설명
Bootpay.setPopupCloseButtonMode(mode)✕ 버튼 노출 모드 설정 (auto/always/never)
Bootpay.addPopupAdHosts(List<String> hosts)auto 모드에서 ✕ 를 띄울 광고 도메인 추가
Bootpay.closePopupWebView()현재 떠 있는 팝업을 프로그래매틱하게 닫기

참고: iOS / Android 전용입니다. Web 에서는 모두 no-op 으로 동작합니다.

Documentation

부트페이 개발매뉴얼을 참조해주세요

기술문의

채팅으로 문의

License

MIT License.

About

2세대 flutter api

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

bootpay 플러터 라이브러리

부트페이에서 지원하는 공식 Flutter 라이브러리 입니다

  • Android, iOS, Web 을 지원합니다.
  • Android SDK 16, iOS OS 13 부터 사용 가능합니다.

Bootpay 버전안내

이 모듈의 4.0.0 이상 버전부터는 Bootpay V2 이며, 그 이하 버전은 Bootpay V1에 해당합니다.

Bootpay V1, V2에 대한 특이점은 개발매뉴얼을 참고해주세요.

기능

  1. web/ios/android 지원
  2. 국내 주요 PG사 지원
  3. 주요 결제수단 지원
  4. 카드/계좌 자동결제 지원
  5. 위젯 지원
  6. 본인인증 지원

설치하기

pubspec.yaml 파일에 아래 모듈을 추가해주세요

...
dependencies:
...bootpay: last_version
...

설정하기

Android

따로 설정하실 것이 없습니다.

iOS

{your project root}/ios/Runner/Info.plist

CFBundleURLNameCFBundleURLSchemes의 값은 개발사에서 고유값으로 지정해주셔야 합니다. 외부앱(카드사앱)에서 다시 기존 앱으로 돌아올 때 필요한 스키마 값입니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPEplist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plistversion="1.0">
<dict>
...
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>kr.co.bootpaySample</string> <key>CFBundleURLSchemes</key>
<array>
<string>bootpaySample</string> </array>
</dict>
</array> </dict>
</plist>

Web

flutter web 빌드하면 web/index.html 파일이 생성됩니다. 해당 파일 header에 아래 script를 추가해주세요.

<!-- bootpay-최신버전-js 를 참조하여 추가합니다 --><scriptsrc="https://js.bootpay.co.kr/bootpay-5.3.0.min.js"></script><scriptsrc="bootpay_api.js" defer></script>

bootpay_api 파일을 프로젝트에 추가합니다.

위 설정을 완료하면 flutter web에서도 동일한 문법으로 bootpay를 사용할 수 있습니다.

iOS WebView 프리워밍 (자동)

iOS의 WKWebView는 첫 로딩 시 GPU, Networking, WebContent 프로세스 초기화로 4-6초 지연이 발생할 수 있습니다.

Bootpay Flutter SDK는 플러그인 등록 시 자동으로 프리워밍이 시작됩니다. 별도의 설정 없이도 첫 결제 화면 로딩 속도가 개선됩니다.

수동 호출 (선택사항)

특별한 타이밍에 프리워밍을 시작하고 싶다면 수동으로 호출할 수 있습니다:

import'package:bootpay/bootpay_warmup.dart';
// 기본 호출 (0.1초 딜레이)awaitBootpayWarmUp.warmUp();
// UI가 버벅이면 딜레이 증가awaitBootpayWarmUp.warmUp(delay:0.5);
// 프리워밍 상태 확인bool isReady =awaitBootpayWarmUp.checkIsWarmedUp();
// 메모리 부족 시 리소스 해제awaitBootpayWarmUp.releaseWarmUp();
API설명
BootpayWarmUp.warmUp()WebView 프로세스 미리 초기화 (자동 실행됨)
BootpayWarmUp.warmUp(delay: 0.5)커스텀 딜레이로 프리워밍
BootpayWarmUp.checkIsWarmedUp()프리워밍 완료 여부 확인
BootpayWarmUp.releaseWarmUp()프리워밍 리소스 해제

참고: Android와 Web에서는 이 기능이 no-op으로 동작합니다 (iOS/macOS 전용).

위젯 설정

부트페이 관리자에서 위젯을 생성하셔야만 사용이 가능합니다.

위젯 렌더링

Payload _payload =Payload();
BootpayWidgetController _controller =BootpayWidgetController();
@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
_payload.orderName ='5월 수강료';
_payload.orderId =DateTime
.now()
.millisecondsSinceEpoch
.toString();
_payload.webApplicationId = webApplicationId;
_payload.androidApplicationId = androidApplicationId;
_payload.iosApplicationId = iosApplicationId;
_payload.price =1000;
_payload.taxFree =0;
_payload.widgetKey ='default-widget';
_payload.widgetSandbox =true;
_payload.widgetUseTerms =true;
// _payload.userToken = "6667b08b04ab6d03f274d32e";
_payload.extra?.displaySuccessResult =true;
}
@overrideWidgetbuild(BuildContext context) {
returnContainer(
//하위로 위젯 정의 
child:BootpayWidget(
payload: _payload,
controller: _controller,
)
);
}

위젯 이벤트 처리

@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
// BootpayWidgetController _controller = BootpayWidgetController();//위젯 사이즈 변경 이벤트 
_controller.onWidgetResize = (height) {
print('onWidgetResize : $height');
//예제에서는 높이가 변경되면 스크롤을 내립니다.if(_widgetHeight == height) return;
if(_widgetHeight < height) {
scrollDown(height - _widgetHeight);
}
setState(() {
_widgetHeight = height;
});
};
//선택된 결제수단 변경 이벤트 
_controller.onWidgetChangePayment = (widgetData) {
print('onWidgetChangePayment22 : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//선택된 약관 변경 이벤트
_controller.onWidgetChangeAgreeTerm = (widgetData) {
print('onWidgetChangeAgreeTerm : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//위젯이 렌더링되면 호출되는 이벤트
_controller.onWidgetReady = () {
print('onWidgetReady');
};
}

위젯으로 결제하기

이 방법은 위젯을 사용하여 결제하는 방법입니다. 위젯을 사용하지 않고 결제를 요청하는 방법은 별도로 제공합니다.

// BootpayWidgetController _controller = BootpayWidgetController();
_controller.requestPayment(
context: context,
payload: _payload,
onCancel: (String data) {
print('------- onCancel 2 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onConfirm: (String data) {
print('------- onConfirm: $data');
returntrue; //결제를 승인합니다 
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onDone: (String data) {
print('------- onDone: $data');
// FlutterToast.showToast(msg: '결제가 완료되었습니다.');
},
);

결제하기

이 방법은 위젯을 사용하지 않고 결제하는 방법입니다.

//결제 정보를 초기화합니다.voidbootpayReqeustDataInit() {
Item item1 =Item();
item1.name ="미키 '마우스"; // 주문정보에 담길 상품명
item1.qty =1; // 해당 상품의 주문 수량
item1.id ="ITEM_CODE_MOUSE"; // 해당 상품의 고유 키
item1.price =500; // 상품의 가격Item item2 =Item();
item2.name ="키보드"; // 주문정보에 담길 상품명
item2.qty =1; // 해당 상품의 주문 수량
item2.id ="ITEM_CODE_KEYBOARD"; // 해당 상품의 고유 키
item2.price =500; // 상품의 가격List<Item> itemList = [item1, item2];
payload.webApplicationId = webApplicationId; // web application id
payload.androidApplicationId = androidApplicationId; // android application id
payload.iosApplicationId = iosApplicationId; // ios application id
payload.pg ='다날';
payload.method ='카드';
// payload.methods = ['카드', '휴대폰', '가상계좌', '계좌이체', '카카오페이'];
payload.orderName ="테스트 상품"; //결제할 상품명
payload.price =1000.0; //정기결제시 0 혹은 주석
payload.orderId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값
payload.items = itemList; // 상품정보 배열User user =User(); // 구매자 정보
user.id ="12341234";
user.username ="사용자 이름";
user.email ="user1234@gmail.com";
user.area ="서울";
user.phone ="010-0000-0000";
user.addr ='null';
Extra extra =Extra(); // 결제 옵션
extra.appScheme ='bootpayFlutter'; //결제 후 돌아갈 ios 앱 스키마를 설정합니다 
payload.user = user;
payload.items = itemList;
payload.extra = extra; }
voidgoBootpayPayment(BuildContext context) {
Bootpay().requestPayment(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 1 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { // checkQtyFromServer(data);returntrue;
},
// onConfirmAsync: (String data) async {// onConfirm 대신 사용하는 이벤트 처리 함수입니다. 내부에서 Future 문법을 사용할 수 있습니다.// print('------- onConfirmAsync: $data');// return true;// },
onDone: (String data) {
print('------- onDone: $data');
},
);
}

Bootpay 승인 요청

onConfirm, onConfirmAsync에서 승인 요청시 사용하는 함수입니다. 이 함수는 return false 로 리턴할 경우 사용합니다.

Bootpay().transactionConfirm();
returnfalse; 

Bootpay 창 닫기

onConfirm, onConfirmAsync등에서 진행중인 결제창을 닫을 때 사용하는 함수입니다. 서버인증으로 승인이 되었을 경우에, 클라이언트에서 창을 닫을 때 사용합니다.

Bootpay().dismiss(context);
returnfalse; 

자동결제 - 빌링키 발급 요청하기

voidgoBootpaySubscriptionUITest(BuildContext context) {
payload.subscriptionId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.pg ="키움페이";
payload.method ="카드자동"; // payload.price = 1000; 금액이 0 이상일 경우 빌링키 발급 후 결제가 진행됩니다.
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값Bootpay().requestSubscription(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 3: $data');
},
onError: (String data) {
print('------- onError 3: $data');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
//TODO - 원하시는 라우터로 페이지 이동
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);
}

본인인증

payload.pg ="다날";
payload.method ="본인인증";
payload.authenticationId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.extra =Extra();
payload.extra?.openType ='iframe';
payload.items =null;
Bootpay().requestAuthentication(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel: $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);

결제 진행 상태에 따라 LifeCycle 함수가 실행됩니다. 각 함수에 대한 상세 설명은 아래를 참고하세요.

onError 함수

결제 진행 중 오류가 발생된 경우 호출되는 함수입니다. 진행중 에러가 발생되는 경우는 다음과 같습니다.

  1. 부트페이 관리자에서 활성화 하지 않은 PG, 결제수단을 사용하고자 할 때
  2. PG에서 보내온 결제 정보를 부트페이 관리자에 잘못 입력하거나 입력하지 않은 경우
  3. 결제 진행 도중 한도초과, 카드정지, 휴대폰소액결제 막힘, 계좌이체 불가 등의 사유로 결제가 안되는 경우
  4. PG에서 리턴된 값이 다른 Client에 의해 변조된 경우

에러가 난 경우 해당 함수를 통해 관련 에러 메세지를 사용자에게 보여줄 수 있습니다.

data 포맷은 아래와 같습니다.

{
action: "BootpayError",
message: "카드사 거절",
receipt_id: "5fffab350c20b903e88a2cff"
}

onCancel 함수

결제 진행 중 사용자가 PG 결제창에서 취소 혹은 닫기 버튼을 눌러 나온 경우 입니다. ****

data 포맷은 아래와 같습니다.

{
action: "BootpayCancel",
message: "사용자가 결제를 취소하였습니다.",
receipt_id: "5fffab350c20b903e88a2cff"
}

onIssued 함수

가상계좌 발급이 완료되면 호출되는 함수입니다(가상계좌를 위한 Done). 가상계좌는 다른 결제와 다르게 입금할 계좌 번호 발급 이후 입금 후에 Feedback URL을 통해 통지가 됩니다. 발급된 가상계좌 정보를 issued 함수를 통해 확인하실 수 있습니다.

data 포맷은 아래와 같습니다.

{
account: "T0309260001169"
accounthodler: "한국사이버결제"
action: "BootpayBankReady"
bankcode: "BK03"
bankname: "기업은행"
expiredate: "2021-01-17 00:00:00"
item_name: "테스트 아이템"
method: "vbank"
method_name: "가상계좌"
order_id: "1610591554856"
metadata: null
payment_group: "vbank"
payment_group_name: "가상계좌"
payment_name: "가상계좌"
pg: "kcp"
pg_name: "KCP"
price: 3000
purchased_at: null
ready_url: "https://dev-app.bootpay.co.kr/bank/7o044QyX7p"
receipt_id: "5fffad430c20b903e88a2d17"
requested_at: "2021-01-14 11:32:35"
status: 2
tax_free: 0
url: "https://d-cdn.bootapi.com"
username: "홍길동"
}

onConfirm 함수

결제 승인이 되기 전 호출되는 함수입니다. 승인 이전 관련 로직을 서버 혹은 클라이언트에서 수행 후 결제를 승인해도 될 경우BootPay.transactionConfirm(data); 또는 return true;

코드를 실행해주시면 PG에서 결제 승인이 진행이 됩니다.

* 페이앱, 페이레터 PG는 이 함수가 실행되지 않고 바로 결제가 승인되는 PG 입니다. 참고해주시기 바랍니다.

data 포맷은 아래와 같습니다.

{
receipt_id: "5fffc0460c20b903e88a2d2c",
action: "BootpayConfirm"
}

onDone 함수

PG에서 거래 승인 이후에 호출 되는 함수입니다. 결제 완료 후 다음 결제 결과를 호출 할 수 있는 함수 입니다.

이 함수가 호출 된 후 반드시 REST API를 통해 결제검증을 수행해증야합니다. data 포맷은 아래와 같습니다.

{
action: "BootpayDone"
card_code: "CCKM",
card_name: "KB국민카드",
card_no: "0000120000000014",
card_quota: "00",
item_name: "테스트 아이템",
method: "card",
method_name: "카드결제",
order_id: "1610596422328",
payment_group: "card",
payment_group_name: "신용카드",
payment_name: "카드결제",
pg: "kcp",
pg_name: "KCP",
price: 100,
purchased_at: "2021-01-14 12:54:53",
receipt_id: "5fffc0460c20b903e88a2d2c",
receipt_url: "https://app.bootpay.co.kr/bill/UFMvZzJqSWNDNU9ERWh1YmUycU9hdnBkV29DVlJqdzUxRzZyNXRXbkNVZW81%0AQT09LS1XYlNJN1VoMDI4Q1hRdDh1LS10MEtZVmE4c1dyWHNHTXpZTVVLUk1R%0APT0%3D%0A",
requested_at: "2021-01-14 12:53:42",
status: 1,
tax_free: 0,
url: "https://d-cdn.bootapi.com"
}

WebView 프리워밍 (iOS/macOS)

iOS에서 WKWebView는 처음 로딩 시 GPU, Networking, WebContent 프로세스를 생성하는데 3-7초가 소요됩니다. Bootpay SDK는 자동으로 앱 시작 시 백그라운드에서 프로세스를 미리 생성하여 첫 결제 화면 로딩 속도를 개선합니다.

자동 프리워밍

SDK 초기화 시(첫 번째 Bootpay() 호출 시) 자동으로 프리워밍이 수행됩니다. 개발자가 별도로 호출할 필요가 없습니다.

메모리 관리 (선택사항)

메모리 부족 시 프리워밍된 리소스를 해제할 수 있습니다:

// 메모리 경고 수신 시 (선택사항)Bootpay.releaseWarmUp();

iOS AppDelegate에서 메모리 경고 시 자동 해제하도록 설정할 수도 있습니다:

// AppDelegate.swift
import bootpay_webview_flutter_wkwebview
overridefunc applicationDidReceiveMemoryWarning(_ application:UIApplication){
super.applicationDidReceiveMemoryWarning(application)BootpayWarmUpManager.shared.releaseWarmUp()}

효과

항목개선 효과
GPU 프로세스 초기화1-2초 단축
Networking 프로세스 초기화1-2초 단축
WebContent 프로세스 초기화1-3초 단축
총 개선 효과3-7초 단축

참고사항

  • iOS/macOS에서만 동작합니다. Android와 Web에서는 자동으로 무시됩니다.
  • 프리워밍은 자동으로 수행되므로 별도 설정이 필요 없습니다.
  • 두 번째 결제부터는 ProcessPool 공유로 자동으로 빠릅니다.

팝업 닫기(✕) 버튼 (iOS/Android)

결제창 안에서 window.open 또는 target="_blank" 로 열리는 팝업(주로 광고)은 앱 안에서 그대로 표시됩니다. 이런 팝업은 우측 상단에 뜨는 반투명 ✕ 버튼으로 사용자가 직접 닫을 수 있습니다.

광고는 차단되지 않습니다. 광고는 항상 인앱에 그대로 노출되며, 아래 설정은 "✕ 버튼을 언제 보여줄지"와 "팝업을 코드로 닫는 방법"만 제어합니다. 결제 PG 팝업은 window.close() 로 스스로 닫히므로 기본적으로 ✕ 가 붙지 않습니다.

import 'package:bootpay/bootpay.dart'; 후 아래 정적 메서드를 사용합니다.

✕ 버튼 노출 모드 설정

// 기본값(auto): 광고 도메인으로 분류된 팝업에만 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.auto);
// 모든 팝업에 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.always);
// ✕ 를 절대 노출하지 않음 (window.close 또는 closePopupWebView 로만 닫기)Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.never);
모드동작
BootpayPopupCloseButtonMode.auto기본값. 광고 도메인(addPopupAdHosts 목록)으로 분류된 팝업에만 ✕ 노출
BootpayPopupCloseButtonMode.always모든 팝업에 ✕ 노출
BootpayPopupCloseButtonMode.never✕ 를 노출하지 않음

광고 도메인 추가 (auto 모드용)

auto 모드에서 ✕ 를 띄울 광고 도메인을 런타임에 추가합니다. SDK 는 doubleclick.net / googleadservices.com / googlesyndication.com 등 주요 광고 네트워크 도메인을 기본 내장하고 있으며, 그 외 도메인을 더 넣고 싶을 때 사용합니다.

// host 의 부분 문자열로 대소문자 구분 없이 매칭됩니다.Bootpay.addPopupAdHosts(['ads.example.com', 'partner-ad.net']);

팝업을 코드로 닫기

광고 SDK 의 "광고 종료" 이벤트 등을 받았을 때, 사용자가 ✕ 를 누르지 않아도 현재 떠 있는 팝업을 닫을 수 있습니다. 메인 결제 WebView 에는 영향이 없으며, 열린 팝업이 없으면 아무 동작도 하지 않습니다.

Bootpay.closePopupWebView();
API설명
Bootpay.setPopupCloseButtonMode(mode)✕ 버튼 노출 모드 설정 (auto/always/never)
Bootpay.addPopupAdHosts(List<String> hosts)auto 모드에서 ✕ 를 띄울 광고 도메인 추가
Bootpay.closePopupWebView()현재 떠 있는 팝업을 프로그래매틱하게 닫기

참고: iOS / Android 전용입니다. Web 에서는 모두 no-op 으로 동작합니다.

Documentation

부트페이 개발매뉴얼을 참조해주세요

기술문의

채팅으로 문의

License

MIT License.

About

2세대 flutter api

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

bootpay 플러터 라이브러리

부트페이에서 지원하는 공식 Flutter 라이브러리 입니다

  • Android, iOS, Web 을 지원합니다.
  • Android SDK 16, iOS OS 13 부터 사용 가능합니다.

Bootpay 버전안내

이 모듈의 4.0.0 이상 버전부터는 Bootpay V2 이며, 그 이하 버전은 Bootpay V1에 해당합니다.

Bootpay V1, V2에 대한 특이점은 개발매뉴얼을 참고해주세요.

기능

  1. web/ios/android 지원
  2. 국내 주요 PG사 지원
  3. 주요 결제수단 지원
  4. 카드/계좌 자동결제 지원
  5. 위젯 지원
  6. 본인인증 지원

설치하기

pubspec.yaml 파일에 아래 모듈을 추가해주세요

...
dependencies:
...bootpay: last_version
...

설정하기

Android

따로 설정하실 것이 없습니다.

iOS

{your project root}/ios/Runner/Info.plist

CFBundleURLNameCFBundleURLSchemes의 값은 개발사에서 고유값으로 지정해주셔야 합니다. 외부앱(카드사앱)에서 다시 기존 앱으로 돌아올 때 필요한 스키마 값입니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPEplist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plistversion="1.0">
<dict>
...
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>kr.co.bootpaySample</string> <key>CFBundleURLSchemes</key>
<array>
<string>bootpaySample</string> </array>
</dict>
</array> </dict>
</plist>

Web

flutter web 빌드하면 web/index.html 파일이 생성됩니다. 해당 파일 header에 아래 script를 추가해주세요.

<!-- bootpay-최신버전-js 를 참조하여 추가합니다 --><scriptsrc="https://js.bootpay.co.kr/bootpay-5.3.0.min.js"></script><scriptsrc="bootpay_api.js" defer></script>

bootpay_api 파일을 프로젝트에 추가합니다.

위 설정을 완료하면 flutter web에서도 동일한 문법으로 bootpay를 사용할 수 있습니다.

iOS WebView 프리워밍 (자동)

iOS의 WKWebView는 첫 로딩 시 GPU, Networking, WebContent 프로세스 초기화로 4-6초 지연이 발생할 수 있습니다.

Bootpay Flutter SDK는 플러그인 등록 시 자동으로 프리워밍이 시작됩니다. 별도의 설정 없이도 첫 결제 화면 로딩 속도가 개선됩니다.

수동 호출 (선택사항)

특별한 타이밍에 프리워밍을 시작하고 싶다면 수동으로 호출할 수 있습니다:

import'package:bootpay/bootpay_warmup.dart';
// 기본 호출 (0.1초 딜레이)awaitBootpayWarmUp.warmUp();
// UI가 버벅이면 딜레이 증가awaitBootpayWarmUp.warmUp(delay:0.5);
// 프리워밍 상태 확인bool isReady =awaitBootpayWarmUp.checkIsWarmedUp();
// 메모리 부족 시 리소스 해제awaitBootpayWarmUp.releaseWarmUp();
API설명
BootpayWarmUp.warmUp()WebView 프로세스 미리 초기화 (자동 실행됨)
BootpayWarmUp.warmUp(delay: 0.5)커스텀 딜레이로 프리워밍
BootpayWarmUp.checkIsWarmedUp()프리워밍 완료 여부 확인
BootpayWarmUp.releaseWarmUp()프리워밍 리소스 해제

참고: Android와 Web에서는 이 기능이 no-op으로 동작합니다 (iOS/macOS 전용).

위젯 설정

부트페이 관리자에서 위젯을 생성하셔야만 사용이 가능합니다.

위젯 렌더링

Payload _payload =Payload();
BootpayWidgetController _controller =BootpayWidgetController();
@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
_payload.orderName ='5월 수강료';
_payload.orderId =DateTime
.now()
.millisecondsSinceEpoch
.toString();
_payload.webApplicationId = webApplicationId;
_payload.androidApplicationId = androidApplicationId;
_payload.iosApplicationId = iosApplicationId;
_payload.price =1000;
_payload.taxFree =0;
_payload.widgetKey ='default-widget';
_payload.widgetSandbox =true;
_payload.widgetUseTerms =true;
// _payload.userToken = "6667b08b04ab6d03f274d32e";
_payload.extra?.displaySuccessResult =true;
}
@overrideWidgetbuild(BuildContext context) {
returnContainer(
//하위로 위젯 정의 
child:BootpayWidget(
payload: _payload,
controller: _controller,
)
);
}

위젯 이벤트 처리

@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
// BootpayWidgetController _controller = BootpayWidgetController();//위젯 사이즈 변경 이벤트 
_controller.onWidgetResize = (height) {
print('onWidgetResize : $height');
//예제에서는 높이가 변경되면 스크롤을 내립니다.if(_widgetHeight == height) return;
if(_widgetHeight < height) {
scrollDown(height - _widgetHeight);
}
setState(() {
_widgetHeight = height;
});
};
//선택된 결제수단 변경 이벤트 
_controller.onWidgetChangePayment = (widgetData) {
print('onWidgetChangePayment22 : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//선택된 약관 변경 이벤트
_controller.onWidgetChangeAgreeTerm = (widgetData) {
print('onWidgetChangeAgreeTerm : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//위젯이 렌더링되면 호출되는 이벤트
_controller.onWidgetReady = () {
print('onWidgetReady');
};
}

위젯으로 결제하기

이 방법은 위젯을 사용하여 결제하는 방법입니다. 위젯을 사용하지 않고 결제를 요청하는 방법은 별도로 제공합니다.

// BootpayWidgetController _controller = BootpayWidgetController();
_controller.requestPayment(
context: context,
payload: _payload,
onCancel: (String data) {
print('------- onCancel 2 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onConfirm: (String data) {
print('------- onConfirm: $data');
returntrue; //결제를 승인합니다 
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onDone: (String data) {
print('------- onDone: $data');
// FlutterToast.showToast(msg: '결제가 완료되었습니다.');
},
);

결제하기

이 방법은 위젯을 사용하지 않고 결제하는 방법입니다.

//결제 정보를 초기화합니다.voidbootpayReqeustDataInit() {
Item item1 =Item();
item1.name ="미키 '마우스"; // 주문정보에 담길 상품명
item1.qty =1; // 해당 상품의 주문 수량
item1.id ="ITEM_CODE_MOUSE"; // 해당 상품의 고유 키
item1.price =500; // 상품의 가격Item item2 =Item();
item2.name ="키보드"; // 주문정보에 담길 상품명
item2.qty =1; // 해당 상품의 주문 수량
item2.id ="ITEM_CODE_KEYBOARD"; // 해당 상품의 고유 키
item2.price =500; // 상품의 가격List<Item> itemList = [item1, item2];
payload.webApplicationId = webApplicationId; // web application id
payload.androidApplicationId = androidApplicationId; // android application id
payload.iosApplicationId = iosApplicationId; // ios application id
payload.pg ='다날';
payload.method ='카드';
// payload.methods = ['카드', '휴대폰', '가상계좌', '계좌이체', '카카오페이'];
payload.orderName ="테스트 상품"; //결제할 상품명
payload.price =1000.0; //정기결제시 0 혹은 주석
payload.orderId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값
payload.items = itemList; // 상품정보 배열User user =User(); // 구매자 정보
user.id ="12341234";
user.username ="사용자 이름";
user.email ="user1234@gmail.com";
user.area ="서울";
user.phone ="010-0000-0000";
user.addr ='null';
Extra extra =Extra(); // 결제 옵션
extra.appScheme ='bootpayFlutter'; //결제 후 돌아갈 ios 앱 스키마를 설정합니다 
payload.user = user;
payload.items = itemList;
payload.extra = extra; }
voidgoBootpayPayment(BuildContext context) {
Bootpay().requestPayment(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 1 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { // checkQtyFromServer(data);returntrue;
},
// onConfirmAsync: (String data) async {// onConfirm 대신 사용하는 이벤트 처리 함수입니다. 내부에서 Future 문법을 사용할 수 있습니다.// print('------- onConfirmAsync: $data');// return true;// },
onDone: (String data) {
print('------- onDone: $data');
},
);
}

Bootpay 승인 요청

onConfirm, onConfirmAsync에서 승인 요청시 사용하는 함수입니다. 이 함수는 return false 로 리턴할 경우 사용합니다.

Bootpay().transactionConfirm();
returnfalse; 

Bootpay 창 닫기

onConfirm, onConfirmAsync등에서 진행중인 결제창을 닫을 때 사용하는 함수입니다. 서버인증으로 승인이 되었을 경우에, 클라이언트에서 창을 닫을 때 사용합니다.

Bootpay().dismiss(context);
returnfalse; 

자동결제 - 빌링키 발급 요청하기

voidgoBootpaySubscriptionUITest(BuildContext context) {
payload.subscriptionId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.pg ="키움페이";
payload.method ="카드자동"; // payload.price = 1000; 금액이 0 이상일 경우 빌링키 발급 후 결제가 진행됩니다.
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값Bootpay().requestSubscription(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 3: $data');
},
onError: (String data) {
print('------- onError 3: $data');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
//TODO - 원하시는 라우터로 페이지 이동
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);
}

본인인증

payload.pg ="다날";
payload.method ="본인인증";
payload.authenticationId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.extra =Extra();
payload.extra?.openType ='iframe';
payload.items =null;
Bootpay().requestAuthentication(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel: $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);

결제 진행 상태에 따라 LifeCycle 함수가 실행됩니다. 각 함수에 대한 상세 설명은 아래를 참고하세요.

onError 함수

결제 진행 중 오류가 발생된 경우 호출되는 함수입니다. 진행중 에러가 발생되는 경우는 다음과 같습니다.

  1. 부트페이 관리자에서 활성화 하지 않은 PG, 결제수단을 사용하고자 할 때
  2. PG에서 보내온 결제 정보를 부트페이 관리자에 잘못 입력하거나 입력하지 않은 경우
  3. 결제 진행 도중 한도초과, 카드정지, 휴대폰소액결제 막힘, 계좌이체 불가 등의 사유로 결제가 안되는 경우
  4. PG에서 리턴된 값이 다른 Client에 의해 변조된 경우

에러가 난 경우 해당 함수를 통해 관련 에러 메세지를 사용자에게 보여줄 수 있습니다.

data 포맷은 아래와 같습니다.

{
action: "BootpayError",
message: "카드사 거절",
receipt_id: "5fffab350c20b903e88a2cff"
}

onCancel 함수

결제 진행 중 사용자가 PG 결제창에서 취소 혹은 닫기 버튼을 눌러 나온 경우 입니다. ****

data 포맷은 아래와 같습니다.

{
action: "BootpayCancel",
message: "사용자가 결제를 취소하였습니다.",
receipt_id: "5fffab350c20b903e88a2cff"
}

onIssued 함수

가상계좌 발급이 완료되면 호출되는 함수입니다(가상계좌를 위한 Done). 가상계좌는 다른 결제와 다르게 입금할 계좌 번호 발급 이후 입금 후에 Feedback URL을 통해 통지가 됩니다. 발급된 가상계좌 정보를 issued 함수를 통해 확인하실 수 있습니다.

data 포맷은 아래와 같습니다.

{
account: "T0309260001169"
accounthodler: "한국사이버결제"
action: "BootpayBankReady"
bankcode: "BK03"
bankname: "기업은행"
expiredate: "2021-01-17 00:00:00"
item_name: "테스트 아이템"
method: "vbank"
method_name: "가상계좌"
order_id: "1610591554856"
metadata: null
payment_group: "vbank"
payment_group_name: "가상계좌"
payment_name: "가상계좌"
pg: "kcp"
pg_name: "KCP"
price: 3000
purchased_at: null
ready_url: "https://dev-app.bootpay.co.kr/bank/7o044QyX7p"
receipt_id: "5fffad430c20b903e88a2d17"
requested_at: "2021-01-14 11:32:35"
status: 2
tax_free: 0
url: "https://d-cdn.bootapi.com"
username: "홍길동"
}

onConfirm 함수

결제 승인이 되기 전 호출되는 함수입니다. 승인 이전 관련 로직을 서버 혹은 클라이언트에서 수행 후 결제를 승인해도 될 경우BootPay.transactionConfirm(data); 또는 return true;

코드를 실행해주시면 PG에서 결제 승인이 진행이 됩니다.

* 페이앱, 페이레터 PG는 이 함수가 실행되지 않고 바로 결제가 승인되는 PG 입니다. 참고해주시기 바랍니다.

data 포맷은 아래와 같습니다.

{
receipt_id: "5fffc0460c20b903e88a2d2c",
action: "BootpayConfirm"
}

onDone 함수

PG에서 거래 승인 이후에 호출 되는 함수입니다. 결제 완료 후 다음 결제 결과를 호출 할 수 있는 함수 입니다.

이 함수가 호출 된 후 반드시 REST API를 통해 결제검증을 수행해증야합니다. data 포맷은 아래와 같습니다.

{
action: "BootpayDone"
card_code: "CCKM",
card_name: "KB국민카드",
card_no: "0000120000000014",
card_quota: "00",
item_name: "테스트 아이템",
method: "card",
method_name: "카드결제",
order_id: "1610596422328",
payment_group: "card",
payment_group_name: "신용카드",
payment_name: "카드결제",
pg: "kcp",
pg_name: "KCP",
price: 100,
purchased_at: "2021-01-14 12:54:53",
receipt_id: "5fffc0460c20b903e88a2d2c",
receipt_url: "https://app.bootpay.co.kr/bill/UFMvZzJqSWNDNU9ERWh1YmUycU9hdnBkV29DVlJqdzUxRzZyNXRXbkNVZW81%0AQT09LS1XYlNJN1VoMDI4Q1hRdDh1LS10MEtZVmE4c1dyWHNHTXpZTVVLUk1R%0APT0%3D%0A",
requested_at: "2021-01-14 12:53:42",
status: 1,
tax_free: 0,
url: "https://d-cdn.bootapi.com"
}

WebView 프리워밍 (iOS/macOS)

iOS에서 WKWebView는 처음 로딩 시 GPU, Networking, WebContent 프로세스를 생성하는데 3-7초가 소요됩니다. Bootpay SDK는 자동으로 앱 시작 시 백그라운드에서 프로세스를 미리 생성하여 첫 결제 화면 로딩 속도를 개선합니다.

자동 프리워밍

SDK 초기화 시(첫 번째 Bootpay() 호출 시) 자동으로 프리워밍이 수행됩니다. 개발자가 별도로 호출할 필요가 없습니다.

메모리 관리 (선택사항)

메모리 부족 시 프리워밍된 리소스를 해제할 수 있습니다:

// 메모리 경고 수신 시 (선택사항)Bootpay.releaseWarmUp();

iOS AppDelegate에서 메모리 경고 시 자동 해제하도록 설정할 수도 있습니다:

// AppDelegate.swift
import bootpay_webview_flutter_wkwebview
overridefunc applicationDidReceiveMemoryWarning(_ application:UIApplication){
super.applicationDidReceiveMemoryWarning(application)BootpayWarmUpManager.shared.releaseWarmUp()}

효과

항목개선 효과
GPU 프로세스 초기화1-2초 단축
Networking 프로세스 초기화1-2초 단축
WebContent 프로세스 초기화1-3초 단축
총 개선 효과3-7초 단축

참고사항

  • iOS/macOS에서만 동작합니다. Android와 Web에서는 자동으로 무시됩니다.
  • 프리워밍은 자동으로 수행되므로 별도 설정이 필요 없습니다.
  • 두 번째 결제부터는 ProcessPool 공유로 자동으로 빠릅니다.

팝업 닫기(✕) 버튼 (iOS/Android)

결제창 안에서 window.open 또는 target="_blank" 로 열리는 팝업(주로 광고)은 앱 안에서 그대로 표시됩니다. 이런 팝업은 우측 상단에 뜨는 반투명 ✕ 버튼으로 사용자가 직접 닫을 수 있습니다.

광고는 차단되지 않습니다. 광고는 항상 인앱에 그대로 노출되며, 아래 설정은 "✕ 버튼을 언제 보여줄지"와 "팝업을 코드로 닫는 방법"만 제어합니다. 결제 PG 팝업은 window.close() 로 스스로 닫히므로 기본적으로 ✕ 가 붙지 않습니다.

import 'package:bootpay/bootpay.dart'; 후 아래 정적 메서드를 사용합니다.

✕ 버튼 노출 모드 설정

// 기본값(auto): 광고 도메인으로 분류된 팝업에만 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.auto);
// 모든 팝업에 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.always);
// ✕ 를 절대 노출하지 않음 (window.close 또는 closePopupWebView 로만 닫기)Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.never);
모드동작
BootpayPopupCloseButtonMode.auto기본값. 광고 도메인(addPopupAdHosts 목록)으로 분류된 팝업에만 ✕ 노출
BootpayPopupCloseButtonMode.always모든 팝업에 ✕ 노출
BootpayPopupCloseButtonMode.never✕ 를 노출하지 않음

광고 도메인 추가 (auto 모드용)

auto 모드에서 ✕ 를 띄울 광고 도메인을 런타임에 추가합니다. SDK 는 doubleclick.net / googleadservices.com / googlesyndication.com 등 주요 광고 네트워크 도메인을 기본 내장하고 있으며, 그 외 도메인을 더 넣고 싶을 때 사용합니다.

// host 의 부분 문자열로 대소문자 구분 없이 매칭됩니다.Bootpay.addPopupAdHosts(['ads.example.com', 'partner-ad.net']);

팝업을 코드로 닫기

광고 SDK 의 "광고 종료" 이벤트 등을 받았을 때, 사용자가 ✕ 를 누르지 않아도 현재 떠 있는 팝업을 닫을 수 있습니다. 메인 결제 WebView 에는 영향이 없으며, 열린 팝업이 없으면 아무 동작도 하지 않습니다.

Bootpay.closePopupWebView();
API설명
Bootpay.setPopupCloseButtonMode(mode)✕ 버튼 노출 모드 설정 (auto/always/never)
Bootpay.addPopupAdHosts(List<String> hosts)auto 모드에서 ✕ 를 띄울 광고 도메인 추가
Bootpay.closePopupWebView()현재 떠 있는 팝업을 프로그래매틱하게 닫기

참고: iOS / Android 전용입니다. Web 에서는 모두 no-op 으로 동작합니다.

Documentation

부트페이 개발매뉴얼을 참조해주세요

기술문의

채팅으로 문의

License

MIT License.

About

2세대 flutter api

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

bootpay 플러터 라이브러리

부트페이에서 지원하는 공식 Flutter 라이브러리 입니다

  • Android, iOS, Web 을 지원합니다.
  • Android SDK 16, iOS OS 13 부터 사용 가능합니다.

Bootpay 버전안내

이 모듈의 4.0.0 이상 버전부터는 Bootpay V2 이며, 그 이하 버전은 Bootpay V1에 해당합니다.

Bootpay V1, V2에 대한 특이점은 개발매뉴얼을 참고해주세요.

기능

  1. web/ios/android 지원
  2. 국내 주요 PG사 지원
  3. 주요 결제수단 지원
  4. 카드/계좌 자동결제 지원
  5. 위젯 지원
  6. 본인인증 지원

설치하기

pubspec.yaml 파일에 아래 모듈을 추가해주세요

...
dependencies:
...bootpay: last_version
...

설정하기

Android

따로 설정하실 것이 없습니다.

iOS

{your project root}/ios/Runner/Info.plist

CFBundleURLNameCFBundleURLSchemes의 값은 개발사에서 고유값으로 지정해주셔야 합니다. 외부앱(카드사앱)에서 다시 기존 앱으로 돌아올 때 필요한 스키마 값입니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPEplist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plistversion="1.0">
<dict>
...
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>kr.co.bootpaySample</string> <key>CFBundleURLSchemes</key>
<array>
<string>bootpaySample</string> </array>
</dict>
</array> </dict>
</plist>

Web

flutter web 빌드하면 web/index.html 파일이 생성됩니다. 해당 파일 header에 아래 script를 추가해주세요.

<!-- bootpay-최신버전-js 를 참조하여 추가합니다 --><scriptsrc="https://js.bootpay.co.kr/bootpay-5.3.0.min.js"></script><scriptsrc="bootpay_api.js" defer></script>

bootpay_api 파일을 프로젝트에 추가합니다.

위 설정을 완료하면 flutter web에서도 동일한 문법으로 bootpay를 사용할 수 있습니다.

iOS WebView 프리워밍 (자동)

iOS의 WKWebView는 첫 로딩 시 GPU, Networking, WebContent 프로세스 초기화로 4-6초 지연이 발생할 수 있습니다.

Bootpay Flutter SDK는 플러그인 등록 시 자동으로 프리워밍이 시작됩니다. 별도의 설정 없이도 첫 결제 화면 로딩 속도가 개선됩니다.

수동 호출 (선택사항)

특별한 타이밍에 프리워밍을 시작하고 싶다면 수동으로 호출할 수 있습니다:

import'package:bootpay/bootpay_warmup.dart';
// 기본 호출 (0.1초 딜레이)awaitBootpayWarmUp.warmUp();
// UI가 버벅이면 딜레이 증가awaitBootpayWarmUp.warmUp(delay:0.5);
// 프리워밍 상태 확인bool isReady =awaitBootpayWarmUp.checkIsWarmedUp();
// 메모리 부족 시 리소스 해제awaitBootpayWarmUp.releaseWarmUp();
API설명
BootpayWarmUp.warmUp()WebView 프로세스 미리 초기화 (자동 실행됨)
BootpayWarmUp.warmUp(delay: 0.5)커스텀 딜레이로 프리워밍
BootpayWarmUp.checkIsWarmedUp()프리워밍 완료 여부 확인
BootpayWarmUp.releaseWarmUp()프리워밍 리소스 해제

참고: Android와 Web에서는 이 기능이 no-op으로 동작합니다 (iOS/macOS 전용).

위젯 설정

부트페이 관리자에서 위젯을 생성하셔야만 사용이 가능합니다.

위젯 렌더링

Payload _payload =Payload();
BootpayWidgetController _controller =BootpayWidgetController();
@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
_payload.orderName ='5월 수강료';
_payload.orderId =DateTime
.now()
.millisecondsSinceEpoch
.toString();
_payload.webApplicationId = webApplicationId;
_payload.androidApplicationId = androidApplicationId;
_payload.iosApplicationId = iosApplicationId;
_payload.price =1000;
_payload.taxFree =0;
_payload.widgetKey ='default-widget';
_payload.widgetSandbox =true;
_payload.widgetUseTerms =true;
// _payload.userToken = "6667b08b04ab6d03f274d32e";
_payload.extra?.displaySuccessResult =true;
}
@overrideWidgetbuild(BuildContext context) {
returnContainer(
//하위로 위젯 정의 
child:BootpayWidget(
payload: _payload,
controller: _controller,
)
);
}

위젯 이벤트 처리

@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
// BootpayWidgetController _controller = BootpayWidgetController();//위젯 사이즈 변경 이벤트 
_controller.onWidgetResize = (height) {
print('onWidgetResize : $height');
//예제에서는 높이가 변경되면 스크롤을 내립니다.if(_widgetHeight == height) return;
if(_widgetHeight < height) {
scrollDown(height - _widgetHeight);
}
setState(() {
_widgetHeight = height;
});
};
//선택된 결제수단 변경 이벤트 
_controller.onWidgetChangePayment = (widgetData) {
print('onWidgetChangePayment22 : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//선택된 약관 변경 이벤트
_controller.onWidgetChangeAgreeTerm = (widgetData) {
print('onWidgetChangeAgreeTerm : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//위젯이 렌더링되면 호출되는 이벤트
_controller.onWidgetReady = () {
print('onWidgetReady');
};
}

위젯으로 결제하기

이 방법은 위젯을 사용하여 결제하는 방법입니다. 위젯을 사용하지 않고 결제를 요청하는 방법은 별도로 제공합니다.

// BootpayWidgetController _controller = BootpayWidgetController();
_controller.requestPayment(
context: context,
payload: _payload,
onCancel: (String data) {
print('------- onCancel 2 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onConfirm: (String data) {
print('------- onConfirm: $data');
returntrue; //결제를 승인합니다 
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onDone: (String data) {
print('------- onDone: $data');
// FlutterToast.showToast(msg: '결제가 완료되었습니다.');
},
);

결제하기

이 방법은 위젯을 사용하지 않고 결제하는 방법입니다.

//결제 정보를 초기화합니다.voidbootpayReqeustDataInit() {
Item item1 =Item();
item1.name ="미키 '마우스"; // 주문정보에 담길 상품명
item1.qty =1; // 해당 상품의 주문 수량
item1.id ="ITEM_CODE_MOUSE"; // 해당 상품의 고유 키
item1.price =500; // 상품의 가격Item item2 =Item();
item2.name ="키보드"; // 주문정보에 담길 상품명
item2.qty =1; // 해당 상품의 주문 수량
item2.id ="ITEM_CODE_KEYBOARD"; // 해당 상품의 고유 키
item2.price =500; // 상품의 가격List<Item> itemList = [item1, item2];
payload.webApplicationId = webApplicationId; // web application id
payload.androidApplicationId = androidApplicationId; // android application id
payload.iosApplicationId = iosApplicationId; // ios application id
payload.pg ='다날';
payload.method ='카드';
// payload.methods = ['카드', '휴대폰', '가상계좌', '계좌이체', '카카오페이'];
payload.orderName ="테스트 상품"; //결제할 상품명
payload.price =1000.0; //정기결제시 0 혹은 주석
payload.orderId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값
payload.items = itemList; // 상품정보 배열User user =User(); // 구매자 정보
user.id ="12341234";
user.username ="사용자 이름";
user.email ="user1234@gmail.com";
user.area ="서울";
user.phone ="010-0000-0000";
user.addr ='null';
Extra extra =Extra(); // 결제 옵션
extra.appScheme ='bootpayFlutter'; //결제 후 돌아갈 ios 앱 스키마를 설정합니다 
payload.user = user;
payload.items = itemList;
payload.extra = extra; }
voidgoBootpayPayment(BuildContext context) {
Bootpay().requestPayment(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 1 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { // checkQtyFromServer(data);returntrue;
},
// onConfirmAsync: (String data) async {// onConfirm 대신 사용하는 이벤트 처리 함수입니다. 내부에서 Future 문법을 사용할 수 있습니다.// print('------- onConfirmAsync: $data');// return true;// },
onDone: (String data) {
print('------- onDone: $data');
},
);
}

Bootpay 승인 요청

onConfirm, onConfirmAsync에서 승인 요청시 사용하는 함수입니다. 이 함수는 return false 로 리턴할 경우 사용합니다.

Bootpay().transactionConfirm();
returnfalse; 

Bootpay 창 닫기

onConfirm, onConfirmAsync등에서 진행중인 결제창을 닫을 때 사용하는 함수입니다. 서버인증으로 승인이 되었을 경우에, 클라이언트에서 창을 닫을 때 사용합니다.

Bootpay().dismiss(context);
returnfalse; 

자동결제 - 빌링키 발급 요청하기

voidgoBootpaySubscriptionUITest(BuildContext context) {
payload.subscriptionId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.pg ="키움페이";
payload.method ="카드자동"; // payload.price = 1000; 금액이 0 이상일 경우 빌링키 발급 후 결제가 진행됩니다.
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값Bootpay().requestSubscription(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 3: $data');
},
onError: (String data) {
print('------- onError 3: $data');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
//TODO - 원하시는 라우터로 페이지 이동
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);
}

본인인증

payload.pg ="다날";
payload.method ="본인인증";
payload.authenticationId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.extra =Extra();
payload.extra?.openType ='iframe';
payload.items =null;
Bootpay().requestAuthentication(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel: $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);

결제 진행 상태에 따라 LifeCycle 함수가 실행됩니다. 각 함수에 대한 상세 설명은 아래를 참고하세요.

onError 함수

결제 진행 중 오류가 발생된 경우 호출되는 함수입니다. 진행중 에러가 발생되는 경우는 다음과 같습니다.

  1. 부트페이 관리자에서 활성화 하지 않은 PG, 결제수단을 사용하고자 할 때
  2. PG에서 보내온 결제 정보를 부트페이 관리자에 잘못 입력하거나 입력하지 않은 경우
  3. 결제 진행 도중 한도초과, 카드정지, 휴대폰소액결제 막힘, 계좌이체 불가 등의 사유로 결제가 안되는 경우
  4. PG에서 리턴된 값이 다른 Client에 의해 변조된 경우

에러가 난 경우 해당 함수를 통해 관련 에러 메세지를 사용자에게 보여줄 수 있습니다.

data 포맷은 아래와 같습니다.

{
action: "BootpayError",
message: "카드사 거절",
receipt_id: "5fffab350c20b903e88a2cff"
}

onCancel 함수

결제 진행 중 사용자가 PG 결제창에서 취소 혹은 닫기 버튼을 눌러 나온 경우 입니다. ****

data 포맷은 아래와 같습니다.

{
action: "BootpayCancel",
message: "사용자가 결제를 취소하였습니다.",
receipt_id: "5fffab350c20b903e88a2cff"
}

onIssued 함수

가상계좌 발급이 완료되면 호출되는 함수입니다(가상계좌를 위한 Done). 가상계좌는 다른 결제와 다르게 입금할 계좌 번호 발급 이후 입금 후에 Feedback URL을 통해 통지가 됩니다. 발급된 가상계좌 정보를 issued 함수를 통해 확인하실 수 있습니다.

data 포맷은 아래와 같습니다.

{
account: "T0309260001169"
accounthodler: "한국사이버결제"
action: "BootpayBankReady"
bankcode: "BK03"
bankname: "기업은행"
expiredate: "2021-01-17 00:00:00"
item_name: "테스트 아이템"
method: "vbank"
method_name: "가상계좌"
order_id: "1610591554856"
metadata: null
payment_group: "vbank"
payment_group_name: "가상계좌"
payment_name: "가상계좌"
pg: "kcp"
pg_name: "KCP"
price: 3000
purchased_at: null
ready_url: "https://dev-app.bootpay.co.kr/bank/7o044QyX7p"
receipt_id: "5fffad430c20b903e88a2d17"
requested_at: "2021-01-14 11:32:35"
status: 2
tax_free: 0
url: "https://d-cdn.bootapi.com"
username: "홍길동"
}

onConfirm 함수

결제 승인이 되기 전 호출되는 함수입니다. 승인 이전 관련 로직을 서버 혹은 클라이언트에서 수행 후 결제를 승인해도 될 경우BootPay.transactionConfirm(data); 또는 return true;

코드를 실행해주시면 PG에서 결제 승인이 진행이 됩니다.

* 페이앱, 페이레터 PG는 이 함수가 실행되지 않고 바로 결제가 승인되는 PG 입니다. 참고해주시기 바랍니다.

data 포맷은 아래와 같습니다.

{
receipt_id: "5fffc0460c20b903e88a2d2c",
action: "BootpayConfirm"
}

onDone 함수

PG에서 거래 승인 이후에 호출 되는 함수입니다. 결제 완료 후 다음 결제 결과를 호출 할 수 있는 함수 입니다.

이 함수가 호출 된 후 반드시 REST API를 통해 결제검증을 수행해증야합니다. data 포맷은 아래와 같습니다.

{
action: "BootpayDone"
card_code: "CCKM",
card_name: "KB국민카드",
card_no: "0000120000000014",
card_quota: "00",
item_name: "테스트 아이템",
method: "card",
method_name: "카드결제",
order_id: "1610596422328",
payment_group: "card",
payment_group_name: "신용카드",
payment_name: "카드결제",
pg: "kcp",
pg_name: "KCP",
price: 100,
purchased_at: "2021-01-14 12:54:53",
receipt_id: "5fffc0460c20b903e88a2d2c",
receipt_url: "https://app.bootpay.co.kr/bill/UFMvZzJqSWNDNU9ERWh1YmUycU9hdnBkV29DVlJqdzUxRzZyNXRXbkNVZW81%0AQT09LS1XYlNJN1VoMDI4Q1hRdDh1LS10MEtZVmE4c1dyWHNHTXpZTVVLUk1R%0APT0%3D%0A",
requested_at: "2021-01-14 12:53:42",
status: 1,
tax_free: 0,
url: "https://d-cdn.bootapi.com"
}

WebView 프리워밍 (iOS/macOS)

iOS에서 WKWebView는 처음 로딩 시 GPU, Networking, WebContent 프로세스를 생성하는데 3-7초가 소요됩니다. Bootpay SDK는 자동으로 앱 시작 시 백그라운드에서 프로세스를 미리 생성하여 첫 결제 화면 로딩 속도를 개선합니다.

자동 프리워밍

SDK 초기화 시(첫 번째 Bootpay() 호출 시) 자동으로 프리워밍이 수행됩니다. 개발자가 별도로 호출할 필요가 없습니다.

메모리 관리 (선택사항)

메모리 부족 시 프리워밍된 리소스를 해제할 수 있습니다:

// 메모리 경고 수신 시 (선택사항)Bootpay.releaseWarmUp();

iOS AppDelegate에서 메모리 경고 시 자동 해제하도록 설정할 수도 있습니다:

// AppDelegate.swift
import bootpay_webview_flutter_wkwebview
overridefunc applicationDidReceiveMemoryWarning(_ application:UIApplication){
super.applicationDidReceiveMemoryWarning(application)BootpayWarmUpManager.shared.releaseWarmUp()}

효과

항목개선 효과
GPU 프로세스 초기화1-2초 단축
Networking 프로세스 초기화1-2초 단축
WebContent 프로세스 초기화1-3초 단축
총 개선 효과3-7초 단축

참고사항

  • iOS/macOS에서만 동작합니다. Android와 Web에서는 자동으로 무시됩니다.
  • 프리워밍은 자동으로 수행되므로 별도 설정이 필요 없습니다.
  • 두 번째 결제부터는 ProcessPool 공유로 자동으로 빠릅니다.

팝업 닫기(✕) 버튼 (iOS/Android)

결제창 안에서 window.open 또는 target="_blank" 로 열리는 팝업(주로 광고)은 앱 안에서 그대로 표시됩니다. 이런 팝업은 우측 상단에 뜨는 반투명 ✕ 버튼으로 사용자가 직접 닫을 수 있습니다.

광고는 차단되지 않습니다. 광고는 항상 인앱에 그대로 노출되며, 아래 설정은 "✕ 버튼을 언제 보여줄지"와 "팝업을 코드로 닫는 방법"만 제어합니다. 결제 PG 팝업은 window.close() 로 스스로 닫히므로 기본적으로 ✕ 가 붙지 않습니다.

import 'package:bootpay/bootpay.dart'; 후 아래 정적 메서드를 사용합니다.

✕ 버튼 노출 모드 설정

// 기본값(auto): 광고 도메인으로 분류된 팝업에만 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.auto);
// 모든 팝업에 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.always);
// ✕ 를 절대 노출하지 않음 (window.close 또는 closePopupWebView 로만 닫기)Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.never);
모드동작
BootpayPopupCloseButtonMode.auto기본값. 광고 도메인(addPopupAdHosts 목록)으로 분류된 팝업에만 ✕ 노출
BootpayPopupCloseButtonMode.always모든 팝업에 ✕ 노출
BootpayPopupCloseButtonMode.never✕ 를 노출하지 않음

광고 도메인 추가 (auto 모드용)

auto 모드에서 ✕ 를 띄울 광고 도메인을 런타임에 추가합니다. SDK 는 doubleclick.net / googleadservices.com / googlesyndication.com 등 주요 광고 네트워크 도메인을 기본 내장하고 있으며, 그 외 도메인을 더 넣고 싶을 때 사용합니다.

// host 의 부분 문자열로 대소문자 구분 없이 매칭됩니다.Bootpay.addPopupAdHosts(['ads.example.com', 'partner-ad.net']);

팝업을 코드로 닫기

광고 SDK 의 "광고 종료" 이벤트 등을 받았을 때, 사용자가 ✕ 를 누르지 않아도 현재 떠 있는 팝업을 닫을 수 있습니다. 메인 결제 WebView 에는 영향이 없으며, 열린 팝업이 없으면 아무 동작도 하지 않습니다.

Bootpay.closePopupWebView();
API설명
Bootpay.setPopupCloseButtonMode(mode)✕ 버튼 노출 모드 설정 (auto/always/never)
Bootpay.addPopupAdHosts(List<String> hosts)auto 모드에서 ✕ 를 띄울 광고 도메인 추가
Bootpay.closePopupWebView()현재 떠 있는 팝업을 프로그래매틱하게 닫기

참고: iOS / Android 전용입니다. Web 에서는 모두 no-op 으로 동작합니다.

Documentation

부트페이 개발매뉴얼을 참조해주세요

기술문의

채팅으로 문의

License

MIT License.

About

2세대 flutter api

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

bootpay 플러터 라이브러리

부트페이에서 지원하는 공식 Flutter 라이브러리 입니다

  • Android, iOS, Web 을 지원합니다.
  • Android SDK 16, iOS OS 13 부터 사용 가능합니다.

Bootpay 버전안내

이 모듈의 4.0.0 이상 버전부터는 Bootpay V2 이며, 그 이하 버전은 Bootpay V1에 해당합니다.

Bootpay V1, V2에 대한 특이점은 개발매뉴얼을 참고해주세요.

기능

  1. web/ios/android 지원
  2. 국내 주요 PG사 지원
  3. 주요 결제수단 지원
  4. 카드/계좌 자동결제 지원
  5. 위젯 지원
  6. 본인인증 지원

설치하기

pubspec.yaml 파일에 아래 모듈을 추가해주세요

...
dependencies:
...bootpay: last_version
...

설정하기

Android

따로 설정하실 것이 없습니다.

iOS

{your project root}/ios/Runner/Info.plist

CFBundleURLNameCFBundleURLSchemes의 값은 개발사에서 고유값으로 지정해주셔야 합니다. 외부앱(카드사앱)에서 다시 기존 앱으로 돌아올 때 필요한 스키마 값입니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPEplist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plistversion="1.0">
<dict>
...
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>kr.co.bootpaySample</string> <key>CFBundleURLSchemes</key>
<array>
<string>bootpaySample</string> </array>
</dict>
</array> </dict>
</plist>

Web

flutter web 빌드하면 web/index.html 파일이 생성됩니다. 해당 파일 header에 아래 script를 추가해주세요.

<!-- bootpay-최신버전-js 를 참조하여 추가합니다 --><scriptsrc="https://js.bootpay.co.kr/bootpay-5.3.0.min.js"></script><scriptsrc="bootpay_api.js" defer></script>

bootpay_api 파일을 프로젝트에 추가합니다.

위 설정을 완료하면 flutter web에서도 동일한 문법으로 bootpay를 사용할 수 있습니다.

iOS WebView 프리워밍 (자동)

iOS의 WKWebView는 첫 로딩 시 GPU, Networking, WebContent 프로세스 초기화로 4-6초 지연이 발생할 수 있습니다.

Bootpay Flutter SDK는 플러그인 등록 시 자동으로 프리워밍이 시작됩니다. 별도의 설정 없이도 첫 결제 화면 로딩 속도가 개선됩니다.

수동 호출 (선택사항)

특별한 타이밍에 프리워밍을 시작하고 싶다면 수동으로 호출할 수 있습니다:

import'package:bootpay/bootpay_warmup.dart';
// 기본 호출 (0.1초 딜레이)awaitBootpayWarmUp.warmUp();
// UI가 버벅이면 딜레이 증가awaitBootpayWarmUp.warmUp(delay:0.5);
// 프리워밍 상태 확인bool isReady =awaitBootpayWarmUp.checkIsWarmedUp();
// 메모리 부족 시 리소스 해제awaitBootpayWarmUp.releaseWarmUp();
API설명
BootpayWarmUp.warmUp()WebView 프로세스 미리 초기화 (자동 실행됨)
BootpayWarmUp.warmUp(delay: 0.5)커스텀 딜레이로 프리워밍
BootpayWarmUp.checkIsWarmedUp()프리워밍 완료 여부 확인
BootpayWarmUp.releaseWarmUp()프리워밍 리소스 해제

참고: Android와 Web에서는 이 기능이 no-op으로 동작합니다 (iOS/macOS 전용).

위젯 설정

부트페이 관리자에서 위젯을 생성하셔야만 사용이 가능합니다.

위젯 렌더링

Payload _payload =Payload();
BootpayWidgetController _controller =BootpayWidgetController();
@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
_payload.orderName ='5월 수강료';
_payload.orderId =DateTime
.now()
.millisecondsSinceEpoch
.toString();
_payload.webApplicationId = webApplicationId;
_payload.androidApplicationId = androidApplicationId;
_payload.iosApplicationId = iosApplicationId;
_payload.price =1000;
_payload.taxFree =0;
_payload.widgetKey ='default-widget';
_payload.widgetSandbox =true;
_payload.widgetUseTerms =true;
// _payload.userToken = "6667b08b04ab6d03f274d32e";
_payload.extra?.displaySuccessResult =true;
}
@overrideWidgetbuild(BuildContext context) {
returnContainer(
//하위로 위젯 정의 
child:BootpayWidget(
payload: _payload,
controller: _controller,
)
);
}

위젯 이벤트 처리

@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
// BootpayWidgetController _controller = BootpayWidgetController();//위젯 사이즈 변경 이벤트 
_controller.onWidgetResize = (height) {
print('onWidgetResize : $height');
//예제에서는 높이가 변경되면 스크롤을 내립니다.if(_widgetHeight == height) return;
if(_widgetHeight < height) {
scrollDown(height - _widgetHeight);
}
setState(() {
_widgetHeight = height;
});
};
//선택된 결제수단 변경 이벤트 
_controller.onWidgetChangePayment = (widgetData) {
print('onWidgetChangePayment22 : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//선택된 약관 변경 이벤트
_controller.onWidgetChangeAgreeTerm = (widgetData) {
print('onWidgetChangeAgreeTerm : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//위젯이 렌더링되면 호출되는 이벤트
_controller.onWidgetReady = () {
print('onWidgetReady');
};
}

위젯으로 결제하기

이 방법은 위젯을 사용하여 결제하는 방법입니다. 위젯을 사용하지 않고 결제를 요청하는 방법은 별도로 제공합니다.

// BootpayWidgetController _controller = BootpayWidgetController();
_controller.requestPayment(
context: context,
payload: _payload,
onCancel: (String data) {
print('------- onCancel 2 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onConfirm: (String data) {
print('------- onConfirm: $data');
returntrue; //결제를 승인합니다 
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onDone: (String data) {
print('------- onDone: $data');
// FlutterToast.showToast(msg: '결제가 완료되었습니다.');
},
);

결제하기

이 방법은 위젯을 사용하지 않고 결제하는 방법입니다.

//결제 정보를 초기화합니다.voidbootpayReqeustDataInit() {
Item item1 =Item();
item1.name ="미키 '마우스"; // 주문정보에 담길 상품명
item1.qty =1; // 해당 상품의 주문 수량
item1.id ="ITEM_CODE_MOUSE"; // 해당 상품의 고유 키
item1.price =500; // 상품의 가격Item item2 =Item();
item2.name ="키보드"; // 주문정보에 담길 상품명
item2.qty =1; // 해당 상품의 주문 수량
item2.id ="ITEM_CODE_KEYBOARD"; // 해당 상품의 고유 키
item2.price =500; // 상품의 가격List<Item> itemList = [item1, item2];
payload.webApplicationId = webApplicationId; // web application id
payload.androidApplicationId = androidApplicationId; // android application id
payload.iosApplicationId = iosApplicationId; // ios application id
payload.pg ='다날';
payload.method ='카드';
// payload.methods = ['카드', '휴대폰', '가상계좌', '계좌이체', '카카오페이'];
payload.orderName ="테스트 상품"; //결제할 상품명
payload.price =1000.0; //정기결제시 0 혹은 주석
payload.orderId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값
payload.items = itemList; // 상품정보 배열User user =User(); // 구매자 정보
user.id ="12341234";
user.username ="사용자 이름";
user.email ="user1234@gmail.com";
user.area ="서울";
user.phone ="010-0000-0000";
user.addr ='null';
Extra extra =Extra(); // 결제 옵션
extra.appScheme ='bootpayFlutter'; //결제 후 돌아갈 ios 앱 스키마를 설정합니다 
payload.user = user;
payload.items = itemList;
payload.extra = extra; }
voidgoBootpayPayment(BuildContext context) {
Bootpay().requestPayment(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 1 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { // checkQtyFromServer(data);returntrue;
},
// onConfirmAsync: (String data) async {// onConfirm 대신 사용하는 이벤트 처리 함수입니다. 내부에서 Future 문법을 사용할 수 있습니다.// print('------- onConfirmAsync: $data');// return true;// },
onDone: (String data) {
print('------- onDone: $data');
},
);
}

Bootpay 승인 요청

onConfirm, onConfirmAsync에서 승인 요청시 사용하는 함수입니다. 이 함수는 return false 로 리턴할 경우 사용합니다.

Bootpay().transactionConfirm();
returnfalse; 

Bootpay 창 닫기

onConfirm, onConfirmAsync등에서 진행중인 결제창을 닫을 때 사용하는 함수입니다. 서버인증으로 승인이 되었을 경우에, 클라이언트에서 창을 닫을 때 사용합니다.

Bootpay().dismiss(context);
returnfalse; 

자동결제 - 빌링키 발급 요청하기

voidgoBootpaySubscriptionUITest(BuildContext context) {
payload.subscriptionId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.pg ="키움페이";
payload.method ="카드자동"; // payload.price = 1000; 금액이 0 이상일 경우 빌링키 발급 후 결제가 진행됩니다.
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값Bootpay().requestSubscription(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 3: $data');
},
onError: (String data) {
print('------- onError 3: $data');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
//TODO - 원하시는 라우터로 페이지 이동
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);
}

본인인증

payload.pg ="다날";
payload.method ="본인인증";
payload.authenticationId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.extra =Extra();
payload.extra?.openType ='iframe';
payload.items =null;
Bootpay().requestAuthentication(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel: $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);

결제 진행 상태에 따라 LifeCycle 함수가 실행됩니다. 각 함수에 대한 상세 설명은 아래를 참고하세요.

onError 함수

결제 진행 중 오류가 발생된 경우 호출되는 함수입니다. 진행중 에러가 발생되는 경우는 다음과 같습니다.

  1. 부트페이 관리자에서 활성화 하지 않은 PG, 결제수단을 사용하고자 할 때
  2. PG에서 보내온 결제 정보를 부트페이 관리자에 잘못 입력하거나 입력하지 않은 경우
  3. 결제 진행 도중 한도초과, 카드정지, 휴대폰소액결제 막힘, 계좌이체 불가 등의 사유로 결제가 안되는 경우
  4. PG에서 리턴된 값이 다른 Client에 의해 변조된 경우

에러가 난 경우 해당 함수를 통해 관련 에러 메세지를 사용자에게 보여줄 수 있습니다.

data 포맷은 아래와 같습니다.

{
action: "BootpayError",
message: "카드사 거절",
receipt_id: "5fffab350c20b903e88a2cff"
}

onCancel 함수

결제 진행 중 사용자가 PG 결제창에서 취소 혹은 닫기 버튼을 눌러 나온 경우 입니다. ****

data 포맷은 아래와 같습니다.

{
action: "BootpayCancel",
message: "사용자가 결제를 취소하였습니다.",
receipt_id: "5fffab350c20b903e88a2cff"
}

onIssued 함수

가상계좌 발급이 완료되면 호출되는 함수입니다(가상계좌를 위한 Done). 가상계좌는 다른 결제와 다르게 입금할 계좌 번호 발급 이후 입금 후에 Feedback URL을 통해 통지가 됩니다. 발급된 가상계좌 정보를 issued 함수를 통해 확인하실 수 있습니다.

data 포맷은 아래와 같습니다.

{
account: "T0309260001169"
accounthodler: "한국사이버결제"
action: "BootpayBankReady"
bankcode: "BK03"
bankname: "기업은행"
expiredate: "2021-01-17 00:00:00"
item_name: "테스트 아이템"
method: "vbank"
method_name: "가상계좌"
order_id: "1610591554856"
metadata: null
payment_group: "vbank"
payment_group_name: "가상계좌"
payment_name: "가상계좌"
pg: "kcp"
pg_name: "KCP"
price: 3000
purchased_at: null
ready_url: "https://dev-app.bootpay.co.kr/bank/7o044QyX7p"
receipt_id: "5fffad430c20b903e88a2d17"
requested_at: "2021-01-14 11:32:35"
status: 2
tax_free: 0
url: "https://d-cdn.bootapi.com"
username: "홍길동"
}

onConfirm 함수

결제 승인이 되기 전 호출되는 함수입니다. 승인 이전 관련 로직을 서버 혹은 클라이언트에서 수행 후 결제를 승인해도 될 경우BootPay.transactionConfirm(data); 또는 return true;

코드를 실행해주시면 PG에서 결제 승인이 진행이 됩니다.

* 페이앱, 페이레터 PG는 이 함수가 실행되지 않고 바로 결제가 승인되는 PG 입니다. 참고해주시기 바랍니다.

data 포맷은 아래와 같습니다.

{
receipt_id: "5fffc0460c20b903e88a2d2c",
action: "BootpayConfirm"
}

onDone 함수

PG에서 거래 승인 이후에 호출 되는 함수입니다. 결제 완료 후 다음 결제 결과를 호출 할 수 있는 함수 입니다.

이 함수가 호출 된 후 반드시 REST API를 통해 결제검증을 수행해증야합니다. data 포맷은 아래와 같습니다.

{
action: "BootpayDone"
card_code: "CCKM",
card_name: "KB국민카드",
card_no: "0000120000000014",
card_quota: "00",
item_name: "테스트 아이템",
method: "card",
method_name: "카드결제",
order_id: "1610596422328",
payment_group: "card",
payment_group_name: "신용카드",
payment_name: "카드결제",
pg: "kcp",
pg_name: "KCP",
price: 100,
purchased_at: "2021-01-14 12:54:53",
receipt_id: "5fffc0460c20b903e88a2d2c",
receipt_url: "https://app.bootpay.co.kr/bill/UFMvZzJqSWNDNU9ERWh1YmUycU9hdnBkV29DVlJqdzUxRzZyNXRXbkNVZW81%0AQT09LS1XYlNJN1VoMDI4Q1hRdDh1LS10MEtZVmE4c1dyWHNHTXpZTVVLUk1R%0APT0%3D%0A",
requested_at: "2021-01-14 12:53:42",
status: 1,
tax_free: 0,
url: "https://d-cdn.bootapi.com"
}

WebView 프리워밍 (iOS/macOS)

iOS에서 WKWebView는 처음 로딩 시 GPU, Networking, WebContent 프로세스를 생성하는데 3-7초가 소요됩니다. Bootpay SDK는 자동으로 앱 시작 시 백그라운드에서 프로세스를 미리 생성하여 첫 결제 화면 로딩 속도를 개선합니다.

자동 프리워밍

SDK 초기화 시(첫 번째 Bootpay() 호출 시) 자동으로 프리워밍이 수행됩니다. 개발자가 별도로 호출할 필요가 없습니다.

메모리 관리 (선택사항)

메모리 부족 시 프리워밍된 리소스를 해제할 수 있습니다:

// 메모리 경고 수신 시 (선택사항)Bootpay.releaseWarmUp();

iOS AppDelegate에서 메모리 경고 시 자동 해제하도록 설정할 수도 있습니다:

// AppDelegate.swift
import bootpay_webview_flutter_wkwebview
overridefunc applicationDidReceiveMemoryWarning(_ application:UIApplication){
super.applicationDidReceiveMemoryWarning(application)BootpayWarmUpManager.shared.releaseWarmUp()}

효과

항목개선 효과
GPU 프로세스 초기화1-2초 단축
Networking 프로세스 초기화1-2초 단축
WebContent 프로세스 초기화1-3초 단축
총 개선 효과3-7초 단축

참고사항

  • iOS/macOS에서만 동작합니다. Android와 Web에서는 자동으로 무시됩니다.
  • 프리워밍은 자동으로 수행되므로 별도 설정이 필요 없습니다.
  • 두 번째 결제부터는 ProcessPool 공유로 자동으로 빠릅니다.

팝업 닫기(✕) 버튼 (iOS/Android)

결제창 안에서 window.open 또는 target="_blank" 로 열리는 팝업(주로 광고)은 앱 안에서 그대로 표시됩니다. 이런 팝업은 우측 상단에 뜨는 반투명 ✕ 버튼으로 사용자가 직접 닫을 수 있습니다.

광고는 차단되지 않습니다. 광고는 항상 인앱에 그대로 노출되며, 아래 설정은 "✕ 버튼을 언제 보여줄지"와 "팝업을 코드로 닫는 방법"만 제어합니다. 결제 PG 팝업은 window.close() 로 스스로 닫히므로 기본적으로 ✕ 가 붙지 않습니다.

import 'package:bootpay/bootpay.dart'; 후 아래 정적 메서드를 사용합니다.

✕ 버튼 노출 모드 설정

// 기본값(auto): 광고 도메인으로 분류된 팝업에만 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.auto);
// 모든 팝업에 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.always);
// ✕ 를 절대 노출하지 않음 (window.close 또는 closePopupWebView 로만 닫기)Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.never);
모드동작
BootpayPopupCloseButtonMode.auto기본값. 광고 도메인(addPopupAdHosts 목록)으로 분류된 팝업에만 ✕ 노출
BootpayPopupCloseButtonMode.always모든 팝업에 ✕ 노출
BootpayPopupCloseButtonMode.never✕ 를 노출하지 않음

광고 도메인 추가 (auto 모드용)

auto 모드에서 ✕ 를 띄울 광고 도메인을 런타임에 추가합니다. SDK 는 doubleclick.net / googleadservices.com / googlesyndication.com 등 주요 광고 네트워크 도메인을 기본 내장하고 있으며, 그 외 도메인을 더 넣고 싶을 때 사용합니다.

// host 의 부분 문자열로 대소문자 구분 없이 매칭됩니다.Bootpay.addPopupAdHosts(['ads.example.com', 'partner-ad.net']);

팝업을 코드로 닫기

광고 SDK 의 "광고 종료" 이벤트 등을 받았을 때, 사용자가 ✕ 를 누르지 않아도 현재 떠 있는 팝업을 닫을 수 있습니다. 메인 결제 WebView 에는 영향이 없으며, 열린 팝업이 없으면 아무 동작도 하지 않습니다.

Bootpay.closePopupWebView();
API설명
Bootpay.setPopupCloseButtonMode(mode)✕ 버튼 노출 모드 설정 (auto/always/never)
Bootpay.addPopupAdHosts(List<String> hosts)auto 모드에서 ✕ 를 띄울 광고 도메인 추가
Bootpay.closePopupWebView()현재 떠 있는 팝업을 프로그래매틱하게 닫기

참고: iOS / Android 전용입니다. Web 에서는 모두 no-op 으로 동작합니다.

Documentation

부트페이 개발매뉴얼을 참조해주세요

기술문의

채팅으로 문의

License

MIT License.

About

2세대 flutter api

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

bootpay 플러터 라이브러리

부트페이에서 지원하는 공식 Flutter 라이브러리 입니다

  • Android, iOS, Web 을 지원합니다.
  • Android SDK 16, iOS OS 13 부터 사용 가능합니다.

Bootpay 버전안내

이 모듈의 4.0.0 이상 버전부터는 Bootpay V2 이며, 그 이하 버전은 Bootpay V1에 해당합니다.

Bootpay V1, V2에 대한 특이점은 개발매뉴얼을 참고해주세요.

기능

  1. web/ios/android 지원
  2. 국내 주요 PG사 지원
  3. 주요 결제수단 지원
  4. 카드/계좌 자동결제 지원
  5. 위젯 지원
  6. 본인인증 지원

설치하기

pubspec.yaml 파일에 아래 모듈을 추가해주세요

...
dependencies:
...bootpay: last_version
...

설정하기

Android

따로 설정하실 것이 없습니다.

iOS

{your project root}/ios/Runner/Info.plist

CFBundleURLNameCFBundleURLSchemes의 값은 개발사에서 고유값으로 지정해주셔야 합니다. 외부앱(카드사앱)에서 다시 기존 앱으로 돌아올 때 필요한 스키마 값입니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPEplist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plistversion="1.0">
<dict>
...
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>kr.co.bootpaySample</string> <key>CFBundleURLSchemes</key>
<array>
<string>bootpaySample</string> </array>
</dict>
</array> </dict>
</plist>

Web

flutter web 빌드하면 web/index.html 파일이 생성됩니다. 해당 파일 header에 아래 script를 추가해주세요.

<!-- bootpay-최신버전-js 를 참조하여 추가합니다 --><scriptsrc="https://js.bootpay.co.kr/bootpay-5.3.0.min.js"></script><scriptsrc="bootpay_api.js" defer></script>

bootpay_api 파일을 프로젝트에 추가합니다.

위 설정을 완료하면 flutter web에서도 동일한 문법으로 bootpay를 사용할 수 있습니다.

iOS WebView 프리워밍 (자동)

iOS의 WKWebView는 첫 로딩 시 GPU, Networking, WebContent 프로세스 초기화로 4-6초 지연이 발생할 수 있습니다.

Bootpay Flutter SDK는 플러그인 등록 시 자동으로 프리워밍이 시작됩니다. 별도의 설정 없이도 첫 결제 화면 로딩 속도가 개선됩니다.

수동 호출 (선택사항)

특별한 타이밍에 프리워밍을 시작하고 싶다면 수동으로 호출할 수 있습니다:

import'package:bootpay/bootpay_warmup.dart';
// 기본 호출 (0.1초 딜레이)awaitBootpayWarmUp.warmUp();
// UI가 버벅이면 딜레이 증가awaitBootpayWarmUp.warmUp(delay:0.5);
// 프리워밍 상태 확인bool isReady =awaitBootpayWarmUp.checkIsWarmedUp();
// 메모리 부족 시 리소스 해제awaitBootpayWarmUp.releaseWarmUp();
API설명
BootpayWarmUp.warmUp()WebView 프로세스 미리 초기화 (자동 실행됨)
BootpayWarmUp.warmUp(delay: 0.5)커스텀 딜레이로 프리워밍
BootpayWarmUp.checkIsWarmedUp()프리워밍 완료 여부 확인
BootpayWarmUp.releaseWarmUp()프리워밍 리소스 해제

참고: Android와 Web에서는 이 기능이 no-op으로 동작합니다 (iOS/macOS 전용).

위젯 설정

부트페이 관리자에서 위젯을 생성하셔야만 사용이 가능합니다.

위젯 렌더링

Payload _payload =Payload();
BootpayWidgetController _controller =BootpayWidgetController();
@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
_payload.orderName ='5월 수강료';
_payload.orderId =DateTime
.now()
.millisecondsSinceEpoch
.toString();
_payload.webApplicationId = webApplicationId;
_payload.androidApplicationId = androidApplicationId;
_payload.iosApplicationId = iosApplicationId;
_payload.price =1000;
_payload.taxFree =0;
_payload.widgetKey ='default-widget';
_payload.widgetSandbox =true;
_payload.widgetUseTerms =true;
// _payload.userToken = "6667b08b04ab6d03f274d32e";
_payload.extra?.displaySuccessResult =true;
}
@overrideWidgetbuild(BuildContext context) {
returnContainer(
//하위로 위젯 정의 
child:BootpayWidget(
payload: _payload,
controller: _controller,
)
);
}

위젯 이벤트 처리

@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
// BootpayWidgetController _controller = BootpayWidgetController();//위젯 사이즈 변경 이벤트 
_controller.onWidgetResize = (height) {
print('onWidgetResize : $height');
//예제에서는 높이가 변경되면 스크롤을 내립니다.if(_widgetHeight == height) return;
if(_widgetHeight < height) {
scrollDown(height - _widgetHeight);
}
setState(() {
_widgetHeight = height;
});
};
//선택된 결제수단 변경 이벤트 
_controller.onWidgetChangePayment = (widgetData) {
print('onWidgetChangePayment22 : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//선택된 약관 변경 이벤트
_controller.onWidgetChangeAgreeTerm = (widgetData) {
print('onWidgetChangeAgreeTerm : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//위젯이 렌더링되면 호출되는 이벤트
_controller.onWidgetReady = () {
print('onWidgetReady');
};
}

위젯으로 결제하기

이 방법은 위젯을 사용하여 결제하는 방법입니다. 위젯을 사용하지 않고 결제를 요청하는 방법은 별도로 제공합니다.

// BootpayWidgetController _controller = BootpayWidgetController();
_controller.requestPayment(
context: context,
payload: _payload,
onCancel: (String data) {
print('------- onCancel 2 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onConfirm: (String data) {
print('------- onConfirm: $data');
returntrue; //결제를 승인합니다 
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onDone: (String data) {
print('------- onDone: $data');
// FlutterToast.showToast(msg: '결제가 완료되었습니다.');
},
);

결제하기

이 방법은 위젯을 사용하지 않고 결제하는 방법입니다.

//결제 정보를 초기화합니다.voidbootpayReqeustDataInit() {
Item item1 =Item();
item1.name ="미키 '마우스"; // 주문정보에 담길 상품명
item1.qty =1; // 해당 상품의 주문 수량
item1.id ="ITEM_CODE_MOUSE"; // 해당 상품의 고유 키
item1.price =500; // 상품의 가격Item item2 =Item();
item2.name ="키보드"; // 주문정보에 담길 상품명
item2.qty =1; // 해당 상품의 주문 수량
item2.id ="ITEM_CODE_KEYBOARD"; // 해당 상품의 고유 키
item2.price =500; // 상품의 가격List<Item> itemList = [item1, item2];
payload.webApplicationId = webApplicationId; // web application id
payload.androidApplicationId = androidApplicationId; // android application id
payload.iosApplicationId = iosApplicationId; // ios application id
payload.pg ='다날';
payload.method ='카드';
// payload.methods = ['카드', '휴대폰', '가상계좌', '계좌이체', '카카오페이'];
payload.orderName ="테스트 상품"; //결제할 상품명
payload.price =1000.0; //정기결제시 0 혹은 주석
payload.orderId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값
payload.items = itemList; // 상품정보 배열User user =User(); // 구매자 정보
user.id ="12341234";
user.username ="사용자 이름";
user.email ="user1234@gmail.com";
user.area ="서울";
user.phone ="010-0000-0000";
user.addr ='null';
Extra extra =Extra(); // 결제 옵션
extra.appScheme ='bootpayFlutter'; //결제 후 돌아갈 ios 앱 스키마를 설정합니다 
payload.user = user;
payload.items = itemList;
payload.extra = extra; }
voidgoBootpayPayment(BuildContext context) {
Bootpay().requestPayment(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 1 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { // checkQtyFromServer(data);returntrue;
},
// onConfirmAsync: (String data) async {// onConfirm 대신 사용하는 이벤트 처리 함수입니다. 내부에서 Future 문법을 사용할 수 있습니다.// print('------- onConfirmAsync: $data');// return true;// },
onDone: (String data) {
print('------- onDone: $data');
},
);
}

Bootpay 승인 요청

onConfirm, onConfirmAsync에서 승인 요청시 사용하는 함수입니다. 이 함수는 return false 로 리턴할 경우 사용합니다.

Bootpay().transactionConfirm();
returnfalse; 

Bootpay 창 닫기

onConfirm, onConfirmAsync등에서 진행중인 결제창을 닫을 때 사용하는 함수입니다. 서버인증으로 승인이 되었을 경우에, 클라이언트에서 창을 닫을 때 사용합니다.

Bootpay().dismiss(context);
returnfalse; 

자동결제 - 빌링키 발급 요청하기

voidgoBootpaySubscriptionUITest(BuildContext context) {
payload.subscriptionId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.pg ="키움페이";
payload.method ="카드자동"; // payload.price = 1000; 금액이 0 이상일 경우 빌링키 발급 후 결제가 진행됩니다.
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값Bootpay().requestSubscription(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 3: $data');
},
onError: (String data) {
print('------- onError 3: $data');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
//TODO - 원하시는 라우터로 페이지 이동
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);
}

본인인증

payload.pg ="다날";
payload.method ="본인인증";
payload.authenticationId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.extra =Extra();
payload.extra?.openType ='iframe';
payload.items =null;
Bootpay().requestAuthentication(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel: $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);

결제 진행 상태에 따라 LifeCycle 함수가 실행됩니다. 각 함수에 대한 상세 설명은 아래를 참고하세요.

onError 함수

결제 진행 중 오류가 발생된 경우 호출되는 함수입니다. 진행중 에러가 발생되는 경우는 다음과 같습니다.

  1. 부트페이 관리자에서 활성화 하지 않은 PG, 결제수단을 사용하고자 할 때
  2. PG에서 보내온 결제 정보를 부트페이 관리자에 잘못 입력하거나 입력하지 않은 경우
  3. 결제 진행 도중 한도초과, 카드정지, 휴대폰소액결제 막힘, 계좌이체 불가 등의 사유로 결제가 안되는 경우
  4. PG에서 리턴된 값이 다른 Client에 의해 변조된 경우

에러가 난 경우 해당 함수를 통해 관련 에러 메세지를 사용자에게 보여줄 수 있습니다.

data 포맷은 아래와 같습니다.

{
action: "BootpayError",
message: "카드사 거절",
receipt_id: "5fffab350c20b903e88a2cff"
}

onCancel 함수

결제 진행 중 사용자가 PG 결제창에서 취소 혹은 닫기 버튼을 눌러 나온 경우 입니다. ****

data 포맷은 아래와 같습니다.

{
action: "BootpayCancel",
message: "사용자가 결제를 취소하였습니다.",
receipt_id: "5fffab350c20b903e88a2cff"
}

onIssued 함수

가상계좌 발급이 완료되면 호출되는 함수입니다(가상계좌를 위한 Done). 가상계좌는 다른 결제와 다르게 입금할 계좌 번호 발급 이후 입금 후에 Feedback URL을 통해 통지가 됩니다. 발급된 가상계좌 정보를 issued 함수를 통해 확인하실 수 있습니다.

data 포맷은 아래와 같습니다.

{
account: "T0309260001169"
accounthodler: "한국사이버결제"
action: "BootpayBankReady"
bankcode: "BK03"
bankname: "기업은행"
expiredate: "2021-01-17 00:00:00"
item_name: "테스트 아이템"
method: "vbank"
method_name: "가상계좌"
order_id: "1610591554856"
metadata: null
payment_group: "vbank"
payment_group_name: "가상계좌"
payment_name: "가상계좌"
pg: "kcp"
pg_name: "KCP"
price: 3000
purchased_at: null
ready_url: "https://dev-app.bootpay.co.kr/bank/7o044QyX7p"
receipt_id: "5fffad430c20b903e88a2d17"
requested_at: "2021-01-14 11:32:35"
status: 2
tax_free: 0
url: "https://d-cdn.bootapi.com"
username: "홍길동"
}

onConfirm 함수

결제 승인이 되기 전 호출되는 함수입니다. 승인 이전 관련 로직을 서버 혹은 클라이언트에서 수행 후 결제를 승인해도 될 경우BootPay.transactionConfirm(data); 또는 return true;

코드를 실행해주시면 PG에서 결제 승인이 진행이 됩니다.

* 페이앱, 페이레터 PG는 이 함수가 실행되지 않고 바로 결제가 승인되는 PG 입니다. 참고해주시기 바랍니다.

data 포맷은 아래와 같습니다.

{
receipt_id: "5fffc0460c20b903e88a2d2c",
action: "BootpayConfirm"
}

onDone 함수

PG에서 거래 승인 이후에 호출 되는 함수입니다. 결제 완료 후 다음 결제 결과를 호출 할 수 있는 함수 입니다.

이 함수가 호출 된 후 반드시 REST API를 통해 결제검증을 수행해증야합니다. data 포맷은 아래와 같습니다.

{
action: "BootpayDone"
card_code: "CCKM",
card_name: "KB국민카드",
card_no: "0000120000000014",
card_quota: "00",
item_name: "테스트 아이템",
method: "card",
method_name: "카드결제",
order_id: "1610596422328",
payment_group: "card",
payment_group_name: "신용카드",
payment_name: "카드결제",
pg: "kcp",
pg_name: "KCP",
price: 100,
purchased_at: "2021-01-14 12:54:53",
receipt_id: "5fffc0460c20b903e88a2d2c",
receipt_url: "https://app.bootpay.co.kr/bill/UFMvZzJqSWNDNU9ERWh1YmUycU9hdnBkV29DVlJqdzUxRzZyNXRXbkNVZW81%0AQT09LS1XYlNJN1VoMDI4Q1hRdDh1LS10MEtZVmE4c1dyWHNHTXpZTVVLUk1R%0APT0%3D%0A",
requested_at: "2021-01-14 12:53:42",
status: 1,
tax_free: 0,
url: "https://d-cdn.bootapi.com"
}

WebView 프리워밍 (iOS/macOS)

iOS에서 WKWebView는 처음 로딩 시 GPU, Networking, WebContent 프로세스를 생성하는데 3-7초가 소요됩니다. Bootpay SDK는 자동으로 앱 시작 시 백그라운드에서 프로세스를 미리 생성하여 첫 결제 화면 로딩 속도를 개선합니다.

자동 프리워밍

SDK 초기화 시(첫 번째 Bootpay() 호출 시) 자동으로 프리워밍이 수행됩니다. 개발자가 별도로 호출할 필요가 없습니다.

메모리 관리 (선택사항)

메모리 부족 시 프리워밍된 리소스를 해제할 수 있습니다:

// 메모리 경고 수신 시 (선택사항)Bootpay.releaseWarmUp();

iOS AppDelegate에서 메모리 경고 시 자동 해제하도록 설정할 수도 있습니다:

// AppDelegate.swift
import bootpay_webview_flutter_wkwebview
overridefunc applicationDidReceiveMemoryWarning(_ application:UIApplication){
super.applicationDidReceiveMemoryWarning(application)BootpayWarmUpManager.shared.releaseWarmUp()}

효과

항목개선 효과
GPU 프로세스 초기화1-2초 단축
Networking 프로세스 초기화1-2초 단축
WebContent 프로세스 초기화1-3초 단축
총 개선 효과3-7초 단축

참고사항

  • iOS/macOS에서만 동작합니다. Android와 Web에서는 자동으로 무시됩니다.
  • 프리워밍은 자동으로 수행되므로 별도 설정이 필요 없습니다.
  • 두 번째 결제부터는 ProcessPool 공유로 자동으로 빠릅니다.

팝업 닫기(✕) 버튼 (iOS/Android)

결제창 안에서 window.open 또는 target="_blank" 로 열리는 팝업(주로 광고)은 앱 안에서 그대로 표시됩니다. 이런 팝업은 우측 상단에 뜨는 반투명 ✕ 버튼으로 사용자가 직접 닫을 수 있습니다.

광고는 차단되지 않습니다. 광고는 항상 인앱에 그대로 노출되며, 아래 설정은 "✕ 버튼을 언제 보여줄지"와 "팝업을 코드로 닫는 방법"만 제어합니다. 결제 PG 팝업은 window.close() 로 스스로 닫히므로 기본적으로 ✕ 가 붙지 않습니다.

import 'package:bootpay/bootpay.dart'; 후 아래 정적 메서드를 사용합니다.

✕ 버튼 노출 모드 설정

// 기본값(auto): 광고 도메인으로 분류된 팝업에만 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.auto);
// 모든 팝업에 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.always);
// ✕ 를 절대 노출하지 않음 (window.close 또는 closePopupWebView 로만 닫기)Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.never);
모드동작
BootpayPopupCloseButtonMode.auto기본값. 광고 도메인(addPopupAdHosts 목록)으로 분류된 팝업에만 ✕ 노출
BootpayPopupCloseButtonMode.always모든 팝업에 ✕ 노출
BootpayPopupCloseButtonMode.never✕ 를 노출하지 않음

광고 도메인 추가 (auto 모드용)

auto 모드에서 ✕ 를 띄울 광고 도메인을 런타임에 추가합니다. SDK 는 doubleclick.net / googleadservices.com / googlesyndication.com 등 주요 광고 네트워크 도메인을 기본 내장하고 있으며, 그 외 도메인을 더 넣고 싶을 때 사용합니다.

// host 의 부분 문자열로 대소문자 구분 없이 매칭됩니다.Bootpay.addPopupAdHosts(['ads.example.com', 'partner-ad.net']);

팝업을 코드로 닫기

광고 SDK 의 "광고 종료" 이벤트 등을 받았을 때, 사용자가 ✕ 를 누르지 않아도 현재 떠 있는 팝업을 닫을 수 있습니다. 메인 결제 WebView 에는 영향이 없으며, 열린 팝업이 없으면 아무 동작도 하지 않습니다.

Bootpay.closePopupWebView();
API설명
Bootpay.setPopupCloseButtonMode(mode)✕ 버튼 노출 모드 설정 (auto/always/never)
Bootpay.addPopupAdHosts(List<String> hosts)auto 모드에서 ✕ 를 띄울 광고 도메인 추가
Bootpay.closePopupWebView()현재 떠 있는 팝업을 프로그래매틱하게 닫기

참고: iOS / Android 전용입니다. Web 에서는 모두 no-op 으로 동작합니다.

Documentation

부트페이 개발매뉴얼을 참조해주세요

기술문의

채팅으로 문의

License

MIT License.

About

2세대 flutter api

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

bootpay 플러터 라이브러리

부트페이에서 지원하는 공식 Flutter 라이브러리 입니다

  • Android, iOS, Web 을 지원합니다.
  • Android SDK 16, iOS OS 13 부터 사용 가능합니다.

Bootpay 버전안내

이 모듈의 4.0.0 이상 버전부터는 Bootpay V2 이며, 그 이하 버전은 Bootpay V1에 해당합니다.

Bootpay V1, V2에 대한 특이점은 개발매뉴얼을 참고해주세요.

기능

  1. web/ios/android 지원
  2. 국내 주요 PG사 지원
  3. 주요 결제수단 지원
  4. 카드/계좌 자동결제 지원
  5. 위젯 지원
  6. 본인인증 지원

설치하기

pubspec.yaml 파일에 아래 모듈을 추가해주세요

...
dependencies:
...bootpay: last_version
...

설정하기

Android

따로 설정하실 것이 없습니다.

iOS

{your project root}/ios/Runner/Info.plist

CFBundleURLNameCFBundleURLSchemes의 값은 개발사에서 고유값으로 지정해주셔야 합니다. 외부앱(카드사앱)에서 다시 기존 앱으로 돌아올 때 필요한 스키마 값입니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPEplist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plistversion="1.0">
<dict>
...
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>kr.co.bootpaySample</string> <key>CFBundleURLSchemes</key>
<array>
<string>bootpaySample</string> </array>
</dict>
</array> </dict>
</plist>

Web

flutter web 빌드하면 web/index.html 파일이 생성됩니다. 해당 파일 header에 아래 script를 추가해주세요.

<!-- bootpay-최신버전-js 를 참조하여 추가합니다 --><scriptsrc="https://js.bootpay.co.kr/bootpay-5.3.0.min.js"></script><scriptsrc="bootpay_api.js" defer></script>

bootpay_api 파일을 프로젝트에 추가합니다.

위 설정을 완료하면 flutter web에서도 동일한 문법으로 bootpay를 사용할 수 있습니다.

iOS WebView 프리워밍 (자동)

iOS의 WKWebView는 첫 로딩 시 GPU, Networking, WebContent 프로세스 초기화로 4-6초 지연이 발생할 수 있습니다.

Bootpay Flutter SDK는 플러그인 등록 시 자동으로 프리워밍이 시작됩니다. 별도의 설정 없이도 첫 결제 화면 로딩 속도가 개선됩니다.

수동 호출 (선택사항)

특별한 타이밍에 프리워밍을 시작하고 싶다면 수동으로 호출할 수 있습니다:

import'package:bootpay/bootpay_warmup.dart';
// 기본 호출 (0.1초 딜레이)awaitBootpayWarmUp.warmUp();
// UI가 버벅이면 딜레이 증가awaitBootpayWarmUp.warmUp(delay:0.5);
// 프리워밍 상태 확인bool isReady =awaitBootpayWarmUp.checkIsWarmedUp();
// 메모리 부족 시 리소스 해제awaitBootpayWarmUp.releaseWarmUp();
API설명
BootpayWarmUp.warmUp()WebView 프로세스 미리 초기화 (자동 실행됨)
BootpayWarmUp.warmUp(delay: 0.5)커스텀 딜레이로 프리워밍
BootpayWarmUp.checkIsWarmedUp()프리워밍 완료 여부 확인
BootpayWarmUp.releaseWarmUp()프리워밍 리소스 해제

참고: Android와 Web에서는 이 기능이 no-op으로 동작합니다 (iOS/macOS 전용).

위젯 설정

부트페이 관리자에서 위젯을 생성하셔야만 사용이 가능합니다.

위젯 렌더링

Payload _payload =Payload();
BootpayWidgetController _controller =BootpayWidgetController();
@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
_payload.orderName ='5월 수강료';
_payload.orderId =DateTime
.now()
.millisecondsSinceEpoch
.toString();
_payload.webApplicationId = webApplicationId;
_payload.androidApplicationId = androidApplicationId;
_payload.iosApplicationId = iosApplicationId;
_payload.price =1000;
_payload.taxFree =0;
_payload.widgetKey ='default-widget';
_payload.widgetSandbox =true;
_payload.widgetUseTerms =true;
// _payload.userToken = "6667b08b04ab6d03f274d32e";
_payload.extra?.displaySuccessResult =true;
}
@overrideWidgetbuild(BuildContext context) {
returnContainer(
//하위로 위젯 정의 
child:BootpayWidget(
payload: _payload,
controller: _controller,
)
);
}

위젯 이벤트 처리

@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
// BootpayWidgetController _controller = BootpayWidgetController();//위젯 사이즈 변경 이벤트 
_controller.onWidgetResize = (height) {
print('onWidgetResize : $height');
//예제에서는 높이가 변경되면 스크롤을 내립니다.if(_widgetHeight == height) return;
if(_widgetHeight < height) {
scrollDown(height - _widgetHeight);
}
setState(() {
_widgetHeight = height;
});
};
//선택된 결제수단 변경 이벤트 
_controller.onWidgetChangePayment = (widgetData) {
print('onWidgetChangePayment22 : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//선택된 약관 변경 이벤트
_controller.onWidgetChangeAgreeTerm = (widgetData) {
print('onWidgetChangeAgreeTerm : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//위젯이 렌더링되면 호출되는 이벤트
_controller.onWidgetReady = () {
print('onWidgetReady');
};
}

위젯으로 결제하기

이 방법은 위젯을 사용하여 결제하는 방법입니다. 위젯을 사용하지 않고 결제를 요청하는 방법은 별도로 제공합니다.

// BootpayWidgetController _controller = BootpayWidgetController();
_controller.requestPayment(
context: context,
payload: _payload,
onCancel: (String data) {
print('------- onCancel 2 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onConfirm: (String data) {
print('------- onConfirm: $data');
returntrue; //결제를 승인합니다 
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onDone: (String data) {
print('------- onDone: $data');
// FlutterToast.showToast(msg: '결제가 완료되었습니다.');
},
);

결제하기

이 방법은 위젯을 사용하지 않고 결제하는 방법입니다.

//결제 정보를 초기화합니다.voidbootpayReqeustDataInit() {
Item item1 =Item();
item1.name ="미키 '마우스"; // 주문정보에 담길 상품명
item1.qty =1; // 해당 상품의 주문 수량
item1.id ="ITEM_CODE_MOUSE"; // 해당 상품의 고유 키
item1.price =500; // 상품의 가격Item item2 =Item();
item2.name ="키보드"; // 주문정보에 담길 상품명
item2.qty =1; // 해당 상품의 주문 수량
item2.id ="ITEM_CODE_KEYBOARD"; // 해당 상품의 고유 키
item2.price =500; // 상품의 가격List<Item> itemList = [item1, item2];
payload.webApplicationId = webApplicationId; // web application id
payload.androidApplicationId = androidApplicationId; // android application id
payload.iosApplicationId = iosApplicationId; // ios application id
payload.pg ='다날';
payload.method ='카드';
// payload.methods = ['카드', '휴대폰', '가상계좌', '계좌이체', '카카오페이'];
payload.orderName ="테스트 상품"; //결제할 상품명
payload.price =1000.0; //정기결제시 0 혹은 주석
payload.orderId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값
payload.items = itemList; // 상품정보 배열User user =User(); // 구매자 정보
user.id ="12341234";
user.username ="사용자 이름";
user.email ="user1234@gmail.com";
user.area ="서울";
user.phone ="010-0000-0000";
user.addr ='null';
Extra extra =Extra(); // 결제 옵션
extra.appScheme ='bootpayFlutter'; //결제 후 돌아갈 ios 앱 스키마를 설정합니다 
payload.user = user;
payload.items = itemList;
payload.extra = extra; }
voidgoBootpayPayment(BuildContext context) {
Bootpay().requestPayment(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 1 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { // checkQtyFromServer(data);returntrue;
},
// onConfirmAsync: (String data) async {// onConfirm 대신 사용하는 이벤트 처리 함수입니다. 내부에서 Future 문법을 사용할 수 있습니다.// print('------- onConfirmAsync: $data');// return true;// },
onDone: (String data) {
print('------- onDone: $data');
},
);
}

Bootpay 승인 요청

onConfirm, onConfirmAsync에서 승인 요청시 사용하는 함수입니다. 이 함수는 return false 로 리턴할 경우 사용합니다.

Bootpay().transactionConfirm();
returnfalse; 

Bootpay 창 닫기

onConfirm, onConfirmAsync등에서 진행중인 결제창을 닫을 때 사용하는 함수입니다. 서버인증으로 승인이 되었을 경우에, 클라이언트에서 창을 닫을 때 사용합니다.

Bootpay().dismiss(context);
returnfalse; 

자동결제 - 빌링키 발급 요청하기

voidgoBootpaySubscriptionUITest(BuildContext context) {
payload.subscriptionId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.pg ="키움페이";
payload.method ="카드자동"; // payload.price = 1000; 금액이 0 이상일 경우 빌링키 발급 후 결제가 진행됩니다.
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값Bootpay().requestSubscription(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 3: $data');
},
onError: (String data) {
print('------- onError 3: $data');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
//TODO - 원하시는 라우터로 페이지 이동
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);
}

본인인증

payload.pg ="다날";
payload.method ="본인인증";
payload.authenticationId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.extra =Extra();
payload.extra?.openType ='iframe';
payload.items =null;
Bootpay().requestAuthentication(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel: $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);

결제 진행 상태에 따라 LifeCycle 함수가 실행됩니다. 각 함수에 대한 상세 설명은 아래를 참고하세요.

onError 함수

결제 진행 중 오류가 발생된 경우 호출되는 함수입니다. 진행중 에러가 발생되는 경우는 다음과 같습니다.

  1. 부트페이 관리자에서 활성화 하지 않은 PG, 결제수단을 사용하고자 할 때
  2. PG에서 보내온 결제 정보를 부트페이 관리자에 잘못 입력하거나 입력하지 않은 경우
  3. 결제 진행 도중 한도초과, 카드정지, 휴대폰소액결제 막힘, 계좌이체 불가 등의 사유로 결제가 안되는 경우
  4. PG에서 리턴된 값이 다른 Client에 의해 변조된 경우

에러가 난 경우 해당 함수를 통해 관련 에러 메세지를 사용자에게 보여줄 수 있습니다.

data 포맷은 아래와 같습니다.

{
action: "BootpayError",
message: "카드사 거절",
receipt_id: "5fffab350c20b903e88a2cff"
}

onCancel 함수

결제 진행 중 사용자가 PG 결제창에서 취소 혹은 닫기 버튼을 눌러 나온 경우 입니다. ****

data 포맷은 아래와 같습니다.

{
action: "BootpayCancel",
message: "사용자가 결제를 취소하였습니다.",
receipt_id: "5fffab350c20b903e88a2cff"
}

onIssued 함수

가상계좌 발급이 완료되면 호출되는 함수입니다(가상계좌를 위한 Done). 가상계좌는 다른 결제와 다르게 입금할 계좌 번호 발급 이후 입금 후에 Feedback URL을 통해 통지가 됩니다. 발급된 가상계좌 정보를 issued 함수를 통해 확인하실 수 있습니다.

data 포맷은 아래와 같습니다.

{
account: "T0309260001169"
accounthodler: "한국사이버결제"
action: "BootpayBankReady"
bankcode: "BK03"
bankname: "기업은행"
expiredate: "2021-01-17 00:00:00"
item_name: "테스트 아이템"
method: "vbank"
method_name: "가상계좌"
order_id: "1610591554856"
metadata: null
payment_group: "vbank"
payment_group_name: "가상계좌"
payment_name: "가상계좌"
pg: "kcp"
pg_name: "KCP"
price: 3000
purchased_at: null
ready_url: "https://dev-app.bootpay.co.kr/bank/7o044QyX7p"
receipt_id: "5fffad430c20b903e88a2d17"
requested_at: "2021-01-14 11:32:35"
status: 2
tax_free: 0
url: "https://d-cdn.bootapi.com"
username: "홍길동"
}

onConfirm 함수

결제 승인이 되기 전 호출되는 함수입니다. 승인 이전 관련 로직을 서버 혹은 클라이언트에서 수행 후 결제를 승인해도 될 경우BootPay.transactionConfirm(data); 또는 return true;

코드를 실행해주시면 PG에서 결제 승인이 진행이 됩니다.

* 페이앱, 페이레터 PG는 이 함수가 실행되지 않고 바로 결제가 승인되는 PG 입니다. 참고해주시기 바랍니다.

data 포맷은 아래와 같습니다.

{
receipt_id: "5fffc0460c20b903e88a2d2c",
action: "BootpayConfirm"
}

onDone 함수

PG에서 거래 승인 이후에 호출 되는 함수입니다. 결제 완료 후 다음 결제 결과를 호출 할 수 있는 함수 입니다.

이 함수가 호출 된 후 반드시 REST API를 통해 결제검증을 수행해증야합니다. data 포맷은 아래와 같습니다.

{
action: "BootpayDone"
card_code: "CCKM",
card_name: "KB국민카드",
card_no: "0000120000000014",
card_quota: "00",
item_name: "테스트 아이템",
method: "card",
method_name: "카드결제",
order_id: "1610596422328",
payment_group: "card",
payment_group_name: "신용카드",
payment_name: "카드결제",
pg: "kcp",
pg_name: "KCP",
price: 100,
purchased_at: "2021-01-14 12:54:53",
receipt_id: "5fffc0460c20b903e88a2d2c",
receipt_url: "https://app.bootpay.co.kr/bill/UFMvZzJqSWNDNU9ERWh1YmUycU9hdnBkV29DVlJqdzUxRzZyNXRXbkNVZW81%0AQT09LS1XYlNJN1VoMDI4Q1hRdDh1LS10MEtZVmE4c1dyWHNHTXpZTVVLUk1R%0APT0%3D%0A",
requested_at: "2021-01-14 12:53:42",
status: 1,
tax_free: 0,
url: "https://d-cdn.bootapi.com"
}

WebView 프리워밍 (iOS/macOS)

iOS에서 WKWebView는 처음 로딩 시 GPU, Networking, WebContent 프로세스를 생성하는데 3-7초가 소요됩니다. Bootpay SDK는 자동으로 앱 시작 시 백그라운드에서 프로세스를 미리 생성하여 첫 결제 화면 로딩 속도를 개선합니다.

자동 프리워밍

SDK 초기화 시(첫 번째 Bootpay() 호출 시) 자동으로 프리워밍이 수행됩니다. 개발자가 별도로 호출할 필요가 없습니다.

메모리 관리 (선택사항)

메모리 부족 시 프리워밍된 리소스를 해제할 수 있습니다:

// 메모리 경고 수신 시 (선택사항)Bootpay.releaseWarmUp();

iOS AppDelegate에서 메모리 경고 시 자동 해제하도록 설정할 수도 있습니다:

// AppDelegate.swift
import bootpay_webview_flutter_wkwebview
overridefunc applicationDidReceiveMemoryWarning(_ application:UIApplication){
super.applicationDidReceiveMemoryWarning(application)BootpayWarmUpManager.shared.releaseWarmUp()}

효과

항목개선 효과
GPU 프로세스 초기화1-2초 단축
Networking 프로세스 초기화1-2초 단축
WebContent 프로세스 초기화1-3초 단축
총 개선 효과3-7초 단축

참고사항

  • iOS/macOS에서만 동작합니다. Android와 Web에서는 자동으로 무시됩니다.
  • 프리워밍은 자동으로 수행되므로 별도 설정이 필요 없습니다.
  • 두 번째 결제부터는 ProcessPool 공유로 자동으로 빠릅니다.

팝업 닫기(✕) 버튼 (iOS/Android)

결제창 안에서 window.open 또는 target="_blank" 로 열리는 팝업(주로 광고)은 앱 안에서 그대로 표시됩니다. 이런 팝업은 우측 상단에 뜨는 반투명 ✕ 버튼으로 사용자가 직접 닫을 수 있습니다.

광고는 차단되지 않습니다. 광고는 항상 인앱에 그대로 노출되며, 아래 설정은 "✕ 버튼을 언제 보여줄지"와 "팝업을 코드로 닫는 방법"만 제어합니다. 결제 PG 팝업은 window.close() 로 스스로 닫히므로 기본적으로 ✕ 가 붙지 않습니다.

import 'package:bootpay/bootpay.dart'; 후 아래 정적 메서드를 사용합니다.

✕ 버튼 노출 모드 설정

// 기본값(auto): 광고 도메인으로 분류된 팝업에만 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.auto);
// 모든 팝업에 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.always);
// ✕ 를 절대 노출하지 않음 (window.close 또는 closePopupWebView 로만 닫기)Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.never);
모드동작
BootpayPopupCloseButtonMode.auto기본값. 광고 도메인(addPopupAdHosts 목록)으로 분류된 팝업에만 ✕ 노출
BootpayPopupCloseButtonMode.always모든 팝업에 ✕ 노출
BootpayPopupCloseButtonMode.never✕ 를 노출하지 않음

광고 도메인 추가 (auto 모드용)

auto 모드에서 ✕ 를 띄울 광고 도메인을 런타임에 추가합니다. SDK 는 doubleclick.net / googleadservices.com / googlesyndication.com 등 주요 광고 네트워크 도메인을 기본 내장하고 있으며, 그 외 도메인을 더 넣고 싶을 때 사용합니다.

// host 의 부분 문자열로 대소문자 구분 없이 매칭됩니다.Bootpay.addPopupAdHosts(['ads.example.com', 'partner-ad.net']);

팝업을 코드로 닫기

광고 SDK 의 "광고 종료" 이벤트 등을 받았을 때, 사용자가 ✕ 를 누르지 않아도 현재 떠 있는 팝업을 닫을 수 있습니다. 메인 결제 WebView 에는 영향이 없으며, 열린 팝업이 없으면 아무 동작도 하지 않습니다.

Bootpay.closePopupWebView();
API설명
Bootpay.setPopupCloseButtonMode(mode)✕ 버튼 노출 모드 설정 (auto/always/never)
Bootpay.addPopupAdHosts(List<String> hosts)auto 모드에서 ✕ 를 띄울 광고 도메인 추가
Bootpay.closePopupWebView()현재 떠 있는 팝업을 프로그래매틱하게 닫기

참고: iOS / Android 전용입니다. Web 에서는 모두 no-op 으로 동작합니다.

Documentation

부트페이 개발매뉴얼을 참조해주세요

기술문의

채팅으로 문의

License

MIT License.

About

2세대 flutter api

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

bootpay 플러터 라이브러리

부트페이에서 지원하는 공식 Flutter 라이브러리 입니다

  • Android, iOS, Web 을 지원합니다.
  • Android SDK 16, iOS OS 13 부터 사용 가능합니다.

Bootpay 버전안내

이 모듈의 4.0.0 이상 버전부터는 Bootpay V2 이며, 그 이하 버전은 Bootpay V1에 해당합니다.

Bootpay V1, V2에 대한 특이점은 개발매뉴얼을 참고해주세요.

기능

  1. web/ios/android 지원
  2. 국내 주요 PG사 지원
  3. 주요 결제수단 지원
  4. 카드/계좌 자동결제 지원
  5. 위젯 지원
  6. 본인인증 지원

설치하기

pubspec.yaml 파일에 아래 모듈을 추가해주세요

...
dependencies:
...bootpay: last_version
...

설정하기

Android

따로 설정하실 것이 없습니다.

iOS

{your project root}/ios/Runner/Info.plist

CFBundleURLNameCFBundleURLSchemes의 값은 개발사에서 고유값으로 지정해주셔야 합니다. 외부앱(카드사앱)에서 다시 기존 앱으로 돌아올 때 필요한 스키마 값입니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPEplist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plistversion="1.0">
<dict>
...
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>kr.co.bootpaySample</string> <key>CFBundleURLSchemes</key>
<array>
<string>bootpaySample</string> </array>
</dict>
</array> </dict>
</plist>

Web

flutter web 빌드하면 web/index.html 파일이 생성됩니다. 해당 파일 header에 아래 script를 추가해주세요.

<!-- bootpay-최신버전-js 를 참조하여 추가합니다 --><scriptsrc="https://js.bootpay.co.kr/bootpay-5.3.0.min.js"></script><scriptsrc="bootpay_api.js" defer></script>

bootpay_api 파일을 프로젝트에 추가합니다.

위 설정을 완료하면 flutter web에서도 동일한 문법으로 bootpay를 사용할 수 있습니다.

iOS WebView 프리워밍 (자동)

iOS의 WKWebView는 첫 로딩 시 GPU, Networking, WebContent 프로세스 초기화로 4-6초 지연이 발생할 수 있습니다.

Bootpay Flutter SDK는 플러그인 등록 시 자동으로 프리워밍이 시작됩니다. 별도의 설정 없이도 첫 결제 화면 로딩 속도가 개선됩니다.

수동 호출 (선택사항)

특별한 타이밍에 프리워밍을 시작하고 싶다면 수동으로 호출할 수 있습니다:

import'package:bootpay/bootpay_warmup.dart';
// 기본 호출 (0.1초 딜레이)awaitBootpayWarmUp.warmUp();
// UI가 버벅이면 딜레이 증가awaitBootpayWarmUp.warmUp(delay:0.5);
// 프리워밍 상태 확인bool isReady =awaitBootpayWarmUp.checkIsWarmedUp();
// 메모리 부족 시 리소스 해제awaitBootpayWarmUp.releaseWarmUp();
API설명
BootpayWarmUp.warmUp()WebView 프로세스 미리 초기화 (자동 실행됨)
BootpayWarmUp.warmUp(delay: 0.5)커스텀 딜레이로 프리워밍
BootpayWarmUp.checkIsWarmedUp()프리워밍 완료 여부 확인
BootpayWarmUp.releaseWarmUp()프리워밍 리소스 해제

참고: Android와 Web에서는 이 기능이 no-op으로 동작합니다 (iOS/macOS 전용).

위젯 설정

부트페이 관리자에서 위젯을 생성하셔야만 사용이 가능합니다.

위젯 렌더링

Payload _payload =Payload();
BootpayWidgetController _controller =BootpayWidgetController();
@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
_payload.orderName ='5월 수강료';
_payload.orderId =DateTime
.now()
.millisecondsSinceEpoch
.toString();
_payload.webApplicationId = webApplicationId;
_payload.androidApplicationId = androidApplicationId;
_payload.iosApplicationId = iosApplicationId;
_payload.price =1000;
_payload.taxFree =0;
_payload.widgetKey ='default-widget';
_payload.widgetSandbox =true;
_payload.widgetUseTerms =true;
// _payload.userToken = "6667b08b04ab6d03f274d32e";
_payload.extra?.displaySuccessResult =true;
}
@overrideWidgetbuild(BuildContext context) {
returnContainer(
//하위로 위젯 정의 
child:BootpayWidget(
payload: _payload,
controller: _controller,
)
);
}

위젯 이벤트 처리

@overridevoidinitState() {
// TODO: implement initStatesuper.initState();
// BootpayWidgetController _controller = BootpayWidgetController();//위젯 사이즈 변경 이벤트 
_controller.onWidgetResize = (height) {
print('onWidgetResize : $height');
//예제에서는 높이가 변경되면 스크롤을 내립니다.if(_widgetHeight == height) return;
if(_widgetHeight < height) {
scrollDown(height - _widgetHeight);
}
setState(() {
_widgetHeight = height;
});
};
//선택된 결제수단 변경 이벤트 
_controller.onWidgetChangePayment = (widgetData) {
print('onWidgetChangePayment22 : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//선택된 약관 변경 이벤트
_controller.onWidgetChangeAgreeTerm = (widgetData) {
print('onWidgetChangeAgreeTerm : ${widgetData?.toJson()}');
//예제에서는 widgetData 정보를 payload에 반영합니다. 반영된 payload는 추후 결제요청시 사용됩니다.setState(() {
_payload?.mergeWidgetData(widgetData);
});
};
//위젯이 렌더링되면 호출되는 이벤트
_controller.onWidgetReady = () {
print('onWidgetReady');
};
}

위젯으로 결제하기

이 방법은 위젯을 사용하여 결제하는 방법입니다. 위젯을 사용하지 않고 결제를 요청하는 방법은 별도로 제공합니다.

// BootpayWidgetController _controller = BootpayWidgetController();
_controller.requestPayment(
context: context,
payload: _payload,
onCancel: (String data) {
print('------- onCancel 2 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onConfirm: (String data) {
print('------- onConfirm: $data');
returntrue; //결제를 승인합니다 
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onDone: (String data) {
print('------- onDone: $data');
// FlutterToast.showToast(msg: '결제가 완료되었습니다.');
},
);

결제하기

이 방법은 위젯을 사용하지 않고 결제하는 방법입니다.

//결제 정보를 초기화합니다.voidbootpayReqeustDataInit() {
Item item1 =Item();
item1.name ="미키 '마우스"; // 주문정보에 담길 상품명
item1.qty =1; // 해당 상품의 주문 수량
item1.id ="ITEM_CODE_MOUSE"; // 해당 상품의 고유 키
item1.price =500; // 상품의 가격Item item2 =Item();
item2.name ="키보드"; // 주문정보에 담길 상품명
item2.qty =1; // 해당 상품의 주문 수량
item2.id ="ITEM_CODE_KEYBOARD"; // 해당 상품의 고유 키
item2.price =500; // 상품의 가격List<Item> itemList = [item1, item2];
payload.webApplicationId = webApplicationId; // web application id
payload.androidApplicationId = androidApplicationId; // android application id
payload.iosApplicationId = iosApplicationId; // ios application id
payload.pg ='다날';
payload.method ='카드';
// payload.methods = ['카드', '휴대폰', '가상계좌', '계좌이체', '카카오페이'];
payload.orderName ="테스트 상품"; //결제할 상품명
payload.price =1000.0; //정기결제시 0 혹은 주석
payload.orderId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값
payload.items = itemList; // 상품정보 배열User user =User(); // 구매자 정보
user.id ="12341234";
user.username ="사용자 이름";
user.email ="user1234@gmail.com";
user.area ="서울";
user.phone ="010-0000-0000";
user.addr ='null';
Extra extra =Extra(); // 결제 옵션
extra.appScheme ='bootpayFlutter'; //결제 후 돌아갈 ios 앱 스키마를 설정합니다 
payload.user = user;
payload.items = itemList;
payload.extra = extra; }
voidgoBootpayPayment(BuildContext context) {
Bootpay().requestPayment(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 1 : $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { // checkQtyFromServer(data);returntrue;
},
// onConfirmAsync: (String data) async {// onConfirm 대신 사용하는 이벤트 처리 함수입니다. 내부에서 Future 문법을 사용할 수 있습니다.// print('------- onConfirmAsync: $data');// return true;// },
onDone: (String data) {
print('------- onDone: $data');
},
);
}

Bootpay 승인 요청

onConfirm, onConfirmAsync에서 승인 요청시 사용하는 함수입니다. 이 함수는 return false 로 리턴할 경우 사용합니다.

Bootpay().transactionConfirm();
returnfalse; 

Bootpay 창 닫기

onConfirm, onConfirmAsync등에서 진행중인 결제창을 닫을 때 사용하는 함수입니다. 서버인증으로 승인이 되었을 경우에, 클라이언트에서 창을 닫을 때 사용합니다.

Bootpay().dismiss(context);
returnfalse; 

자동결제 - 빌링키 발급 요청하기

voidgoBootpaySubscriptionUITest(BuildContext context) {
payload.subscriptionId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.pg ="키움페이";
payload.method ="카드자동"; // payload.price = 1000; 금액이 0 이상일 경우 빌링키 발급 후 결제가 진행됩니다.
payload.metadata = {
"callbackParam1":"value12",
"callbackParam2":"value34",
"callbackParam3":"value56",
"callbackParam4":"value78",
}; // 전달할 파라미터, 결제 후 되돌려 주는 값Bootpay().requestSubscription(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel 3: $data');
},
onError: (String data) {
print('------- onError 3: $data');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
//TODO - 원하시는 라우터로 페이지 이동
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);
}

본인인증

payload.pg ="다날";
payload.method ="본인인증";
payload.authenticationId =DateTime.now().millisecondsSinceEpoch.toString(); //주문번호, 개발사에서 고유값으로 지정해야함
payload.extra =Extra();
payload.extra?.openType ='iframe';
payload.items =null;
Bootpay().requestAuthentication(
context: context,
payload: payload,
showCloseButton:false,
// closeButton: Icon(Icons.close, size: 35.0, color: Colors.black54),
onCancel: (String data) {
print('------- onCancel: $data');
},
onError: (String data) {
print('------- onError: $data');
},
onClose: () {
print('------- onClose');
if (!kIsWeb) {
Bootpay().dismiss(context); //명시적으로 부트페이 뷰 종료 호출
}
},
onIssued: (String data) {
print('------- onIssued: $data');
},
onConfirm: (String data) { returntrue;
},
onDone: (String data) {
print('------- onDone: $data');
},
);

결제 진행 상태에 따라 LifeCycle 함수가 실행됩니다. 각 함수에 대한 상세 설명은 아래를 참고하세요.

onError 함수

결제 진행 중 오류가 발생된 경우 호출되는 함수입니다. 진행중 에러가 발생되는 경우는 다음과 같습니다.

  1. 부트페이 관리자에서 활성화 하지 않은 PG, 결제수단을 사용하고자 할 때
  2. PG에서 보내온 결제 정보를 부트페이 관리자에 잘못 입력하거나 입력하지 않은 경우
  3. 결제 진행 도중 한도초과, 카드정지, 휴대폰소액결제 막힘, 계좌이체 불가 등의 사유로 결제가 안되는 경우
  4. PG에서 리턴된 값이 다른 Client에 의해 변조된 경우

에러가 난 경우 해당 함수를 통해 관련 에러 메세지를 사용자에게 보여줄 수 있습니다.

data 포맷은 아래와 같습니다.

{
action: "BootpayError",
message: "카드사 거절",
receipt_id: "5fffab350c20b903e88a2cff"
}

onCancel 함수

결제 진행 중 사용자가 PG 결제창에서 취소 혹은 닫기 버튼을 눌러 나온 경우 입니다. ****

data 포맷은 아래와 같습니다.

{
action: "BootpayCancel",
message: "사용자가 결제를 취소하였습니다.",
receipt_id: "5fffab350c20b903e88a2cff"
}

onIssued 함수

가상계좌 발급이 완료되면 호출되는 함수입니다(가상계좌를 위한 Done). 가상계좌는 다른 결제와 다르게 입금할 계좌 번호 발급 이후 입금 후에 Feedback URL을 통해 통지가 됩니다. 발급된 가상계좌 정보를 issued 함수를 통해 확인하실 수 있습니다.

data 포맷은 아래와 같습니다.

{
account: "T0309260001169"
accounthodler: "한국사이버결제"
action: "BootpayBankReady"
bankcode: "BK03"
bankname: "기업은행"
expiredate: "2021-01-17 00:00:00"
item_name: "테스트 아이템"
method: "vbank"
method_name: "가상계좌"
order_id: "1610591554856"
metadata: null
payment_group: "vbank"
payment_group_name: "가상계좌"
payment_name: "가상계좌"
pg: "kcp"
pg_name: "KCP"
price: 3000
purchased_at: null
ready_url: "https://dev-app.bootpay.co.kr/bank/7o044QyX7p"
receipt_id: "5fffad430c20b903e88a2d17"
requested_at: "2021-01-14 11:32:35"
status: 2
tax_free: 0
url: "https://d-cdn.bootapi.com"
username: "홍길동"
}

onConfirm 함수

결제 승인이 되기 전 호출되는 함수입니다. 승인 이전 관련 로직을 서버 혹은 클라이언트에서 수행 후 결제를 승인해도 될 경우BootPay.transactionConfirm(data); 또는 return true;

코드를 실행해주시면 PG에서 결제 승인이 진행이 됩니다.

* 페이앱, 페이레터 PG는 이 함수가 실행되지 않고 바로 결제가 승인되는 PG 입니다. 참고해주시기 바랍니다.

data 포맷은 아래와 같습니다.

{
receipt_id: "5fffc0460c20b903e88a2d2c",
action: "BootpayConfirm"
}

onDone 함수

PG에서 거래 승인 이후에 호출 되는 함수입니다. 결제 완료 후 다음 결제 결과를 호출 할 수 있는 함수 입니다.

이 함수가 호출 된 후 반드시 REST API를 통해 결제검증을 수행해증야합니다. data 포맷은 아래와 같습니다.

{
action: "BootpayDone"
card_code: "CCKM",
card_name: "KB국민카드",
card_no: "0000120000000014",
card_quota: "00",
item_name: "테스트 아이템",
method: "card",
method_name: "카드결제",
order_id: "1610596422328",
payment_group: "card",
payment_group_name: "신용카드",
payment_name: "카드결제",
pg: "kcp",
pg_name: "KCP",
price: 100,
purchased_at: "2021-01-14 12:54:53",
receipt_id: "5fffc0460c20b903e88a2d2c",
receipt_url: "https://app.bootpay.co.kr/bill/UFMvZzJqSWNDNU9ERWh1YmUycU9hdnBkV29DVlJqdzUxRzZyNXRXbkNVZW81%0AQT09LS1XYlNJN1VoMDI4Q1hRdDh1LS10MEtZVmE4c1dyWHNHTXpZTVVLUk1R%0APT0%3D%0A",
requested_at: "2021-01-14 12:53:42",
status: 1,
tax_free: 0,
url: "https://d-cdn.bootapi.com"
}

WebView 프리워밍 (iOS/macOS)

iOS에서 WKWebView는 처음 로딩 시 GPU, Networking, WebContent 프로세스를 생성하는데 3-7초가 소요됩니다. Bootpay SDK는 자동으로 앱 시작 시 백그라운드에서 프로세스를 미리 생성하여 첫 결제 화면 로딩 속도를 개선합니다.

자동 프리워밍

SDK 초기화 시(첫 번째 Bootpay() 호출 시) 자동으로 프리워밍이 수행됩니다. 개발자가 별도로 호출할 필요가 없습니다.

메모리 관리 (선택사항)

메모리 부족 시 프리워밍된 리소스를 해제할 수 있습니다:

// 메모리 경고 수신 시 (선택사항)Bootpay.releaseWarmUp();

iOS AppDelegate에서 메모리 경고 시 자동 해제하도록 설정할 수도 있습니다:

// AppDelegate.swift
import bootpay_webview_flutter_wkwebview
overridefunc applicationDidReceiveMemoryWarning(_ application:UIApplication){
super.applicationDidReceiveMemoryWarning(application)BootpayWarmUpManager.shared.releaseWarmUp()}

효과

항목개선 효과
GPU 프로세스 초기화1-2초 단축
Networking 프로세스 초기화1-2초 단축
WebContent 프로세스 초기화1-3초 단축
총 개선 효과3-7초 단축

참고사항

  • iOS/macOS에서만 동작합니다. Android와 Web에서는 자동으로 무시됩니다.
  • 프리워밍은 자동으로 수행되므로 별도 설정이 필요 없습니다.
  • 두 번째 결제부터는 ProcessPool 공유로 자동으로 빠릅니다.

팝업 닫기(✕) 버튼 (iOS/Android)

결제창 안에서 window.open 또는 target="_blank" 로 열리는 팝업(주로 광고)은 앱 안에서 그대로 표시됩니다. 이런 팝업은 우측 상단에 뜨는 반투명 ✕ 버튼으로 사용자가 직접 닫을 수 있습니다.

광고는 차단되지 않습니다. 광고는 항상 인앱에 그대로 노출되며, 아래 설정은 "✕ 버튼을 언제 보여줄지"와 "팝업을 코드로 닫는 방법"만 제어합니다. 결제 PG 팝업은 window.close() 로 스스로 닫히므로 기본적으로 ✕ 가 붙지 않습니다.

import 'package:bootpay/bootpay.dart'; 후 아래 정적 메서드를 사용합니다.

✕ 버튼 노출 모드 설정

// 기본값(auto): 광고 도메인으로 분류된 팝업에만 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.auto);
// 모든 팝업에 ✕ 노출Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.always);
// ✕ 를 절대 노출하지 않음 (window.close 또는 closePopupWebView 로만 닫기)Bootpay.setPopupCloseButtonMode(BootpayPopupCloseButtonMode.never);
모드동작
BootpayPopupCloseButtonMode.auto기본값. 광고 도메인(addPopupAdHosts 목록)으로 분류된 팝업에만 ✕ 노출
BootpayPopupCloseButtonMode.always모든 팝업에 ✕ 노출
BootpayPopupCloseButtonMode.never✕ 를 노출하지 않음

광고 도메인 추가 (auto 모드용)

auto 모드에서 ✕ 를 띄울 광고 도메인을 런타임에 추가합니다. SDK 는 doubleclick.net / googleadservices.com / googlesyndication.com 등 주요 광고 네트워크 도메인을 기본 내장하고 있으며, 그 외 도메인을 더 넣고 싶을 때 사용합니다.

// host 의 부분 문자열로 대소문자 구분 없이 매칭됩니다.Bootpay.addPopupAdHosts(['ads.example.com', 'partner-ad.net']);

팝업을 코드로 닫기

광고 SDK 의 "광고 종료" 이벤트 등을 받았을 때, 사용자가 ✕ 를 누르지 않아도 현재 떠 있는 팝업을 닫을 수 있습니다. 메인 결제 WebView 에는 영향이 없으며, 열린 팝업이 없으면 아무 동작도 하지 않습니다.

Bootpay.closePopupWebView();
API설명
Bootpay.setPopupCloseButtonMode(mode)✕ 버튼 노출 모드 설정 (auto/always/never)
Bootpay.addPopupAdHosts(List<String> hosts)auto 모드에서 ✕ 를 띄울 광고 도메인 추가
Bootpay.closePopupWebView()현재 떠 있는 팝업을 프로그래매틱하게 닫기

참고: iOS / Android 전용입니다. Web 에서는 모두 no-op 으로 동작합니다.

Documentation

부트페이 개발매뉴얼을 참조해주세요

기술문의

채팅으로 문의

License

MIT License.

About

2세대 flutter api

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages