react-native-bootpay-api 13.13.42 → 13.13.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -0
- package/lib/Bootpay.js +4 -4
- package/lib/BootpayCommerce.js +14 -0
- package/lib/BootpayWidget.js +103 -0
- package/lib/CommerceTypes.js +1 -0
- package/lib/UserInfo.js +1 -1
- package/lib/WidgetTypes.js +1 -0
- package/lib/bootpayAnalytics.js +1 -1
- package/lib/index.js +1 -1
- package/package.json +40 -41
- package/react-native.config.js +1 -59
- package/src/Bootpay.tsx +20 -6
- package/src/BootpayCommerce.tsx +429 -0
- package/src/BootpayTypes.ts +19 -7
- package/src/BootpayWidget.tsx +1095 -0
- package/src/CommerceTypes.ts +123 -0
- package/src/UserInfo.ts +4 -1
- package/src/WidgetTypes.ts +110 -0
- package/src/__tests__/index.test.d.ts +1 -1
- package/src/__tests__/index.test.js +1 -1
- package/src/index.tsx +132 -2
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { ViewProps } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export interface CommerceEventData {
|
|
4
|
+
event: string;
|
|
5
|
+
receipt_id?: string;
|
|
6
|
+
order_id?: string;
|
|
7
|
+
request_id?: string;
|
|
8
|
+
price?: number;
|
|
9
|
+
message?: string;
|
|
10
|
+
code?: number | string;
|
|
11
|
+
metadata?: Record<string, unknown>;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface BootpayCommerceProps extends ViewProps {
|
|
16
|
+
ref?: React.RefObject<unknown>;
|
|
17
|
+
onCancel?: (data: CommerceEventData) => void;
|
|
18
|
+
onError?: (data: CommerceEventData) => void;
|
|
19
|
+
onDone?: (data: CommerceEventData) => void;
|
|
20
|
+
onIssued?: (data: CommerceEventData) => void; // 가상계좌 발급 완료 콜백 (iOS SDK와 동일)
|
|
21
|
+
onClose?: () => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class CommerceUser {
|
|
25
|
+
membershipType?: string = 'guest'; // 'guest' | 'member'
|
|
26
|
+
userId?: string;
|
|
27
|
+
name?: string;
|
|
28
|
+
phone?: string;
|
|
29
|
+
email?: string;
|
|
30
|
+
|
|
31
|
+
constructor() {}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class CommerceProduct {
|
|
35
|
+
productId: string = '';
|
|
36
|
+
duration: number = -1; // -1: 무기한
|
|
37
|
+
quantity: number = 1;
|
|
38
|
+
|
|
39
|
+
constructor() {}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class CommerceExtra {
|
|
43
|
+
separatelyConfirmed?: boolean = false;
|
|
44
|
+
createOrderImmediately?: boolean = true;
|
|
45
|
+
|
|
46
|
+
constructor() {}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class CommercePayload {
|
|
50
|
+
clientKey: string = '';
|
|
51
|
+
name?: string;
|
|
52
|
+
memo?: string;
|
|
53
|
+
user?: CommerceUser;
|
|
54
|
+
price: number = 0;
|
|
55
|
+
redirectUrl?: string;
|
|
56
|
+
usageApiUrl?: string;
|
|
57
|
+
useAutoLogin?: boolean = false;
|
|
58
|
+
requestId?: string;
|
|
59
|
+
useNotification?: boolean = false;
|
|
60
|
+
products?: CommerceProduct[];
|
|
61
|
+
metadata?: Record<string, string>;
|
|
62
|
+
metadataAny?: Record<string, unknown>;
|
|
63
|
+
extra?: CommerceExtra;
|
|
64
|
+
|
|
65
|
+
constructor() {}
|
|
66
|
+
|
|
67
|
+
toJSON(): Record<string, unknown> {
|
|
68
|
+
const json: Record<string, unknown> = {
|
|
69
|
+
client_key: this.clientKey,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// price > 0 일 때만 포함 (iOS SDK와 동일)
|
|
73
|
+
if (this.price > 0) json.price = this.price;
|
|
74
|
+
|
|
75
|
+
if (this.name) json.name = this.name;
|
|
76
|
+
if (this.memo) json.memo = this.memo;
|
|
77
|
+
if (this.redirectUrl) json.redirect_url = this.redirectUrl;
|
|
78
|
+
if (this.usageApiUrl) json.usage_api_url = this.usageApiUrl;
|
|
79
|
+
json.use_auto_login = this.useAutoLogin ?? false;
|
|
80
|
+
if (this.requestId) json.request_id = this.requestId;
|
|
81
|
+
json.use_notification = this.useNotification ?? false;
|
|
82
|
+
|
|
83
|
+
if (this.user) {
|
|
84
|
+
const userJson: Record<string, unknown> = {
|
|
85
|
+
membership_type: this.user.membershipType ?? 'guest',
|
|
86
|
+
};
|
|
87
|
+
if (this.user.userId) userJson.user_id = this.user.userId;
|
|
88
|
+
if (this.user.name) userJson.name = this.user.name;
|
|
89
|
+
if (this.user.phone) userJson.phone = this.user.phone;
|
|
90
|
+
if (this.user.email) userJson.email = this.user.email;
|
|
91
|
+
json.user = userJson;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (this.products && this.products.length > 0) {
|
|
95
|
+
json.products = this.products.map((p) => ({
|
|
96
|
+
product_id: p.productId,
|
|
97
|
+
duration: p.duration,
|
|
98
|
+
quantity: p.quantity,
|
|
99
|
+
}));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// metadataAny 우선, 없으면 metadata 사용 (iOS SDK와 동일)
|
|
103
|
+
if (this.metadataAny && Object.keys(this.metadataAny).length > 0) {
|
|
104
|
+
json.metadata = this.metadataAny;
|
|
105
|
+
} else if (this.metadata && Object.keys(this.metadata).length > 0) {
|
|
106
|
+
json.metadata = this.metadata;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (this.extra) {
|
|
110
|
+
const extraJson: Record<string, unknown> = {
|
|
111
|
+
separately_confirmed: this.extra.separatelyConfirmed ?? false,
|
|
112
|
+
create_order_immediately: this.extra.createOrderImmediately ?? true,
|
|
113
|
+
};
|
|
114
|
+
json.extra = extraJson;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return json;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
toJSONString(): string {
|
|
121
|
+
return JSON.stringify(this.toJSON());
|
|
122
|
+
}
|
|
123
|
+
}
|
package/src/UserInfo.ts
CHANGED
|
@@ -13,7 +13,10 @@ export default class UserInfo {
|
|
|
13
13
|
console.error(`Error setting Bootpay info for key ${key}:`, error);
|
|
14
14
|
|
|
15
15
|
// 특정 에러 코드에 따라 처리 (iOS와 Android 모두 고려)
|
|
16
|
-
if (
|
|
16
|
+
if (
|
|
17
|
+
error instanceof Error &&
|
|
18
|
+
error.message.includes('null is not an object')
|
|
19
|
+
) {
|
|
17
20
|
console.warn('Keychain configuration or capability might be missing.');
|
|
18
21
|
}
|
|
19
22
|
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget 관련 타입 정의
|
|
3
|
+
* Flutter의 widget_data.dart를 참고하여 구현
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface WidgetTerm {
|
|
7
|
+
term_id?: string;
|
|
8
|
+
pk?: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
agree?: boolean;
|
|
11
|
+
term_type?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface WidgetExtra {
|
|
15
|
+
direct_card_company?: string;
|
|
16
|
+
direct_card_quota?: number;
|
|
17
|
+
card_quota?: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface WidgetData {
|
|
21
|
+
pg?: string;
|
|
22
|
+
method?: string;
|
|
23
|
+
wallet_id?: string;
|
|
24
|
+
select_terms?: WidgetTerm[];
|
|
25
|
+
currency?: string; // KRW, USD
|
|
26
|
+
term_passed?: boolean;
|
|
27
|
+
completed?: boolean;
|
|
28
|
+
extra?: WidgetExtra;
|
|
29
|
+
// 네이티브 SDK와 호환을 위한 추가 필드
|
|
30
|
+
method_origin_symbol?: string;
|
|
31
|
+
method_symbol?: string;
|
|
32
|
+
easy_pay?: string;
|
|
33
|
+
card_quota?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type WidgetReadyCallback = () => void;
|
|
37
|
+
export type WidgetResizeCallback = (height: number) => void;
|
|
38
|
+
export type WidgetChangePaymentCallback = (data: WidgetData | null) => void;
|
|
39
|
+
export type WidgetChangeTermsCallback = (data: WidgetData | null) => void;
|
|
40
|
+
|
|
41
|
+
export interface BootpayWidgetProps {
|
|
42
|
+
// 앱 ID
|
|
43
|
+
ios_application_id?: string;
|
|
44
|
+
android_application_id?: string;
|
|
45
|
+
|
|
46
|
+
// Widget 전용 콜백
|
|
47
|
+
onWidgetReady?: WidgetReadyCallback;
|
|
48
|
+
onWidgetResize?: WidgetResizeCallback;
|
|
49
|
+
onWidgetChangePayment?: WidgetChangePaymentCallback;
|
|
50
|
+
onWidgetChangeTerms?: WidgetChangeTermsCallback;
|
|
51
|
+
|
|
52
|
+
// 결제 콜백
|
|
53
|
+
onCancel?: (data: unknown) => void;
|
|
54
|
+
onError?: (data: unknown) => void;
|
|
55
|
+
onIssued?: (data: unknown) => void;
|
|
56
|
+
onConfirm?: (data: unknown) => boolean;
|
|
57
|
+
onDone?: (data: unknown) => void;
|
|
58
|
+
onClose?: () => void;
|
|
59
|
+
|
|
60
|
+
// 스타일
|
|
61
|
+
height?: number;
|
|
62
|
+
style?: object;
|
|
63
|
+
widgetTop?: number; // Widget 위치 (위젯 모드에서 position: absolute의 top 값)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export class WidgetPayload {
|
|
67
|
+
widget_key?: string;
|
|
68
|
+
widget_sandbox?: boolean;
|
|
69
|
+
widget_use_terms?: boolean;
|
|
70
|
+
|
|
71
|
+
// 기본 Payload 필드
|
|
72
|
+
application_id?: string;
|
|
73
|
+
pg?: string;
|
|
74
|
+
method?: string;
|
|
75
|
+
methods?: string[];
|
|
76
|
+
order_name?: string;
|
|
77
|
+
price?: number;
|
|
78
|
+
tax_free?: number;
|
|
79
|
+
order_id?: string;
|
|
80
|
+
subscription_id?: string;
|
|
81
|
+
metadata?: Record<string, unknown>;
|
|
82
|
+
extra?: WidgetPayloadExtra;
|
|
83
|
+
|
|
84
|
+
constructor() {
|
|
85
|
+
this.widget_sandbox = false;
|
|
86
|
+
this.widget_use_terms = false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export class WidgetPayloadExtra {
|
|
91
|
+
app_scheme?: string;
|
|
92
|
+
card_quota?: string;
|
|
93
|
+
show_close_button?: boolean;
|
|
94
|
+
separately_confirmed?: boolean;
|
|
95
|
+
display_success_result?: boolean;
|
|
96
|
+
display_error_result?: boolean;
|
|
97
|
+
locale?: string;
|
|
98
|
+
offer_period?: string;
|
|
99
|
+
open_type?: string;
|
|
100
|
+
use_bootpay_inapp_sdk?: boolean; // native app에서 redirect를 완성도있게 지원하기 위한 옵션
|
|
101
|
+
redirect_url?: string;
|
|
102
|
+
|
|
103
|
+
constructor() {
|
|
104
|
+
this.separately_confirmed = true;
|
|
105
|
+
this.display_success_result = false;
|
|
106
|
+
this.display_error_result = false;
|
|
107
|
+
this.use_bootpay_inapp_sdk = true;
|
|
108
|
+
this.redirect_url = 'https://api.bootpay.co.kr/v2/callback';
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
//# sourceMappingURL=index.test.d.ts.map
|
|
1
|
+
//# sourceMappingURL=index.test.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
it.todo('write a test');
|
package/src/index.tsx
CHANGED
|
@@ -1,4 +1,134 @@
|
|
|
1
|
+
import { NativeModules, Platform } from 'react-native';
|
|
1
2
|
import { Bootpay } from './Bootpay';
|
|
2
|
-
import {
|
|
3
|
+
import { BootpayWidget } from './BootpayWidget';
|
|
4
|
+
import { BootpayCommerce } from './BootpayCommerce';
|
|
5
|
+
import {
|
|
6
|
+
Payload,
|
|
7
|
+
Extra,
|
|
8
|
+
Item,
|
|
9
|
+
User,
|
|
10
|
+
BootpayEventData,
|
|
11
|
+
BootpayTypesProps,
|
|
12
|
+
} from './BootpayTypes';
|
|
13
|
+
import {
|
|
14
|
+
WidgetData,
|
|
15
|
+
WidgetTerm,
|
|
16
|
+
WidgetExtra,
|
|
17
|
+
WidgetPayload,
|
|
18
|
+
WidgetPayloadExtra,
|
|
19
|
+
BootpayWidgetProps,
|
|
20
|
+
WidgetReadyCallback,
|
|
21
|
+
WidgetResizeCallback,
|
|
22
|
+
WidgetChangePaymentCallback,
|
|
23
|
+
WidgetChangeTermsCallback,
|
|
24
|
+
} from './WidgetTypes';
|
|
25
|
+
import {
|
|
26
|
+
CommercePayload,
|
|
27
|
+
CommerceUser,
|
|
28
|
+
CommerceProduct,
|
|
29
|
+
CommerceExtra,
|
|
30
|
+
CommerceEventData,
|
|
31
|
+
BootpayCommerceProps,
|
|
32
|
+
} from './CommerceTypes';
|
|
3
33
|
|
|
4
|
-
|
|
34
|
+
const BPCWebViewModule = NativeModules.BPCWebViewModule;
|
|
35
|
+
|
|
36
|
+
// 자동 warmUp 상태 관리
|
|
37
|
+
let _autoWarmUpCalled = false;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 내부 자동 warmUp 함수
|
|
41
|
+
* 패키지 import 시 자동으로 호출되어 WebView 프로세스를 미리 초기화합니다.
|
|
42
|
+
*/
|
|
43
|
+
const _autoWarmUp = (): void => {
|
|
44
|
+
if (_autoWarmUpCalled) return;
|
|
45
|
+
_autoWarmUpCalled = true;
|
|
46
|
+
|
|
47
|
+
// iOS/Android에서만 동작
|
|
48
|
+
if (Platform.OS !== 'ios' && Platform.OS !== 'android') return;
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
if (BPCWebViewModule?.warmUp) {
|
|
52
|
+
BPCWebViewModule.warmUp();
|
|
53
|
+
if (__DEV__) {
|
|
54
|
+
console.log('[Bootpay] WebView auto warm-up initiated');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} catch (e) {
|
|
58
|
+
// warmUp 실패해도 결제 기능에는 영향 없음
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* WebView 프로세스를 미리 초기화하여 첫 결제 화면 로딩 속도를 개선합니다.
|
|
64
|
+
*
|
|
65
|
+
* iOS: WKWebView의 첫 생성 시 GPU, Networking, WebContent 프로세스 초기화에 3-7초 소요
|
|
66
|
+
* Android: Chromium 엔진 초기화에 200-300ms 소요
|
|
67
|
+
*
|
|
68
|
+
* 참고: SDK import 시 자동으로 warmUp이 호출되므로, 일반적으로 명시적 호출이 필요하지 않습니다.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```tsx
|
|
72
|
+
* // 자동 warmUp이 기본 동작이므로, 별도 호출 불필요
|
|
73
|
+
* // 필요한 경우에만 명시적으로 호출
|
|
74
|
+
* import { warmUp } from 'react-native-bootpay-api';
|
|
75
|
+
* warmUp();
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export const warmUp = (): void => {
|
|
79
|
+
if (BPCWebViewModule?.warmUp) {
|
|
80
|
+
BPCWebViewModule.warmUp();
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 프리워밍된 WebView 리소스를 해제합니다.
|
|
86
|
+
* 메모리가 부족할 때 호출할 수 있습니다.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```tsx
|
|
90
|
+
* import { releaseWarmUp } from 'react-native-bootpay-api';
|
|
91
|
+
*
|
|
92
|
+
* // 메모리 정리가 필요할 때
|
|
93
|
+
* releaseWarmUp();
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export const releaseWarmUp = (): void => {
|
|
97
|
+
if (BPCWebViewModule?.releaseWarmUp) {
|
|
98
|
+
BPCWebViewModule.releaseWarmUp();
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// 패키지 import 시 자동으로 warmUp 실행
|
|
103
|
+
_autoWarmUp();
|
|
104
|
+
|
|
105
|
+
export {
|
|
106
|
+
// 기존 결제 컴포넌트
|
|
107
|
+
Bootpay,
|
|
108
|
+
Payload,
|
|
109
|
+
Extra,
|
|
110
|
+
Item,
|
|
111
|
+
User,
|
|
112
|
+
BootpayEventData,
|
|
113
|
+
BootpayTypesProps,
|
|
114
|
+
// Widget 컴포넌트
|
|
115
|
+
BootpayWidget,
|
|
116
|
+
WidgetData,
|
|
117
|
+
WidgetTerm,
|
|
118
|
+
WidgetExtra,
|
|
119
|
+
WidgetPayload,
|
|
120
|
+
WidgetPayloadExtra,
|
|
121
|
+
BootpayWidgetProps,
|
|
122
|
+
WidgetReadyCallback,
|
|
123
|
+
WidgetResizeCallback,
|
|
124
|
+
WidgetChangePaymentCallback,
|
|
125
|
+
WidgetChangeTermsCallback,
|
|
126
|
+
// Commerce 컴포넌트
|
|
127
|
+
BootpayCommerce,
|
|
128
|
+
CommercePayload,
|
|
129
|
+
CommerceUser,
|
|
130
|
+
CommerceProduct,
|
|
131
|
+
CommerceExtra,
|
|
132
|
+
CommerceEventData,
|
|
133
|
+
BootpayCommerceProps,
|
|
134
|
+
};
|