@apps-in-toss/native-modules 1.11.1 → 1.12.0
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/dist/index.cjs +33 -3
- package/dist/index.d.cts +170 -12
- package/dist/index.d.ts +170 -12
- package/dist/index.js +31 -1
- package/package.json +2 -2
- package/src/AppsInTossModule/native-modules/AppsInTossModule.ts +4 -0
- package/src/AppsInTossModule/native-modules/iap.ts +202 -13
package/dist/index.cjs
CHANGED
|
@@ -663,7 +663,8 @@ async function getTossShareLinkV1(path) {
|
|
|
663
663
|
}
|
|
664
664
|
|
|
665
665
|
// src/AppsInTossModule/native-modules/iap.ts
|
|
666
|
-
var
|
|
666
|
+
var noop2 = () => {
|
|
667
|
+
};
|
|
667
668
|
function iapCreateOneTimePurchaseOrder(params) {
|
|
668
669
|
const sku = params.sku ?? params.productId;
|
|
669
670
|
return AppsInTossModule.iapCreateOneTimePurchaseOrder({ productId: sku });
|
|
@@ -697,7 +698,7 @@ function createOneTimePurchaseOrder(params) {
|
|
|
697
698
|
ios: "5.219.0"
|
|
698
699
|
});
|
|
699
700
|
if (!isIAPSupported) {
|
|
700
|
-
return
|
|
701
|
+
return noop2;
|
|
701
702
|
}
|
|
702
703
|
const isProcessProductGrantSupported = isMinVersionSupported({
|
|
703
704
|
android: "5.231.1",
|
|
@@ -716,7 +717,7 @@ function createOneTimePurchaseOrder(params) {
|
|
|
716
717
|
}).catch((error) => {
|
|
717
718
|
onError(error);
|
|
718
719
|
});
|
|
719
|
-
return
|
|
720
|
+
return noop2;
|
|
720
721
|
};
|
|
721
722
|
return v1();
|
|
722
723
|
}
|
|
@@ -778,8 +779,37 @@ async function completeProductGrant(params) {
|
|
|
778
779
|
}
|
|
779
780
|
return AppsInTossModule.completeProductGrant(params);
|
|
780
781
|
}
|
|
782
|
+
function createSubscriptionPurchaseOrder(params) {
|
|
783
|
+
const isSupported = isMinVersionSupported({
|
|
784
|
+
android: "5.248.0",
|
|
785
|
+
ios: "5.249.0"
|
|
786
|
+
});
|
|
787
|
+
if (!isSupported) {
|
|
788
|
+
return noop2;
|
|
789
|
+
}
|
|
790
|
+
const { options, onEvent, onError } = params;
|
|
791
|
+
const { sku, offerId, processProductGrant: processProductGrant2 } = options;
|
|
792
|
+
const unregisterCallbacks = INTERNAL__appBridgeHandler.invokeAppBridgeMethod(
|
|
793
|
+
"requestSubscriptionPurchase",
|
|
794
|
+
{ sku, offerId: offerId ?? null },
|
|
795
|
+
{
|
|
796
|
+
onPurchased: async (purchasedParams) => {
|
|
797
|
+
const isProductGranted = await processProductGrant2(purchasedParams);
|
|
798
|
+
await AppsInTossModule.processProductGrant({ orderId: purchasedParams.orderId, isProductGranted });
|
|
799
|
+
},
|
|
800
|
+
onSuccess: (result) => {
|
|
801
|
+
onEvent({ type: "success", data: result });
|
|
802
|
+
},
|
|
803
|
+
onError: (error) => {
|
|
804
|
+
onError(error);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
);
|
|
808
|
+
return unregisterCallbacks;
|
|
809
|
+
}
|
|
781
810
|
var IAP = {
|
|
782
811
|
createOneTimePurchaseOrder,
|
|
812
|
+
createSubscriptionPurchaseOrder,
|
|
783
813
|
getProductItemList,
|
|
784
814
|
getPendingOrders,
|
|
785
815
|
getCompletedOrRefundedOrders,
|
package/dist/index.d.cts
CHANGED
|
@@ -976,7 +976,7 @@ interface IapCreateOneTimePurchaseOrderResult {
|
|
|
976
976
|
fraction: number;
|
|
977
977
|
miniAppIconUrl: string | null;
|
|
978
978
|
}
|
|
979
|
-
interface
|
|
979
|
+
interface OneTimePurchaseSuccessEvent {
|
|
980
980
|
type: 'success';
|
|
981
981
|
data: IapCreateOneTimePurchaseOrderResult;
|
|
982
982
|
}
|
|
@@ -1002,12 +1002,12 @@ interface IapCreateOneTimePurchaseOrderOptions {
|
|
|
1002
1002
|
orderId: string;
|
|
1003
1003
|
}) => boolean | Promise<boolean>;
|
|
1004
1004
|
};
|
|
1005
|
-
onEvent: (event:
|
|
1005
|
+
onEvent: (event: OneTimePurchaseSuccessEvent) => void | Promise<void>;
|
|
1006
1006
|
onError: (error: unknown) => void | Promise<void>;
|
|
1007
1007
|
}
|
|
1008
1008
|
interface IapRequestOneTimePurchaseOptions {
|
|
1009
1009
|
options: Sku;
|
|
1010
|
-
onEvent: (event: PurchasedEvent |
|
|
1010
|
+
onEvent: (event: PurchasedEvent | OneTimePurchaseSuccessEvent) => void | Promise<void>;
|
|
1011
1011
|
onError: (error: unknown) => void | Promise<void>;
|
|
1012
1012
|
}
|
|
1013
1013
|
declare function iapCreateOneTimePurchaseOrder(params: Sku): Promise<IapCreateOneTimePurchaseOrderResult>;
|
|
@@ -1076,24 +1076,88 @@ declare function requestOneTimePurchase(params: IapRequestOneTimePurchaseOptions
|
|
|
1076
1076
|
* ```
|
|
1077
1077
|
*/
|
|
1078
1078
|
declare function createOneTimePurchaseOrder(params: IapCreateOneTimePurchaseOrderOptions): () => void;
|
|
1079
|
+
interface BasicProductListItem {
|
|
1080
|
+
sku: string;
|
|
1081
|
+
displayAmount: string;
|
|
1082
|
+
displayName: string;
|
|
1083
|
+
iconUrl: string;
|
|
1084
|
+
description: string;
|
|
1085
|
+
}
|
|
1086
|
+
type Offer = {
|
|
1087
|
+
type: 'FREE_TRIAL';
|
|
1088
|
+
offerId: string;
|
|
1089
|
+
period: string;
|
|
1090
|
+
} | {
|
|
1091
|
+
type: 'NEW_SUBSCRIPTION';
|
|
1092
|
+
offerId: string;
|
|
1093
|
+
period: string;
|
|
1094
|
+
displayAmount: string;
|
|
1095
|
+
} | {
|
|
1096
|
+
type: 'RETURNING';
|
|
1097
|
+
offerId: string;
|
|
1098
|
+
period: string;
|
|
1099
|
+
displayAmount: string;
|
|
1100
|
+
};
|
|
1079
1101
|
/**
|
|
1080
1102
|
* @public
|
|
1081
1103
|
* @category 인앱결제
|
|
1082
|
-
* @name
|
|
1083
|
-
* @description
|
|
1104
|
+
* @name ConsumableProductListItem
|
|
1105
|
+
* @description 소모품 상품 정보를 담은 객체예요.
|
|
1084
1106
|
* @property {string} sku - 상품의 고유 ID예요.
|
|
1107
|
+
* @property {string} type - 상품의 유형이에요. `CONSUMABLE`을 나타내요.
|
|
1085
1108
|
* @property {string} displayName - 화면에 표시할 상품 이름이에요. 상품 이름은 앱인토스 콘솔에서 설정한 값이에요.
|
|
1086
1109
|
* @property {string} displayAmount - 통화 단위가 포함된 가격 정보예요. 예를 들어 `1,000원`으로 가격과 통화가 함께 표시돼요.
|
|
1087
1110
|
* @property {string} iconUrl - 상품 아이콘 이미지의 URL이에요. 아이콘은 앱인토스 콘솔에서 설정한 이미지예요.
|
|
1088
1111
|
* @property {string} description - 상품에 대한 설명이에요. 설명은 앱인토스 콘솔에서 설정한 값이에요.
|
|
1089
1112
|
*/
|
|
1090
|
-
interface
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1113
|
+
interface ConsumableProductListItem extends BasicProductListItem {
|
|
1114
|
+
type: 'CONSUMABLE';
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* @public
|
|
1118
|
+
* @category 인앱결제
|
|
1119
|
+
* @name NonConsumableProductListItem
|
|
1120
|
+
* @description 비소모품 상품 정보를 담은 객체예요.
|
|
1121
|
+
* @property {string} sku - 상품의 고유 ID예요.
|
|
1122
|
+
* @property {string} type - 상품의 유형이에요. `NON_CONSUMABLE`을 나타내요.
|
|
1123
|
+
* @property {string} displayName - 화면에 표시할 상품 이름이에요. 상품 이름은 앱인토스 콘솔에서 설정한 값이에요.
|
|
1124
|
+
* @property {string} displayAmount - 통화 단위가 포함된 가격 정보예요. 예를 들어 `1,000원`으로 가격과 통화가 함께 표시돼요.
|
|
1125
|
+
* @property {string} iconUrl - 상품 아이콘 이미지의 URL이에요. 아이콘은 앱인토스 콘솔에서 설정한 이미지예요.
|
|
1126
|
+
* @property {string} description - 상품에 대한 설명이에요. 설명은 앱인토스 콘솔에서 설정한 값이에요.
|
|
1127
|
+
*/
|
|
1128
|
+
interface NonConsumableProductListItem extends BasicProductListItem {
|
|
1129
|
+
type: 'NON_CONSUMABLE';
|
|
1096
1130
|
}
|
|
1131
|
+
/**
|
|
1132
|
+
* @public
|
|
1133
|
+
* @category 인앱결제
|
|
1134
|
+
* @name SubscriptionProductListItem
|
|
1135
|
+
* @description 자동 갱신 구독 상품 정보를 담은 객체예요.
|
|
1136
|
+
* @property {string} sku - 상품의 고유 ID예요.
|
|
1137
|
+
* @property {string} type - 상품의 유형이에요. `SUBSCRIPTION`을 나타내요.
|
|
1138
|
+
* @property {string} displayName - 화면에 표시할 상품 이름이에요. 상품 이름은 앱인토스 콘솔에서 설정한 값이에요.
|
|
1139
|
+
* @property {string} displayAmount - 통화 단위가 포함된 가격 정보예요. 예를 들어 `1,000원`으로 가격과 통화가 함께 표시돼요.
|
|
1140
|
+
* @property {string} iconUrl - 상품 아이콘 이미지의 URL이에요. 아이콘은 앱인토스 콘솔에서 설정한 이미지예요.
|
|
1141
|
+
* @property {string} description - 상품에 대한 설명이에요. 설명은 앱인토스 콘솔에서 설정한 값이에요.
|
|
1142
|
+
* @property {string} renewalCycle - 구독 갱신 주기이에요. `WEEKLY`, `MONTHLY`, `YEARLY` 중 하나를 나타내요.
|
|
1143
|
+
* @property {Offer[]} offers - 구독 혜택 옵션 목록이에요. 각 옵션은 하나의 구독 혜택을 나타내요.
|
|
1144
|
+
* @property {string} offers[].type - 구독 혜택 옵션 유형이에요. `FREE_TRIAL`, `NEW_SUBSCRIPTION`, `RETURNING` 중 하나를 나타내요.
|
|
1145
|
+
* @property {string} offers[].offerId - 구독 혜택 옵션의 고유 ID예요.
|
|
1146
|
+
* @property {string} offers[].period - 구독 혜택 옵션의 적용 기간이에요.
|
|
1147
|
+
* @property {string} offers[].displayAmount - 통화 단위가 포함된 구독 혜택 옵션의 가격 정보예요. 예를 들어 `1,000원`으로 가격과 통화가 함께 표시돼요.
|
|
1148
|
+
*/
|
|
1149
|
+
interface SubscriptionProductListItem extends BasicProductListItem {
|
|
1150
|
+
type: 'SUBSCRIPTION';
|
|
1151
|
+
renewalCycle: 'WEEKLY' | 'MONTHLY' | 'YEARLY';
|
|
1152
|
+
offers?: Offer[];
|
|
1153
|
+
}
|
|
1154
|
+
/**
|
|
1155
|
+
* @public
|
|
1156
|
+
* @category 인앱결제
|
|
1157
|
+
* @name IapProductListItem
|
|
1158
|
+
* @description 인앱결제로 구매할 수 있는 상품 하나의 정보를 담은 객체예요. 상품 목록을 화면에 표시할 때 사용해요.
|
|
1159
|
+
*/
|
|
1160
|
+
type IapProductListItem = ConsumableProductListItem | NonConsumableProductListItem | SubscriptionProductListItem;
|
|
1097
1161
|
/**
|
|
1098
1162
|
* @public
|
|
1099
1163
|
* @category 인앱결제
|
|
@@ -1272,6 +1336,90 @@ declare function completeProductGrant(params: {
|
|
|
1272
1336
|
orderId: string;
|
|
1273
1337
|
};
|
|
1274
1338
|
}): Promise<boolean | undefined>;
|
|
1339
|
+
/**
|
|
1340
|
+
* @public
|
|
1341
|
+
* @category 인앱결제
|
|
1342
|
+
* @name CreateSubscriptionPurchaseOrderOptions
|
|
1343
|
+
* @description 구독 인앱결제를 생성할 때 필요한 옵션이에요.
|
|
1344
|
+
* @property {object} options - 결제할 구독 상품의 정보예요.
|
|
1345
|
+
* @property {string} options.sku - 주문할 구독 상품의 고유 ID예요.
|
|
1346
|
+
* @property {string | null} [options.offerId] - 적용할 offer ID예요. 없으면 기본 가격이 적용돼요.
|
|
1347
|
+
* @property {(params: { orderId: string, subscriptionId?: string }) => boolean | Promise<boolean>} options.processProductGrant - 주문이 만들어진 뒤 실제로 상품을 지급할 때 호출해요.
|
|
1348
|
+
* @property {(event: SubscriptionSuccessEvent) => void | Promise<void>} onEvent - 결제가 성공했을 때 호출해요.
|
|
1349
|
+
* @property {(error: unknown) => void | Promise<void>} onError - 결제 과정에서 에러가 발생했을 때 호출해요.
|
|
1350
|
+
*/
|
|
1351
|
+
interface CreateSubscriptionPurchaseOrderOptions {
|
|
1352
|
+
options: {
|
|
1353
|
+
sku: string;
|
|
1354
|
+
offerId?: string | null;
|
|
1355
|
+
processProductGrant: (params: {
|
|
1356
|
+
orderId: string;
|
|
1357
|
+
subscriptionId?: string;
|
|
1358
|
+
}) => boolean | Promise<boolean>;
|
|
1359
|
+
};
|
|
1360
|
+
onEvent: (event: SubscriptionSuccessEvent) => void | Promise<void>;
|
|
1361
|
+
onError: (error: unknown) => void | Promise<void>;
|
|
1362
|
+
}
|
|
1363
|
+
/**
|
|
1364
|
+
* @public
|
|
1365
|
+
* @category 인앱결제
|
|
1366
|
+
* @name IapCreateSubscriptionPurchaseOrderResult
|
|
1367
|
+
* @description 구독 인앱결제가 완료되면 결제 세부 정보와 상품 정보를 담아 반환해요. `IapCreateOneTimePurchaseOrderResult`와 동일한 구조예요.
|
|
1368
|
+
*/
|
|
1369
|
+
type IapCreateSubscriptionPurchaseOrderResult = IapCreateOneTimePurchaseOrderResult;
|
|
1370
|
+
interface SubscriptionSuccessEvent {
|
|
1371
|
+
type: 'success';
|
|
1372
|
+
data: IapCreateSubscriptionPurchaseOrderResult;
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
* @public
|
|
1376
|
+
* @category 인앱결제
|
|
1377
|
+
* @name createSubscriptionPurchaseOrder
|
|
1378
|
+
* @description
|
|
1379
|
+
* 구독 인앱결제 주문서 페이지로 이동해요. 사용자가 구독 상품 구매 버튼을 누르는 상황 등에 사용할 수 있어요.
|
|
1380
|
+
* @param {CreateSubscriptionPurchaseOrderOptions} params - 구독 인앱결제를 생성할 때 필요한 정보예요.
|
|
1381
|
+
* @returns {() => void} 앱브릿지 cleanup 함수를 반환해요. 인앱결제 기능이 끝나면 반드시 이 함수를 호출해서 리소스를 해제해야 해요.
|
|
1382
|
+
*
|
|
1383
|
+
* @example
|
|
1384
|
+
* ### 구독 인앱결제 주문서 페이지로 이동하기
|
|
1385
|
+
*
|
|
1386
|
+
* ```tsx
|
|
1387
|
+
* import { IAP } from "@apps-in-toss/web-framework";
|
|
1388
|
+
* import { Button } from "@toss/tds-react-native";
|
|
1389
|
+
* import { useCallback } from "react";
|
|
1390
|
+
*
|
|
1391
|
+
* interface Props {
|
|
1392
|
+
* sku: string;
|
|
1393
|
+
* offerId?: string;
|
|
1394
|
+
* }
|
|
1395
|
+
*
|
|
1396
|
+
* function SubscriptionPurchaseButton({ sku, offerId }: Props) {
|
|
1397
|
+
* const handleClick = useCallback(async () => {
|
|
1398
|
+
* const cleanup = IAP.createSubscriptionPurchaseOrder({
|
|
1399
|
+
* options: {
|
|
1400
|
+
* sku,
|
|
1401
|
+
* offerId,
|
|
1402
|
+
* processProductGrant: ({ orderId, subscriptionId }) => {
|
|
1403
|
+
* // 상품 지급 로직 작성
|
|
1404
|
+
* return true; // 상품 지급 여부
|
|
1405
|
+
* },
|
|
1406
|
+
* },
|
|
1407
|
+
* onEvent: (event) => {
|
|
1408
|
+
* console.log(event);
|
|
1409
|
+
* },
|
|
1410
|
+
* onError: (error) => {
|
|
1411
|
+
* console.error(error);
|
|
1412
|
+
* },
|
|
1413
|
+
* });
|
|
1414
|
+
*
|
|
1415
|
+
* return cleanup;
|
|
1416
|
+
* }, [sku, offerId]);
|
|
1417
|
+
*
|
|
1418
|
+
* return <Button onClick={handleClick}>구독하기</Button>;
|
|
1419
|
+
* }
|
|
1420
|
+
* ```
|
|
1421
|
+
*/
|
|
1422
|
+
declare function createSubscriptionPurchaseOrder(params: CreateSubscriptionPurchaseOrderOptions): () => void;
|
|
1275
1423
|
/**
|
|
1276
1424
|
* @public
|
|
1277
1425
|
* @category 인앱결제
|
|
@@ -1285,6 +1433,7 @@ declare function completeProductGrant(params: {
|
|
|
1285
1433
|
*/
|
|
1286
1434
|
declare const IAP: {
|
|
1287
1435
|
createOneTimePurchaseOrder: typeof createOneTimePurchaseOrder;
|
|
1436
|
+
createSubscriptionPurchaseOrder: typeof createSubscriptionPurchaseOrder;
|
|
1288
1437
|
getProductItemList: typeof getProductItemList;
|
|
1289
1438
|
getPendingOrders: typeof getPendingOrders;
|
|
1290
1439
|
getCompletedOrRefundedOrders: typeof getCompletedOrRefundedOrders;
|
|
@@ -1469,6 +1618,15 @@ interface Spec extends TurboModule {
|
|
|
1469
1618
|
orderId: string;
|
|
1470
1619
|
}) => void;
|
|
1471
1620
|
}) => () => void;
|
|
1621
|
+
requestSubscriptionPurchase: (params: {
|
|
1622
|
+
sku: string;
|
|
1623
|
+
offerId: string | null;
|
|
1624
|
+
}, fallbacks: {
|
|
1625
|
+
onPurchased: (params: {
|
|
1626
|
+
orderId: string;
|
|
1627
|
+
subscriptionId?: string;
|
|
1628
|
+
}) => void;
|
|
1629
|
+
}) => () => void;
|
|
1472
1630
|
processProductGrant: (params: {
|
|
1473
1631
|
orderId: string;
|
|
1474
1632
|
isProductGranted: boolean;
|
|
@@ -3004,4 +3162,4 @@ declare const INTERNAL__module: {
|
|
|
3004
3162
|
tossCoreEventLog: typeof tossCoreEventLog;
|
|
3005
3163
|
};
|
|
3006
3164
|
|
|
3007
|
-
export { AppsInTossModule, type AppsInTossSignTossCertParams, BedrockCoreModule, BedrockModule, type CheckoutPaymentOptions, type CheckoutPaymentResult, type CompletedOrRefundedOrdersResult, type ContactsViralParams, type EventLogParams, type GameCenterGameProfileResponse, type GetUserKeyForGameErrorResponse, type GetUserKeyForGameResponse, type GetUserKeyForGameSuccessResponse, GoogleAdMob, type GrantPromotionRewardForGameErrorResponse, type GrantPromotionRewardForGameErrorResult, type GrantPromotionRewardForGameResponse, type GrantPromotionRewardForGameSuccessResponse, type HapticFeedbackType, IAP, AppsInTossModuleInstance as INTERNAL__AppsInTossModule, INTERNAL__appBridgeHandler, INTERNAL__module, type IapCreateOneTimePurchaseOrderOptions, type IapCreateOneTimePurchaseOrderResult, type IapProductListItem, type NetworkStatus, type Primitive, type SaveBase64DataParams, Storage, type SubmitGameCenterLeaderBoardScoreResponse, TossPay, type UpdateLocationEventEmitter, appLogin, appsInTossEvent, appsInTossSignTossCert, closeView, contactsViral, eventLog, fetchAlbumPhotos, fetchContacts, generateHapticFeedback, getClipboardText, getCurrentLocation, getDeviceId, getGameCenterGameProfile, getIsTossLoginIntegratedService, getLocale, getNetworkStatus, getOperationalEnvironment, getPlatformOS, getSchemeUri, getServerTime, getTossAppVersion, getTossShareLink, getUserKeyForGame, grantPromotionRewardForGame, iapCreateOneTimePurchaseOrder, isMinVersionSupported, onVisibilityChangedByTransparentServiceWeb, openCamera, openGameCenterLeaderboard, openURL, processProductGrant, requestOneTimePurchase, saveBase64Data, setClipboardText, setDeviceOrientation, setIosSwipeGestureEnabled, setScreenAwakeMode, setSecureScreen, share, startUpdateLocation, submitGameCenterLeaderBoardScore };
|
|
3165
|
+
export { AppsInTossModule, type AppsInTossSignTossCertParams, BedrockCoreModule, BedrockModule, type CheckoutPaymentOptions, type CheckoutPaymentResult, type CompletedOrRefundedOrdersResult, type ConsumableProductListItem, type ContactsViralParams, type CreateSubscriptionPurchaseOrderOptions, type EventLogParams, type GameCenterGameProfileResponse, type GetUserKeyForGameErrorResponse, type GetUserKeyForGameResponse, type GetUserKeyForGameSuccessResponse, GoogleAdMob, type GrantPromotionRewardForGameErrorResponse, type GrantPromotionRewardForGameErrorResult, type GrantPromotionRewardForGameResponse, type GrantPromotionRewardForGameSuccessResponse, type HapticFeedbackType, IAP, AppsInTossModuleInstance as INTERNAL__AppsInTossModule, INTERNAL__appBridgeHandler, INTERNAL__module, type IapCreateOneTimePurchaseOrderOptions, type IapCreateOneTimePurchaseOrderResult, type IapCreateSubscriptionPurchaseOrderResult, type IapProductListItem, type NetworkStatus, type NonConsumableProductListItem, type Primitive, type SaveBase64DataParams, Storage, type SubmitGameCenterLeaderBoardScoreResponse, type SubscriptionProductListItem, TossPay, type UpdateLocationEventEmitter, appLogin, appsInTossEvent, appsInTossSignTossCert, closeView, contactsViral, eventLog, fetchAlbumPhotos, fetchContacts, generateHapticFeedback, getClipboardText, getCurrentLocation, getDeviceId, getGameCenterGameProfile, getIsTossLoginIntegratedService, getLocale, getNetworkStatus, getOperationalEnvironment, getPlatformOS, getSchemeUri, getServerTime, getTossAppVersion, getTossShareLink, getUserKeyForGame, grantPromotionRewardForGame, iapCreateOneTimePurchaseOrder, isMinVersionSupported, onVisibilityChangedByTransparentServiceWeb, openCamera, openGameCenterLeaderboard, openURL, processProductGrant, requestOneTimePurchase, saveBase64Data, setClipboardText, setDeviceOrientation, setIosSwipeGestureEnabled, setScreenAwakeMode, setSecureScreen, share, startUpdateLocation, submitGameCenterLeaderBoardScore };
|
package/dist/index.d.ts
CHANGED
|
@@ -976,7 +976,7 @@ interface IapCreateOneTimePurchaseOrderResult {
|
|
|
976
976
|
fraction: number;
|
|
977
977
|
miniAppIconUrl: string | null;
|
|
978
978
|
}
|
|
979
|
-
interface
|
|
979
|
+
interface OneTimePurchaseSuccessEvent {
|
|
980
980
|
type: 'success';
|
|
981
981
|
data: IapCreateOneTimePurchaseOrderResult;
|
|
982
982
|
}
|
|
@@ -1002,12 +1002,12 @@ interface IapCreateOneTimePurchaseOrderOptions {
|
|
|
1002
1002
|
orderId: string;
|
|
1003
1003
|
}) => boolean | Promise<boolean>;
|
|
1004
1004
|
};
|
|
1005
|
-
onEvent: (event:
|
|
1005
|
+
onEvent: (event: OneTimePurchaseSuccessEvent) => void | Promise<void>;
|
|
1006
1006
|
onError: (error: unknown) => void | Promise<void>;
|
|
1007
1007
|
}
|
|
1008
1008
|
interface IapRequestOneTimePurchaseOptions {
|
|
1009
1009
|
options: Sku;
|
|
1010
|
-
onEvent: (event: PurchasedEvent |
|
|
1010
|
+
onEvent: (event: PurchasedEvent | OneTimePurchaseSuccessEvent) => void | Promise<void>;
|
|
1011
1011
|
onError: (error: unknown) => void | Promise<void>;
|
|
1012
1012
|
}
|
|
1013
1013
|
declare function iapCreateOneTimePurchaseOrder(params: Sku): Promise<IapCreateOneTimePurchaseOrderResult>;
|
|
@@ -1076,24 +1076,88 @@ declare function requestOneTimePurchase(params: IapRequestOneTimePurchaseOptions
|
|
|
1076
1076
|
* ```
|
|
1077
1077
|
*/
|
|
1078
1078
|
declare function createOneTimePurchaseOrder(params: IapCreateOneTimePurchaseOrderOptions): () => void;
|
|
1079
|
+
interface BasicProductListItem {
|
|
1080
|
+
sku: string;
|
|
1081
|
+
displayAmount: string;
|
|
1082
|
+
displayName: string;
|
|
1083
|
+
iconUrl: string;
|
|
1084
|
+
description: string;
|
|
1085
|
+
}
|
|
1086
|
+
type Offer = {
|
|
1087
|
+
type: 'FREE_TRIAL';
|
|
1088
|
+
offerId: string;
|
|
1089
|
+
period: string;
|
|
1090
|
+
} | {
|
|
1091
|
+
type: 'NEW_SUBSCRIPTION';
|
|
1092
|
+
offerId: string;
|
|
1093
|
+
period: string;
|
|
1094
|
+
displayAmount: string;
|
|
1095
|
+
} | {
|
|
1096
|
+
type: 'RETURNING';
|
|
1097
|
+
offerId: string;
|
|
1098
|
+
period: string;
|
|
1099
|
+
displayAmount: string;
|
|
1100
|
+
};
|
|
1079
1101
|
/**
|
|
1080
1102
|
* @public
|
|
1081
1103
|
* @category 인앱결제
|
|
1082
|
-
* @name
|
|
1083
|
-
* @description
|
|
1104
|
+
* @name ConsumableProductListItem
|
|
1105
|
+
* @description 소모품 상품 정보를 담은 객체예요.
|
|
1084
1106
|
* @property {string} sku - 상품의 고유 ID예요.
|
|
1107
|
+
* @property {string} type - 상품의 유형이에요. `CONSUMABLE`을 나타내요.
|
|
1085
1108
|
* @property {string} displayName - 화면에 표시할 상품 이름이에요. 상품 이름은 앱인토스 콘솔에서 설정한 값이에요.
|
|
1086
1109
|
* @property {string} displayAmount - 통화 단위가 포함된 가격 정보예요. 예를 들어 `1,000원`으로 가격과 통화가 함께 표시돼요.
|
|
1087
1110
|
* @property {string} iconUrl - 상품 아이콘 이미지의 URL이에요. 아이콘은 앱인토스 콘솔에서 설정한 이미지예요.
|
|
1088
1111
|
* @property {string} description - 상품에 대한 설명이에요. 설명은 앱인토스 콘솔에서 설정한 값이에요.
|
|
1089
1112
|
*/
|
|
1090
|
-
interface
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1113
|
+
interface ConsumableProductListItem extends BasicProductListItem {
|
|
1114
|
+
type: 'CONSUMABLE';
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* @public
|
|
1118
|
+
* @category 인앱결제
|
|
1119
|
+
* @name NonConsumableProductListItem
|
|
1120
|
+
* @description 비소모품 상품 정보를 담은 객체예요.
|
|
1121
|
+
* @property {string} sku - 상품의 고유 ID예요.
|
|
1122
|
+
* @property {string} type - 상품의 유형이에요. `NON_CONSUMABLE`을 나타내요.
|
|
1123
|
+
* @property {string} displayName - 화면에 표시할 상품 이름이에요. 상품 이름은 앱인토스 콘솔에서 설정한 값이에요.
|
|
1124
|
+
* @property {string} displayAmount - 통화 단위가 포함된 가격 정보예요. 예를 들어 `1,000원`으로 가격과 통화가 함께 표시돼요.
|
|
1125
|
+
* @property {string} iconUrl - 상품 아이콘 이미지의 URL이에요. 아이콘은 앱인토스 콘솔에서 설정한 이미지예요.
|
|
1126
|
+
* @property {string} description - 상품에 대한 설명이에요. 설명은 앱인토스 콘솔에서 설정한 값이에요.
|
|
1127
|
+
*/
|
|
1128
|
+
interface NonConsumableProductListItem extends BasicProductListItem {
|
|
1129
|
+
type: 'NON_CONSUMABLE';
|
|
1096
1130
|
}
|
|
1131
|
+
/**
|
|
1132
|
+
* @public
|
|
1133
|
+
* @category 인앱결제
|
|
1134
|
+
* @name SubscriptionProductListItem
|
|
1135
|
+
* @description 자동 갱신 구독 상품 정보를 담은 객체예요.
|
|
1136
|
+
* @property {string} sku - 상품의 고유 ID예요.
|
|
1137
|
+
* @property {string} type - 상품의 유형이에요. `SUBSCRIPTION`을 나타내요.
|
|
1138
|
+
* @property {string} displayName - 화면에 표시할 상품 이름이에요. 상품 이름은 앱인토스 콘솔에서 설정한 값이에요.
|
|
1139
|
+
* @property {string} displayAmount - 통화 단위가 포함된 가격 정보예요. 예를 들어 `1,000원`으로 가격과 통화가 함께 표시돼요.
|
|
1140
|
+
* @property {string} iconUrl - 상품 아이콘 이미지의 URL이에요. 아이콘은 앱인토스 콘솔에서 설정한 이미지예요.
|
|
1141
|
+
* @property {string} description - 상품에 대한 설명이에요. 설명은 앱인토스 콘솔에서 설정한 값이에요.
|
|
1142
|
+
* @property {string} renewalCycle - 구독 갱신 주기이에요. `WEEKLY`, `MONTHLY`, `YEARLY` 중 하나를 나타내요.
|
|
1143
|
+
* @property {Offer[]} offers - 구독 혜택 옵션 목록이에요. 각 옵션은 하나의 구독 혜택을 나타내요.
|
|
1144
|
+
* @property {string} offers[].type - 구독 혜택 옵션 유형이에요. `FREE_TRIAL`, `NEW_SUBSCRIPTION`, `RETURNING` 중 하나를 나타내요.
|
|
1145
|
+
* @property {string} offers[].offerId - 구독 혜택 옵션의 고유 ID예요.
|
|
1146
|
+
* @property {string} offers[].period - 구독 혜택 옵션의 적용 기간이에요.
|
|
1147
|
+
* @property {string} offers[].displayAmount - 통화 단위가 포함된 구독 혜택 옵션의 가격 정보예요. 예를 들어 `1,000원`으로 가격과 통화가 함께 표시돼요.
|
|
1148
|
+
*/
|
|
1149
|
+
interface SubscriptionProductListItem extends BasicProductListItem {
|
|
1150
|
+
type: 'SUBSCRIPTION';
|
|
1151
|
+
renewalCycle: 'WEEKLY' | 'MONTHLY' | 'YEARLY';
|
|
1152
|
+
offers?: Offer[];
|
|
1153
|
+
}
|
|
1154
|
+
/**
|
|
1155
|
+
* @public
|
|
1156
|
+
* @category 인앱결제
|
|
1157
|
+
* @name IapProductListItem
|
|
1158
|
+
* @description 인앱결제로 구매할 수 있는 상품 하나의 정보를 담은 객체예요. 상품 목록을 화면에 표시할 때 사용해요.
|
|
1159
|
+
*/
|
|
1160
|
+
type IapProductListItem = ConsumableProductListItem | NonConsumableProductListItem | SubscriptionProductListItem;
|
|
1097
1161
|
/**
|
|
1098
1162
|
* @public
|
|
1099
1163
|
* @category 인앱결제
|
|
@@ -1272,6 +1336,90 @@ declare function completeProductGrant(params: {
|
|
|
1272
1336
|
orderId: string;
|
|
1273
1337
|
};
|
|
1274
1338
|
}): Promise<boolean | undefined>;
|
|
1339
|
+
/**
|
|
1340
|
+
* @public
|
|
1341
|
+
* @category 인앱결제
|
|
1342
|
+
* @name CreateSubscriptionPurchaseOrderOptions
|
|
1343
|
+
* @description 구독 인앱결제를 생성할 때 필요한 옵션이에요.
|
|
1344
|
+
* @property {object} options - 결제할 구독 상품의 정보예요.
|
|
1345
|
+
* @property {string} options.sku - 주문할 구독 상품의 고유 ID예요.
|
|
1346
|
+
* @property {string | null} [options.offerId] - 적용할 offer ID예요. 없으면 기본 가격이 적용돼요.
|
|
1347
|
+
* @property {(params: { orderId: string, subscriptionId?: string }) => boolean | Promise<boolean>} options.processProductGrant - 주문이 만들어진 뒤 실제로 상품을 지급할 때 호출해요.
|
|
1348
|
+
* @property {(event: SubscriptionSuccessEvent) => void | Promise<void>} onEvent - 결제가 성공했을 때 호출해요.
|
|
1349
|
+
* @property {(error: unknown) => void | Promise<void>} onError - 결제 과정에서 에러가 발생했을 때 호출해요.
|
|
1350
|
+
*/
|
|
1351
|
+
interface CreateSubscriptionPurchaseOrderOptions {
|
|
1352
|
+
options: {
|
|
1353
|
+
sku: string;
|
|
1354
|
+
offerId?: string | null;
|
|
1355
|
+
processProductGrant: (params: {
|
|
1356
|
+
orderId: string;
|
|
1357
|
+
subscriptionId?: string;
|
|
1358
|
+
}) => boolean | Promise<boolean>;
|
|
1359
|
+
};
|
|
1360
|
+
onEvent: (event: SubscriptionSuccessEvent) => void | Promise<void>;
|
|
1361
|
+
onError: (error: unknown) => void | Promise<void>;
|
|
1362
|
+
}
|
|
1363
|
+
/**
|
|
1364
|
+
* @public
|
|
1365
|
+
* @category 인앱결제
|
|
1366
|
+
* @name IapCreateSubscriptionPurchaseOrderResult
|
|
1367
|
+
* @description 구독 인앱결제가 완료되면 결제 세부 정보와 상품 정보를 담아 반환해요. `IapCreateOneTimePurchaseOrderResult`와 동일한 구조예요.
|
|
1368
|
+
*/
|
|
1369
|
+
type IapCreateSubscriptionPurchaseOrderResult = IapCreateOneTimePurchaseOrderResult;
|
|
1370
|
+
interface SubscriptionSuccessEvent {
|
|
1371
|
+
type: 'success';
|
|
1372
|
+
data: IapCreateSubscriptionPurchaseOrderResult;
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
* @public
|
|
1376
|
+
* @category 인앱결제
|
|
1377
|
+
* @name createSubscriptionPurchaseOrder
|
|
1378
|
+
* @description
|
|
1379
|
+
* 구독 인앱결제 주문서 페이지로 이동해요. 사용자가 구독 상품 구매 버튼을 누르는 상황 등에 사용할 수 있어요.
|
|
1380
|
+
* @param {CreateSubscriptionPurchaseOrderOptions} params - 구독 인앱결제를 생성할 때 필요한 정보예요.
|
|
1381
|
+
* @returns {() => void} 앱브릿지 cleanup 함수를 반환해요. 인앱결제 기능이 끝나면 반드시 이 함수를 호출해서 리소스를 해제해야 해요.
|
|
1382
|
+
*
|
|
1383
|
+
* @example
|
|
1384
|
+
* ### 구독 인앱결제 주문서 페이지로 이동하기
|
|
1385
|
+
*
|
|
1386
|
+
* ```tsx
|
|
1387
|
+
* import { IAP } from "@apps-in-toss/web-framework";
|
|
1388
|
+
* import { Button } from "@toss/tds-react-native";
|
|
1389
|
+
* import { useCallback } from "react";
|
|
1390
|
+
*
|
|
1391
|
+
* interface Props {
|
|
1392
|
+
* sku: string;
|
|
1393
|
+
* offerId?: string;
|
|
1394
|
+
* }
|
|
1395
|
+
*
|
|
1396
|
+
* function SubscriptionPurchaseButton({ sku, offerId }: Props) {
|
|
1397
|
+
* const handleClick = useCallback(async () => {
|
|
1398
|
+
* const cleanup = IAP.createSubscriptionPurchaseOrder({
|
|
1399
|
+
* options: {
|
|
1400
|
+
* sku,
|
|
1401
|
+
* offerId,
|
|
1402
|
+
* processProductGrant: ({ orderId, subscriptionId }) => {
|
|
1403
|
+
* // 상품 지급 로직 작성
|
|
1404
|
+
* return true; // 상품 지급 여부
|
|
1405
|
+
* },
|
|
1406
|
+
* },
|
|
1407
|
+
* onEvent: (event) => {
|
|
1408
|
+
* console.log(event);
|
|
1409
|
+
* },
|
|
1410
|
+
* onError: (error) => {
|
|
1411
|
+
* console.error(error);
|
|
1412
|
+
* },
|
|
1413
|
+
* });
|
|
1414
|
+
*
|
|
1415
|
+
* return cleanup;
|
|
1416
|
+
* }, [sku, offerId]);
|
|
1417
|
+
*
|
|
1418
|
+
* return <Button onClick={handleClick}>구독하기</Button>;
|
|
1419
|
+
* }
|
|
1420
|
+
* ```
|
|
1421
|
+
*/
|
|
1422
|
+
declare function createSubscriptionPurchaseOrder(params: CreateSubscriptionPurchaseOrderOptions): () => void;
|
|
1275
1423
|
/**
|
|
1276
1424
|
* @public
|
|
1277
1425
|
* @category 인앱결제
|
|
@@ -1285,6 +1433,7 @@ declare function completeProductGrant(params: {
|
|
|
1285
1433
|
*/
|
|
1286
1434
|
declare const IAP: {
|
|
1287
1435
|
createOneTimePurchaseOrder: typeof createOneTimePurchaseOrder;
|
|
1436
|
+
createSubscriptionPurchaseOrder: typeof createSubscriptionPurchaseOrder;
|
|
1288
1437
|
getProductItemList: typeof getProductItemList;
|
|
1289
1438
|
getPendingOrders: typeof getPendingOrders;
|
|
1290
1439
|
getCompletedOrRefundedOrders: typeof getCompletedOrRefundedOrders;
|
|
@@ -1469,6 +1618,15 @@ interface Spec extends TurboModule {
|
|
|
1469
1618
|
orderId: string;
|
|
1470
1619
|
}) => void;
|
|
1471
1620
|
}) => () => void;
|
|
1621
|
+
requestSubscriptionPurchase: (params: {
|
|
1622
|
+
sku: string;
|
|
1623
|
+
offerId: string | null;
|
|
1624
|
+
}, fallbacks: {
|
|
1625
|
+
onPurchased: (params: {
|
|
1626
|
+
orderId: string;
|
|
1627
|
+
subscriptionId?: string;
|
|
1628
|
+
}) => void;
|
|
1629
|
+
}) => () => void;
|
|
1472
1630
|
processProductGrant: (params: {
|
|
1473
1631
|
orderId: string;
|
|
1474
1632
|
isProductGranted: boolean;
|
|
@@ -3004,4 +3162,4 @@ declare const INTERNAL__module: {
|
|
|
3004
3162
|
tossCoreEventLog: typeof tossCoreEventLog;
|
|
3005
3163
|
};
|
|
3006
3164
|
|
|
3007
|
-
export { AppsInTossModule, type AppsInTossSignTossCertParams, BedrockCoreModule, BedrockModule, type CheckoutPaymentOptions, type CheckoutPaymentResult, type CompletedOrRefundedOrdersResult, type ContactsViralParams, type EventLogParams, type GameCenterGameProfileResponse, type GetUserKeyForGameErrorResponse, type GetUserKeyForGameResponse, type GetUserKeyForGameSuccessResponse, GoogleAdMob, type GrantPromotionRewardForGameErrorResponse, type GrantPromotionRewardForGameErrorResult, type GrantPromotionRewardForGameResponse, type GrantPromotionRewardForGameSuccessResponse, type HapticFeedbackType, IAP, AppsInTossModuleInstance as INTERNAL__AppsInTossModule, INTERNAL__appBridgeHandler, INTERNAL__module, type IapCreateOneTimePurchaseOrderOptions, type IapCreateOneTimePurchaseOrderResult, type IapProductListItem, type NetworkStatus, type Primitive, type SaveBase64DataParams, Storage, type SubmitGameCenterLeaderBoardScoreResponse, TossPay, type UpdateLocationEventEmitter, appLogin, appsInTossEvent, appsInTossSignTossCert, closeView, contactsViral, eventLog, fetchAlbumPhotos, fetchContacts, generateHapticFeedback, getClipboardText, getCurrentLocation, getDeviceId, getGameCenterGameProfile, getIsTossLoginIntegratedService, getLocale, getNetworkStatus, getOperationalEnvironment, getPlatformOS, getSchemeUri, getServerTime, getTossAppVersion, getTossShareLink, getUserKeyForGame, grantPromotionRewardForGame, iapCreateOneTimePurchaseOrder, isMinVersionSupported, onVisibilityChangedByTransparentServiceWeb, openCamera, openGameCenterLeaderboard, openURL, processProductGrant, requestOneTimePurchase, saveBase64Data, setClipboardText, setDeviceOrientation, setIosSwipeGestureEnabled, setScreenAwakeMode, setSecureScreen, share, startUpdateLocation, submitGameCenterLeaderBoardScore };
|
|
3165
|
+
export { AppsInTossModule, type AppsInTossSignTossCertParams, BedrockCoreModule, BedrockModule, type CheckoutPaymentOptions, type CheckoutPaymentResult, type CompletedOrRefundedOrdersResult, type ConsumableProductListItem, type ContactsViralParams, type CreateSubscriptionPurchaseOrderOptions, type EventLogParams, type GameCenterGameProfileResponse, type GetUserKeyForGameErrorResponse, type GetUserKeyForGameResponse, type GetUserKeyForGameSuccessResponse, GoogleAdMob, type GrantPromotionRewardForGameErrorResponse, type GrantPromotionRewardForGameErrorResult, type GrantPromotionRewardForGameResponse, type GrantPromotionRewardForGameSuccessResponse, type HapticFeedbackType, IAP, AppsInTossModuleInstance as INTERNAL__AppsInTossModule, INTERNAL__appBridgeHandler, INTERNAL__module, type IapCreateOneTimePurchaseOrderOptions, type IapCreateOneTimePurchaseOrderResult, type IapCreateSubscriptionPurchaseOrderResult, type IapProductListItem, type NetworkStatus, type NonConsumableProductListItem, type Primitive, type SaveBase64DataParams, Storage, type SubmitGameCenterLeaderBoardScoreResponse, type SubscriptionProductListItem, TossPay, type UpdateLocationEventEmitter, appLogin, appsInTossEvent, appsInTossSignTossCert, closeView, contactsViral, eventLog, fetchAlbumPhotos, fetchContacts, generateHapticFeedback, getClipboardText, getCurrentLocation, getDeviceId, getGameCenterGameProfile, getIsTossLoginIntegratedService, getLocale, getNetworkStatus, getOperationalEnvironment, getPlatformOS, getSchemeUri, getServerTime, getTossAppVersion, getTossShareLink, getUserKeyForGame, grantPromotionRewardForGame, iapCreateOneTimePurchaseOrder, isMinVersionSupported, onVisibilityChangedByTransparentServiceWeb, openCamera, openGameCenterLeaderboard, openURL, processProductGrant, requestOneTimePurchase, saveBase64Data, setClipboardText, setDeviceOrientation, setIosSwipeGestureEnabled, setScreenAwakeMode, setSecureScreen, share, startUpdateLocation, submitGameCenterLeaderBoardScore };
|
package/dist/index.js
CHANGED
|
@@ -586,7 +586,8 @@ async function getTossShareLinkV1(path) {
|
|
|
586
586
|
}
|
|
587
587
|
|
|
588
588
|
// src/AppsInTossModule/native-modules/iap.ts
|
|
589
|
-
|
|
589
|
+
var noop2 = () => {
|
|
590
|
+
};
|
|
590
591
|
function iapCreateOneTimePurchaseOrder(params) {
|
|
591
592
|
const sku = params.sku ?? params.productId;
|
|
592
593
|
return AppsInTossModule.iapCreateOneTimePurchaseOrder({ productId: sku });
|
|
@@ -701,8 +702,37 @@ async function completeProductGrant(params) {
|
|
|
701
702
|
}
|
|
702
703
|
return AppsInTossModule.completeProductGrant(params);
|
|
703
704
|
}
|
|
705
|
+
function createSubscriptionPurchaseOrder(params) {
|
|
706
|
+
const isSupported = isMinVersionSupported({
|
|
707
|
+
android: "5.248.0",
|
|
708
|
+
ios: "5.249.0"
|
|
709
|
+
});
|
|
710
|
+
if (!isSupported) {
|
|
711
|
+
return noop2;
|
|
712
|
+
}
|
|
713
|
+
const { options, onEvent, onError } = params;
|
|
714
|
+
const { sku, offerId, processProductGrant: processProductGrant2 } = options;
|
|
715
|
+
const unregisterCallbacks = INTERNAL__appBridgeHandler.invokeAppBridgeMethod(
|
|
716
|
+
"requestSubscriptionPurchase",
|
|
717
|
+
{ sku, offerId: offerId ?? null },
|
|
718
|
+
{
|
|
719
|
+
onPurchased: async (purchasedParams) => {
|
|
720
|
+
const isProductGranted = await processProductGrant2(purchasedParams);
|
|
721
|
+
await AppsInTossModule.processProductGrant({ orderId: purchasedParams.orderId, isProductGranted });
|
|
722
|
+
},
|
|
723
|
+
onSuccess: (result) => {
|
|
724
|
+
onEvent({ type: "success", data: result });
|
|
725
|
+
},
|
|
726
|
+
onError: (error) => {
|
|
727
|
+
onError(error);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
);
|
|
731
|
+
return unregisterCallbacks;
|
|
732
|
+
}
|
|
704
733
|
var IAP = {
|
|
705
734
|
createOneTimePurchaseOrder,
|
|
735
|
+
createSubscriptionPurchaseOrder,
|
|
706
736
|
getProductItemList,
|
|
707
737
|
getPendingOrders,
|
|
708
738
|
getCompletedOrRefundedOrders,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apps-in-toss/native-modules",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.12.0",
|
|
5
5
|
"description": "Native Modules for Apps In Toss",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"typecheck": "tsc --noEmit",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"vitest": "^3.2.4"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@apps-in-toss/types": "^1.
|
|
45
|
+
"@apps-in-toss/types": "^1.12.0",
|
|
46
46
|
"es-toolkit": "^1.39.3"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
@@ -74,6 +74,10 @@ interface Spec extends __TurboModule {
|
|
|
74
74
|
params: { sku: string },
|
|
75
75
|
fallbacks: { onPurchased: (params: { orderId: string }) => void }
|
|
76
76
|
) => () => void;
|
|
77
|
+
requestSubscriptionPurchase: (
|
|
78
|
+
params: { sku: string; offerId: string | null },
|
|
79
|
+
fallbacks: { onPurchased: (params: { orderId: string; subscriptionId?: string }) => void }
|
|
80
|
+
) => () => void;
|
|
77
81
|
processProductGrant: (params: { orderId: string; isProductGranted: boolean }) => Promise<void>;
|
|
78
82
|
getPendingOrders: (
|
|
79
83
|
params: CompatiblePlaceholderArgument
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { noop } from 'es-toolkit';
|
|
2
1
|
import { AppsInTossModule } from './AppsInTossModule';
|
|
3
2
|
import { isMinVersionSupported } from './isMinVersionSupported';
|
|
4
3
|
import { INTERNAL__appBridgeHandler } from '../native-event-emitter/internal/appBridge';
|
|
5
4
|
|
|
5
|
+
const noop = () => {};
|
|
6
|
+
|
|
6
7
|
type Sku =
|
|
7
8
|
| {
|
|
8
9
|
/**
|
|
@@ -38,8 +39,7 @@ export interface IapCreateOneTimePurchaseOrderResult {
|
|
|
38
39
|
fraction: number;
|
|
39
40
|
miniAppIconUrl: string | null;
|
|
40
41
|
}
|
|
41
|
-
|
|
42
|
-
interface SuccessEvent {
|
|
42
|
+
interface OneTimePurchaseSuccessEvent {
|
|
43
43
|
type: 'success';
|
|
44
44
|
data: IapCreateOneTimePurchaseOrderResult;
|
|
45
45
|
}
|
|
@@ -61,13 +61,13 @@ interface PurchasedEvent {
|
|
|
61
61
|
*/
|
|
62
62
|
export interface IapCreateOneTimePurchaseOrderOptions {
|
|
63
63
|
options: Sku & { processProductGrant: (params: { orderId: string }) => boolean | Promise<boolean> };
|
|
64
|
-
onEvent: (event:
|
|
64
|
+
onEvent: (event: OneTimePurchaseSuccessEvent) => void | Promise<void>;
|
|
65
65
|
onError: (error: unknown) => void | Promise<void>;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
interface IapRequestOneTimePurchaseOptions {
|
|
69
69
|
options: Sku;
|
|
70
|
-
onEvent: (event: PurchasedEvent |
|
|
70
|
+
onEvent: (event: PurchasedEvent | OneTimePurchaseSuccessEvent) => void | Promise<void>;
|
|
71
71
|
onError: (error: unknown) => void | Promise<void>;
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -222,25 +222,97 @@ function createOneTimePurchaseOrder(params: IapCreateOneTimePurchaseOrderOptions
|
|
|
222
222
|
return unregisterCallbacks;
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
+
interface BasicProductListItem {
|
|
226
|
+
sku: string;
|
|
227
|
+
displayAmount: string;
|
|
228
|
+
displayName: string;
|
|
229
|
+
iconUrl: string;
|
|
230
|
+
description: string;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
type Offer =
|
|
234
|
+
| {
|
|
235
|
+
type: 'FREE_TRIAL';
|
|
236
|
+
offerId: string;
|
|
237
|
+
period: string;
|
|
238
|
+
}
|
|
239
|
+
| {
|
|
240
|
+
type: 'NEW_SUBSCRIPTION';
|
|
241
|
+
offerId: string;
|
|
242
|
+
period: string;
|
|
243
|
+
displayAmount: string;
|
|
244
|
+
}
|
|
245
|
+
| {
|
|
246
|
+
type: 'RETURNING';
|
|
247
|
+
offerId: string;
|
|
248
|
+
period: string;
|
|
249
|
+
displayAmount: string;
|
|
250
|
+
};
|
|
251
|
+
|
|
225
252
|
/**
|
|
226
253
|
* @public
|
|
227
254
|
* @category 인앱결제
|
|
228
|
-
* @name
|
|
229
|
-
* @description
|
|
255
|
+
* @name ConsumableProductListItem
|
|
256
|
+
* @description 소모품 상품 정보를 담은 객체예요.
|
|
230
257
|
* @property {string} sku - 상품의 고유 ID예요.
|
|
258
|
+
* @property {string} type - 상품의 유형이에요. `CONSUMABLE`을 나타내요.
|
|
231
259
|
* @property {string} displayName - 화면에 표시할 상품 이름이에요. 상품 이름은 앱인토스 콘솔에서 설정한 값이에요.
|
|
232
260
|
* @property {string} displayAmount - 통화 단위가 포함된 가격 정보예요. 예를 들어 `1,000원`으로 가격과 통화가 함께 표시돼요.
|
|
233
261
|
* @property {string} iconUrl - 상품 아이콘 이미지의 URL이에요. 아이콘은 앱인토스 콘솔에서 설정한 이미지예요.
|
|
234
262
|
* @property {string} description - 상품에 대한 설명이에요. 설명은 앱인토스 콘솔에서 설정한 값이에요.
|
|
235
263
|
*/
|
|
236
|
-
export interface
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
264
|
+
export interface ConsumableProductListItem extends BasicProductListItem {
|
|
265
|
+
type: 'CONSUMABLE';
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* @public
|
|
270
|
+
* @category 인앱결제
|
|
271
|
+
* @name NonConsumableProductListItem
|
|
272
|
+
* @description 비소모품 상품 정보를 담은 객체예요.
|
|
273
|
+
* @property {string} sku - 상품의 고유 ID예요.
|
|
274
|
+
* @property {string} type - 상품의 유형이에요. `NON_CONSUMABLE`을 나타내요.
|
|
275
|
+
* @property {string} displayName - 화면에 표시할 상품 이름이에요. 상품 이름은 앱인토스 콘솔에서 설정한 값이에요.
|
|
276
|
+
* @property {string} displayAmount - 통화 단위가 포함된 가격 정보예요. 예를 들어 `1,000원`으로 가격과 통화가 함께 표시돼요.
|
|
277
|
+
* @property {string} iconUrl - 상품 아이콘 이미지의 URL이에요. 아이콘은 앱인토스 콘솔에서 설정한 이미지예요.
|
|
278
|
+
* @property {string} description - 상품에 대한 설명이에요. 설명은 앱인토스 콘솔에서 설정한 값이에요.
|
|
279
|
+
*/
|
|
280
|
+
export interface NonConsumableProductListItem extends BasicProductListItem {
|
|
281
|
+
type: 'NON_CONSUMABLE';
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* @public
|
|
286
|
+
* @category 인앱결제
|
|
287
|
+
* @name SubscriptionProductListItem
|
|
288
|
+
* @description 자동 갱신 구독 상품 정보를 담은 객체예요.
|
|
289
|
+
* @property {string} sku - 상품의 고유 ID예요.
|
|
290
|
+
* @property {string} type - 상품의 유형이에요. `SUBSCRIPTION`을 나타내요.
|
|
291
|
+
* @property {string} displayName - 화면에 표시할 상품 이름이에요. 상품 이름은 앱인토스 콘솔에서 설정한 값이에요.
|
|
292
|
+
* @property {string} displayAmount - 통화 단위가 포함된 가격 정보예요. 예를 들어 `1,000원`으로 가격과 통화가 함께 표시돼요.
|
|
293
|
+
* @property {string} iconUrl - 상품 아이콘 이미지의 URL이에요. 아이콘은 앱인토스 콘솔에서 설정한 이미지예요.
|
|
294
|
+
* @property {string} description - 상품에 대한 설명이에요. 설명은 앱인토스 콘솔에서 설정한 값이에요.
|
|
295
|
+
* @property {string} renewalCycle - 구독 갱신 주기이에요. `WEEKLY`, `MONTHLY`, `YEARLY` 중 하나를 나타내요.
|
|
296
|
+
* @property {Offer[]} offers - 구독 혜택 옵션 목록이에요. 각 옵션은 하나의 구독 혜택을 나타내요.
|
|
297
|
+
* @property {string} offers[].type - 구독 혜택 옵션 유형이에요. `FREE_TRIAL`, `NEW_SUBSCRIPTION`, `RETURNING` 중 하나를 나타내요.
|
|
298
|
+
* @property {string} offers[].offerId - 구독 혜택 옵션의 고유 ID예요.
|
|
299
|
+
* @property {string} offers[].period - 구독 혜택 옵션의 적용 기간이에요.
|
|
300
|
+
* @property {string} offers[].displayAmount - 통화 단위가 포함된 구독 혜택 옵션의 가격 정보예요. 예를 들어 `1,000원`으로 가격과 통화가 함께 표시돼요.
|
|
301
|
+
*/
|
|
302
|
+
export interface SubscriptionProductListItem extends BasicProductListItem {
|
|
303
|
+
type: 'SUBSCRIPTION';
|
|
304
|
+
renewalCycle: 'WEEKLY' | 'MONTHLY' | 'YEARLY';
|
|
305
|
+
offers?: Offer[];
|
|
242
306
|
}
|
|
243
307
|
|
|
308
|
+
/**
|
|
309
|
+
* @public
|
|
310
|
+
* @category 인앱결제
|
|
311
|
+
* @name IapProductListItem
|
|
312
|
+
* @description 인앱결제로 구매할 수 있는 상품 하나의 정보를 담은 객체예요. 상품 목록을 화면에 표시할 때 사용해요.
|
|
313
|
+
*/
|
|
314
|
+
export type IapProductListItem = ConsumableProductListItem | NonConsumableProductListItem | SubscriptionProductListItem;
|
|
315
|
+
|
|
244
316
|
/**
|
|
245
317
|
* @public
|
|
246
318
|
* @category 인앱결제
|
|
@@ -449,6 +521,122 @@ async function completeProductGrant(params: { params: { orderId: string } }) {
|
|
|
449
521
|
return AppsInTossModule.completeProductGrant(params);
|
|
450
522
|
}
|
|
451
523
|
|
|
524
|
+
/**
|
|
525
|
+
* @public
|
|
526
|
+
* @category 인앱결제
|
|
527
|
+
* @name CreateSubscriptionPurchaseOrderOptions
|
|
528
|
+
* @description 구독 인앱결제를 생성할 때 필요한 옵션이에요.
|
|
529
|
+
* @property {object} options - 결제할 구독 상품의 정보예요.
|
|
530
|
+
* @property {string} options.sku - 주문할 구독 상품의 고유 ID예요.
|
|
531
|
+
* @property {string | null} [options.offerId] - 적용할 offer ID예요. 없으면 기본 가격이 적용돼요.
|
|
532
|
+
* @property {(params: { orderId: string, subscriptionId?: string }) => boolean | Promise<boolean>} options.processProductGrant - 주문이 만들어진 뒤 실제로 상품을 지급할 때 호출해요.
|
|
533
|
+
* @property {(event: SubscriptionSuccessEvent) => void | Promise<void>} onEvent - 결제가 성공했을 때 호출해요.
|
|
534
|
+
* @property {(error: unknown) => void | Promise<void>} onError - 결제 과정에서 에러가 발생했을 때 호출해요.
|
|
535
|
+
*/
|
|
536
|
+
export interface CreateSubscriptionPurchaseOrderOptions {
|
|
537
|
+
options: {
|
|
538
|
+
sku: string;
|
|
539
|
+
offerId?: string | null;
|
|
540
|
+
processProductGrant: (params: { orderId: string; subscriptionId?: string }) => boolean | Promise<boolean>;
|
|
541
|
+
};
|
|
542
|
+
onEvent: (event: SubscriptionSuccessEvent) => void | Promise<void>;
|
|
543
|
+
onError: (error: unknown) => void | Promise<void>;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* @public
|
|
548
|
+
* @category 인앱결제
|
|
549
|
+
* @name IapCreateSubscriptionPurchaseOrderResult
|
|
550
|
+
* @description 구독 인앱결제가 완료되면 결제 세부 정보와 상품 정보를 담아 반환해요. `IapCreateOneTimePurchaseOrderResult`와 동일한 구조예요.
|
|
551
|
+
*/
|
|
552
|
+
export type IapCreateSubscriptionPurchaseOrderResult = IapCreateOneTimePurchaseOrderResult;
|
|
553
|
+
|
|
554
|
+
interface SubscriptionSuccessEvent {
|
|
555
|
+
type: 'success';
|
|
556
|
+
data: IapCreateSubscriptionPurchaseOrderResult;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* @public
|
|
561
|
+
* @category 인앱결제
|
|
562
|
+
* @name createSubscriptionPurchaseOrder
|
|
563
|
+
* @description
|
|
564
|
+
* 구독 인앱결제 주문서 페이지로 이동해요. 사용자가 구독 상품 구매 버튼을 누르는 상황 등에 사용할 수 있어요.
|
|
565
|
+
* @param {CreateSubscriptionPurchaseOrderOptions} params - 구독 인앱결제를 생성할 때 필요한 정보예요.
|
|
566
|
+
* @returns {() => void} 앱브릿지 cleanup 함수를 반환해요. 인앱결제 기능이 끝나면 반드시 이 함수를 호출해서 리소스를 해제해야 해요.
|
|
567
|
+
*
|
|
568
|
+
* @example
|
|
569
|
+
* ### 구독 인앱결제 주문서 페이지로 이동하기
|
|
570
|
+
*
|
|
571
|
+
* ```tsx
|
|
572
|
+
* import { IAP } from "@apps-in-toss/web-framework";
|
|
573
|
+
* import { Button } from "@toss/tds-react-native";
|
|
574
|
+
* import { useCallback } from "react";
|
|
575
|
+
*
|
|
576
|
+
* interface Props {
|
|
577
|
+
* sku: string;
|
|
578
|
+
* offerId?: string;
|
|
579
|
+
* }
|
|
580
|
+
*
|
|
581
|
+
* function SubscriptionPurchaseButton({ sku, offerId }: Props) {
|
|
582
|
+
* const handleClick = useCallback(async () => {
|
|
583
|
+
* const cleanup = IAP.createSubscriptionPurchaseOrder({
|
|
584
|
+
* options: {
|
|
585
|
+
* sku,
|
|
586
|
+
* offerId,
|
|
587
|
+
* processProductGrant: ({ orderId, subscriptionId }) => {
|
|
588
|
+
* // 상품 지급 로직 작성
|
|
589
|
+
* return true; // 상품 지급 여부
|
|
590
|
+
* },
|
|
591
|
+
* },
|
|
592
|
+
* onEvent: (event) => {
|
|
593
|
+
* console.log(event);
|
|
594
|
+
* },
|
|
595
|
+
* onError: (error) => {
|
|
596
|
+
* console.error(error);
|
|
597
|
+
* },
|
|
598
|
+
* });
|
|
599
|
+
*
|
|
600
|
+
* return cleanup;
|
|
601
|
+
* }, [sku, offerId]);
|
|
602
|
+
*
|
|
603
|
+
* return <Button onClick={handleClick}>구독하기</Button>;
|
|
604
|
+
* }
|
|
605
|
+
* ```
|
|
606
|
+
*/
|
|
607
|
+
function createSubscriptionPurchaseOrder(params: CreateSubscriptionPurchaseOrderOptions): () => void {
|
|
608
|
+
const isSupported = isMinVersionSupported({
|
|
609
|
+
android: '5.248.0',
|
|
610
|
+
ios: '5.249.0',
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
if (!isSupported) {
|
|
614
|
+
return noop;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const { options, onEvent, onError } = params;
|
|
618
|
+
const { sku, offerId, processProductGrant } = options;
|
|
619
|
+
|
|
620
|
+
const unregisterCallbacks = INTERNAL__appBridgeHandler.invokeAppBridgeMethod(
|
|
621
|
+
'requestSubscriptionPurchase',
|
|
622
|
+
{ sku, offerId: offerId ?? null },
|
|
623
|
+
{
|
|
624
|
+
onPurchased: async (purchasedParams: { orderId: string; subscriptionId?: string }) => {
|
|
625
|
+
const isProductGranted = await processProductGrant(purchasedParams);
|
|
626
|
+
await AppsInTossModule.processProductGrant({ orderId: purchasedParams.orderId, isProductGranted });
|
|
627
|
+
},
|
|
628
|
+
onSuccess: (result: IapCreateSubscriptionPurchaseOrderResult) => {
|
|
629
|
+
onEvent({ type: 'success', data: result });
|
|
630
|
+
},
|
|
631
|
+
onError: (error: unknown) => {
|
|
632
|
+
onError(error);
|
|
633
|
+
},
|
|
634
|
+
}
|
|
635
|
+
);
|
|
636
|
+
|
|
637
|
+
return unregisterCallbacks;
|
|
638
|
+
}
|
|
639
|
+
|
|
452
640
|
/**
|
|
453
641
|
* @public
|
|
454
642
|
* @category 인앱결제
|
|
@@ -462,6 +650,7 @@ async function completeProductGrant(params: { params: { orderId: string } }) {
|
|
|
462
650
|
*/
|
|
463
651
|
export const IAP = {
|
|
464
652
|
createOneTimePurchaseOrder,
|
|
653
|
+
createSubscriptionPurchaseOrder,
|
|
465
654
|
getProductItemList,
|
|
466
655
|
getPendingOrders,
|
|
467
656
|
getCompletedOrRefundedOrders,
|