expo-iap 2.2.2 → 2.2.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"useIap.d.ts","sourceRoot":"","sources":["../src/useIap.ts"],"names":[],"mappings":"AAYA,OAAO,EACL,OAAO,EACP,eAAe,EACf,QAAQ,EACR,aAAa,EACb,cAAc,EACd,mBAAmB,EAEpB,MAAM,iBAAiB,CAAC;AAIzB,KAAK,UAAU,GAAG;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,mBAAmB,EAAE,eAAe,EAAE,CAAC;IACvC,aAAa,EAAE,mBAAmB,EAAE,CAAC;IACrC,iBAAiB,EAAE,eAAe,EAAE,CAAC;IACrC,kBAAkB,EAAE,eAAe,EAAE,CAAC;IACtC,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,oBAAoB,CAAC,EAAE,aAAa,CAAC;IACrC,iBAAiB,EAAE,CAAC,EAClB,QAAQ,EACR,YAAY,EACZ,uBAAuB,GACxB,EAAE;QACD,QAAQ,EAAE,QAAQ,CAAC;QACnB,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,uBAAuB,CAAC,EAAE,MAAM,CAAC;KAClC,KAAK,OAAO,CAAC,MAAM,GAAG,OAAO,GAAG,cAAc,GAAG,IAAI,CAAC,CAAC;IACxD,qBAAqB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,oBAAoB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD,CAAC;AAMF,wBAAgB,MAAM,IAAI,UAAU,CAqInC"}
1
+ {"version":3,"file":"useIap.d.ts","sourceRoot":"","sources":["../src/useIap.ts"],"names":[],"mappings":"AAYA,OAAO,EACL,OAAO,EACP,eAAe,EACf,QAAQ,EACR,aAAa,EACb,cAAc,EACd,mBAAmB,EAEpB,MAAM,iBAAiB,CAAC;AAKzB,KAAK,UAAU,GAAG;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,mBAAmB,EAAE,eAAe,EAAE,CAAC;IACvC,aAAa,EAAE,mBAAmB,EAAE,CAAC;IACrC,iBAAiB,EAAE,eAAe,EAAE,CAAC;IACrC,kBAAkB,EAAE,eAAe,EAAE,CAAC;IACtC,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,oBAAoB,CAAC,EAAE,aAAa,CAAC;IACrC,iBAAiB,EAAE,CAAC,EAClB,QAAQ,EACR,YAAY,EACZ,uBAAuB,GACxB,EAAE;QACD,QAAQ,EAAE,QAAQ,CAAC;QACnB,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,uBAAuB,CAAC,EAAE,MAAM,CAAC;KAClC,KAAK,OAAO,CAAC,MAAM,GAAG,OAAO,GAAG,cAAc,GAAG,IAAI,CAAC,CAAC;IACxD,qBAAqB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,oBAAoB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD,CAAC;AAEF,wBAAgB,MAAM,IAAI,UAAU,CAsInC"}
package/build/useIap.js CHANGED
@@ -1,8 +1,6 @@
1
1
  import { endConnection, initConnection, purchaseErrorListener, purchaseUpdatedListener, transactionUpdatedIos, getProducts, getAvailablePurchases, getPurchaseHistory, getSubscriptions, } from './';
2
- import { useCallback, useEffect, useState } from 'react';
3
- let purchaseUpdateSubscription;
4
- let purchaseErrorSubscription;
5
- let promotedProductsSubscription;
2
+ import { useCallback, useEffect, useState, useRef } from 'react';
3
+ import { Platform } from 'react-native';
6
4
  export function useIAP() {
7
5
  const [connected, setConnected] = useState(false);
8
6
  const [products, setProducts] = useState([]);
@@ -12,6 +10,8 @@ export function useIAP() {
12
10
  const [availablePurchases, setAvailablePurchases] = useState([]);
13
11
  const [currentPurchase, setCurrentPurchase] = useState();
14
12
  const [currentPurchaseError, setCurrentPurchaseError] = useState();
13
+ // 구독을 훅 인스턴스별로 관리하기 위한 ref
14
+ const subscriptionsRef = useRef({});
15
15
  const requestProducts = useCallback(async (skus) => {
16
16
  setProducts(await getProducts(skus));
17
17
  }, []);
@@ -40,44 +40,38 @@ export function useIAP() {
40
40
  setCurrentPurchase(undefined);
41
41
  }
42
42
  if (purchase.id === currentPurchaseError?.productId) {
43
- // Note that PurchaseError still uses productId
44
43
  setCurrentPurchaseError(undefined);
45
44
  }
46
45
  }
47
- }, [
48
- currentPurchase?.id,
49
- currentPurchaseError?.productId,
50
- setCurrentPurchase,
51
- setCurrentPurchaseError,
52
- ]);
46
+ }, [currentPurchase?.id, currentPurchaseError?.productId]);
53
47
  const initIapWithSubscriptions = useCallback(async () => {
54
48
  const result = await initConnection();
55
49
  setConnected(result);
56
50
  if (result) {
57
- purchaseUpdateSubscription = purchaseUpdatedListener(async (purchase) => {
51
+ subscriptionsRef.current.purchaseUpdate = purchaseUpdatedListener(async (purchase) => {
58
52
  setCurrentPurchaseError(undefined);
59
53
  setCurrentPurchase(purchase);
60
54
  });
61
- purchaseErrorSubscription = purchaseErrorListener((error) => {
55
+ subscriptionsRef.current.purchaseError = purchaseErrorListener((error) => {
62
56
  setCurrentPurchase(undefined);
63
57
  setCurrentPurchaseError(error);
64
58
  });
65
- promotedProductsSubscription = transactionUpdatedIos((event) => {
66
- setPromotedProductsIOS((prevProducts) => event.transaction
67
- ? [...prevProducts, event.transaction]
68
- : prevProducts);
69
- });
59
+ if (Platform.OS === 'ios') {
60
+ subscriptionsRef.current.promotedProductsIos = transactionUpdatedIos((event) => {
61
+ setPromotedProductsIOS((prevProducts) => event.transaction
62
+ ? [...prevProducts, event.transaction]
63
+ : prevProducts);
64
+ });
65
+ }
70
66
  }
71
67
  }, []);
72
68
  useEffect(() => {
73
69
  initIapWithSubscriptions();
70
+ const currentSubscriptions = subscriptionsRef.current;
74
71
  return () => {
75
- if (purchaseUpdateSubscription)
76
- purchaseUpdateSubscription.remove();
77
- if (purchaseErrorSubscription)
78
- purchaseErrorSubscription.remove();
79
- if (promotedProductsSubscription)
80
- promotedProductsSubscription.remove();
72
+ currentSubscriptions.purchaseUpdate?.remove();
73
+ currentSubscriptions.purchaseError?.remove();
74
+ currentSubscriptions.promotedProductsIos?.remove();
81
75
  endConnection();
82
76
  setConnected(false);
83
77
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useIap.js","sourceRoot":"","sources":["../src/useIap.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n endConnection,\n initConnection,\n purchaseErrorListener,\n purchaseUpdatedListener,\n transactionUpdatedIos,\n getProducts,\n getAvailablePurchases,\n getPurchaseHistory,\n getSubscriptions,\n} from './';\nimport {useCallback, useEffect, useState} from 'react';\nimport {\n Product,\n ProductPurchase,\n Purchase,\n PurchaseError,\n PurchaseResult,\n SubscriptionProduct,\n SubscriptionPurchase,\n} from './ExpoIap.types';\nimport {TransactionEvent} from './modules/ios';\nimport {Subscription} from 'expo-modules-core';\n\ntype IAP_STATUS = {\n connected: boolean;\n products: Product[];\n promotedProductsIOS: ProductPurchase[];\n subscriptions: SubscriptionProduct[];\n purchaseHistories: ProductPurchase[];\n availablePurchases: ProductPurchase[];\n currentPurchase?: ProductPurchase;\n currentPurchaseError?: PurchaseError;\n finishTransaction: ({\n purchase,\n isConsumable,\n developerPayloadAndroid,\n }: {\n purchase: Purchase;\n isConsumable?: boolean;\n developerPayloadAndroid?: string;\n }) => Promise<string | boolean | PurchaseResult | void>;\n getAvailablePurchases: () => Promise<void>;\n getPurchaseHistories: () => Promise<void>;\n getProducts: (skus: string[]) => Promise<void>;\n getSubscriptions: (skus: string[]) => Promise<void>;\n};\n\nlet purchaseUpdateSubscription: Subscription;\nlet purchaseErrorSubscription: Subscription;\nlet promotedProductsSubscription: Subscription;\n\nexport function useIAP(): IAP_STATUS {\n const [connected, setConnected] = useState<boolean>(false);\n const [products, setProducts] = useState<Product[]>([]);\n const [promotedProductsIOS, setPromotedProductsIOS] = useState<\n ProductPurchase[]\n >([]);\n const [subscriptions, setSubscriptions] = useState<SubscriptionProduct[]>([]);\n const [purchaseHistories, setPurchaseHistories] = useState<ProductPurchase[]>(\n [],\n );\n const [availablePurchases, setAvailablePurchases] = useState<\n ProductPurchase[]\n >([]);\n const [currentPurchase, setCurrentPurchase] = useState<ProductPurchase>();\n const [currentPurchaseError, setCurrentPurchaseError] =\n useState<PurchaseError>();\n\n const requestProducts = useCallback(async (skus: string[]): Promise<void> => {\n setProducts(await getProducts(skus));\n }, []);\n\n const requestSubscriptions = useCallback(\n async (skus: string[]): Promise<void> => {\n setSubscriptions(await getSubscriptions(skus));\n },\n [],\n );\n\n const requestAvailablePurchases = useCallback(async (): Promise<void> => {\n setAvailablePurchases(await getAvailablePurchases());\n }, []);\n\n const requestPurchaseHistories = useCallback(async (): Promise<void> => {\n setPurchaseHistories(await getPurchaseHistory());\n }, []);\n\n const finishTransaction = useCallback(\n async ({\n purchase,\n isConsumable,\n developerPayloadAndroid,\n }: {\n purchase: ProductPurchase;\n isConsumable?: boolean;\n developerPayloadAndroid?: string;\n }): Promise<string | boolean | PurchaseResult | void> => {\n try {\n return await finishTransaction({\n purchase,\n isConsumable,\n developerPayloadAndroid,\n });\n } catch (err) {\n throw err;\n } finally {\n if (purchase.id === currentPurchase?.id) {\n setCurrentPurchase(undefined);\n }\n\n if (purchase.id === currentPurchaseError?.productId) {\n // Note that PurchaseError still uses productId\n setCurrentPurchaseError(undefined);\n }\n }\n },\n [\n currentPurchase?.id,\n currentPurchaseError?.productId,\n setCurrentPurchase,\n setCurrentPurchaseError,\n ],\n );\n\n const initIapWithSubscriptions = useCallback(async (): Promise<void> => {\n const result = await initConnection();\n\n setConnected(result);\n\n if (result) {\n purchaseUpdateSubscription = purchaseUpdatedListener(\n async (purchase: Purchase | SubscriptionPurchase) => {\n setCurrentPurchaseError(undefined);\n setCurrentPurchase(purchase);\n },\n );\n\n purchaseErrorSubscription = purchaseErrorListener(\n (error: PurchaseError) => {\n setCurrentPurchase(undefined);\n setCurrentPurchaseError(error);\n },\n );\n\n promotedProductsSubscription = transactionUpdatedIos(\n (event: TransactionEvent) => {\n setPromotedProductsIOS((prevProducts) =>\n event.transaction\n ? [...prevProducts, event.transaction]\n : prevProducts,\n );\n },\n );\n }\n }, []);\n\n useEffect(() => {\n initIapWithSubscriptions();\n\n return (): void => {\n if (purchaseUpdateSubscription) purchaseUpdateSubscription.remove();\n if (purchaseErrorSubscription) purchaseErrorSubscription.remove();\n if (promotedProductsSubscription) promotedProductsSubscription.remove();\n\n endConnection();\n setConnected(false);\n };\n }, [initIapWithSubscriptions]);\n\n return {\n connected,\n products,\n promotedProductsIOS,\n subscriptions,\n purchaseHistories,\n finishTransaction,\n availablePurchases,\n currentPurchase,\n currentPurchaseError,\n getProducts: requestProducts,\n getSubscriptions: requestSubscriptions,\n getAvailablePurchases: requestAvailablePurchases,\n getPurchaseHistories: requestPurchaseHistories,\n };\n}\n"]}
1
+ {"version":3,"file":"useIap.js","sourceRoot":"","sources":["../src/useIap.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,cAAc,EACd,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,WAAW,EACX,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,IAAI,CAAC;AACZ,OAAO,EAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAC,MAAM,OAAO,CAAC;AAY/D,OAAO,EAAC,QAAQ,EAAC,MAAM,cAAc,CAAC;AA0BtC,MAAM,UAAU,MAAM;IACpB,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAU,KAAK,CAAC,CAAC;IAC3D,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAY,EAAE,CAAC,CAAC;IACxD,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GAAG,QAAQ,CAE5D,EAAE,CAAC,CAAC;IACN,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAwB,EAAE,CAAC,CAAC;IAC9E,MAAM,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,GAAG,QAAQ,CACxD,EAAE,CACH,CAAC;IACF,MAAM,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,GAAG,QAAQ,CAE1D,EAAE,CAAC,CAAC;IACN,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,EAAmB,CAAC;IAC1E,MAAM,CAAC,oBAAoB,EAAE,uBAAuB,CAAC,GACnD,QAAQ,EAAiB,CAAC;IAE5B,2BAA2B;IAC3B,MAAM,gBAAgB,GAAG,MAAM,CAI5B,EAAE,CAAC,CAAC;IAEP,MAAM,eAAe,GAAG,WAAW,CAAC,KAAK,EAAE,IAAc,EAAiB,EAAE;QAC1E,WAAW,CAAC,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;IACvC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,oBAAoB,GAAG,WAAW,CACtC,KAAK,EAAE,IAAc,EAAiB,EAAE;QACtC,gBAAgB,CAAC,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;IACjD,CAAC,EACD,EAAE,CACH,CAAC;IAEF,MAAM,yBAAyB,GAAG,WAAW,CAAC,KAAK,IAAmB,EAAE;QACtE,qBAAqB,CAAC,MAAM,qBAAqB,EAAE,CAAC,CAAC;IACvD,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,wBAAwB,GAAG,WAAW,CAAC,KAAK,IAAmB,EAAE;QACrE,oBAAoB,CAAC,MAAM,kBAAkB,EAAE,CAAC,CAAC;IACnD,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,iBAAiB,GAAG,WAAW,CACnC,KAAK,EAAE,EACL,QAAQ,EACR,YAAY,EACZ,uBAAuB,GAKxB,EAAqD,EAAE;QACtD,IAAI,CAAC;YACH,OAAO,MAAM,iBAAiB,CAAC;gBAC7B,QAAQ;gBACR,YAAY;gBACZ,uBAAuB;aACxB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,IAAI,QAAQ,CAAC,EAAE,KAAK,eAAe,EAAE,EAAE,EAAE,CAAC;gBACxC,kBAAkB,CAAC,SAAS,CAAC,CAAC;YAChC,CAAC;YACD,IAAI,QAAQ,CAAC,EAAE,KAAK,oBAAoB,EAAE,SAAS,EAAE,CAAC;gBACpD,uBAAuB,CAAC,SAAS,CAAC,CAAC;YACrC,CAAC;QACH,CAAC;IACH,CAAC,EACD,CAAC,eAAe,EAAE,EAAE,EAAE,oBAAoB,EAAE,SAAS,CAAC,CACvD,CAAC;IAEF,MAAM,wBAAwB,GAAG,WAAW,CAAC,KAAK,IAAmB,EAAE;QACrE,MAAM,MAAM,GAAG,MAAM,cAAc,EAAE,CAAC;QACtC,YAAY,CAAC,MAAM,CAAC,CAAC;QAErB,IAAI,MAAM,EAAE,CAAC;YACX,gBAAgB,CAAC,OAAO,CAAC,cAAc,GAAG,uBAAuB,CAC/D,KAAK,EAAE,QAAyC,EAAE,EAAE;gBAClD,uBAAuB,CAAC,SAAS,CAAC,CAAC;gBACnC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;YAC/B,CAAC,CACF,CAAC;YAEF,gBAAgB,CAAC,OAAO,CAAC,aAAa,GAAG,qBAAqB,CAC5D,CAAC,KAAoB,EAAE,EAAE;gBACvB,kBAAkB,CAAC,SAAS,CAAC,CAAC;gBAC9B,uBAAuB,CAAC,KAAK,CAAC,CAAC;YACjC,CAAC,CACF,CAAC;YAEF,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;gBAC1B,gBAAgB,CAAC,OAAO,CAAC,mBAAmB,GAAG,qBAAqB,CAClE,CAAC,KAAuB,EAAE,EAAE;oBAC1B,sBAAsB,CAAC,CAAC,YAAY,EAAE,EAAE,CACtC,KAAK,CAAC,WAAW;wBACf,CAAC,CAAC,CAAC,GAAG,YAAY,EAAE,KAAK,CAAC,WAAW,CAAC;wBACtC,CAAC,CAAC,YAAY,CACjB,CAAC;gBACJ,CAAC,CACF,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,SAAS,CAAC,GAAG,EAAE;QACb,wBAAwB,EAAE,CAAC;QAC3B,MAAM,oBAAoB,GAAG,gBAAgB,CAAC,OAAO,CAAC;QAEtD,OAAO,GAAG,EAAE;YACV,oBAAoB,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC;YAC9C,oBAAoB,CAAC,aAAa,EAAE,MAAM,EAAE,CAAC;YAC7C,oBAAoB,CAAC,mBAAmB,EAAE,MAAM,EAAE,CAAC;YACnD,aAAa,EAAE,CAAC;YAChB,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,wBAAwB,CAAC,CAAC,CAAC;IAE/B,OAAO;QACL,SAAS;QACT,QAAQ;QACR,mBAAmB;QACnB,aAAa;QACb,iBAAiB;QACjB,iBAAiB;QACjB,kBAAkB;QAClB,eAAe;QACf,oBAAoB;QACpB,WAAW,EAAE,eAAe;QAC5B,gBAAgB,EAAE,oBAAoB;QACtC,qBAAqB,EAAE,yBAAyB;QAChD,oBAAoB,EAAE,wBAAwB;KAC/C,CAAC;AACJ,CAAC","sourcesContent":["import {\n endConnection,\n initConnection,\n purchaseErrorListener,\n purchaseUpdatedListener,\n transactionUpdatedIos,\n getProducts,\n getAvailablePurchases,\n getPurchaseHistory,\n getSubscriptions,\n} from './';\nimport {useCallback, useEffect, useState, useRef} from 'react';\nimport {\n Product,\n ProductPurchase,\n Purchase,\n PurchaseError,\n PurchaseResult,\n SubscriptionProduct,\n SubscriptionPurchase,\n} from './ExpoIap.types';\nimport {TransactionEvent} from './modules/ios';\nimport {Subscription} from 'expo-modules-core';\nimport {Platform} from 'react-native';\n\ntype IAP_STATUS = {\n connected: boolean;\n products: Product[];\n promotedProductsIOS: ProductPurchase[];\n subscriptions: SubscriptionProduct[];\n purchaseHistories: ProductPurchase[];\n availablePurchases: ProductPurchase[];\n currentPurchase?: ProductPurchase;\n currentPurchaseError?: PurchaseError;\n finishTransaction: ({\n purchase,\n isConsumable,\n developerPayloadAndroid,\n }: {\n purchase: Purchase;\n isConsumable?: boolean;\n developerPayloadAndroid?: string;\n }) => Promise<string | boolean | PurchaseResult | void>;\n getAvailablePurchases: () => Promise<void>;\n getPurchaseHistories: () => Promise<void>;\n getProducts: (skus: string[]) => Promise<void>;\n getSubscriptions: (skus: string[]) => Promise<void>;\n};\n\nexport function useIAP(): IAP_STATUS {\n const [connected, setConnected] = useState<boolean>(false);\n const [products, setProducts] = useState<Product[]>([]);\n const [promotedProductsIOS, setPromotedProductsIOS] = useState<\n ProductPurchase[]\n >([]);\n const [subscriptions, setSubscriptions] = useState<SubscriptionProduct[]>([]);\n const [purchaseHistories, setPurchaseHistories] = useState<ProductPurchase[]>(\n [],\n );\n const [availablePurchases, setAvailablePurchases] = useState<\n ProductPurchase[]\n >([]);\n const [currentPurchase, setCurrentPurchase] = useState<ProductPurchase>();\n const [currentPurchaseError, setCurrentPurchaseError] =\n useState<PurchaseError>();\n\n // 구독을 훅 인스턴스별로 관리하기 위한 ref\n const subscriptionsRef = useRef<{\n purchaseUpdate?: Subscription;\n purchaseError?: Subscription;\n promotedProductsIos?: Subscription;\n }>({});\n\n const requestProducts = useCallback(async (skus: string[]): Promise<void> => {\n setProducts(await getProducts(skus));\n }, []);\n\n const requestSubscriptions = useCallback(\n async (skus: string[]): Promise<void> => {\n setSubscriptions(await getSubscriptions(skus));\n },\n [],\n );\n\n const requestAvailablePurchases = useCallback(async (): Promise<void> => {\n setAvailablePurchases(await getAvailablePurchases());\n }, []);\n\n const requestPurchaseHistories = useCallback(async (): Promise<void> => {\n setPurchaseHistories(await getPurchaseHistory());\n }, []);\n\n const finishTransaction = useCallback(\n async ({\n purchase,\n isConsumable,\n developerPayloadAndroid,\n }: {\n purchase: ProductPurchase;\n isConsumable?: boolean;\n developerPayloadAndroid?: string;\n }): Promise<string | boolean | PurchaseResult | void> => {\n try {\n return await finishTransaction({\n purchase,\n isConsumable,\n developerPayloadAndroid,\n });\n } catch (err) {\n throw err;\n } finally {\n if (purchase.id === currentPurchase?.id) {\n setCurrentPurchase(undefined);\n }\n if (purchase.id === currentPurchaseError?.productId) {\n setCurrentPurchaseError(undefined);\n }\n }\n },\n [currentPurchase?.id, currentPurchaseError?.productId],\n );\n\n const initIapWithSubscriptions = useCallback(async (): Promise<void> => {\n const result = await initConnection();\n setConnected(result);\n\n if (result) {\n subscriptionsRef.current.purchaseUpdate = purchaseUpdatedListener(\n async (purchase: Purchase | SubscriptionPurchase) => {\n setCurrentPurchaseError(undefined);\n setCurrentPurchase(purchase);\n },\n );\n\n subscriptionsRef.current.purchaseError = purchaseErrorListener(\n (error: PurchaseError) => {\n setCurrentPurchase(undefined);\n setCurrentPurchaseError(error);\n },\n );\n\n if (Platform.OS === 'ios') {\n subscriptionsRef.current.promotedProductsIos = transactionUpdatedIos(\n (event: TransactionEvent) => {\n setPromotedProductsIOS((prevProducts) =>\n event.transaction\n ? [...prevProducts, event.transaction]\n : prevProducts,\n );\n },\n );\n }\n }\n }, []);\n\n useEffect(() => {\n initIapWithSubscriptions();\n const currentSubscriptions = subscriptionsRef.current;\n\n return () => {\n currentSubscriptions.purchaseUpdate?.remove();\n currentSubscriptions.purchaseError?.remove();\n currentSubscriptions.promotedProductsIos?.remove();\n endConnection();\n setConnected(false);\n };\n }, [initIapWithSubscriptions]);\n\n return {\n connected,\n products,\n promotedProductsIOS,\n subscriptions,\n purchaseHistories,\n finishTransaction,\n availablePurchases,\n currentPurchase,\n currentPurchaseError,\n getProducts: requestProducts,\n getSubscriptions: requestSubscriptions,\n getAvailablePurchases: requestAvailablePurchases,\n getPurchaseHistories: requestPurchaseHistories,\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-iap",
3
- "version": "2.2.2",
3
+ "version": "2.2.3",
4
4
  "description": "In App Purchase module in Expo",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
package/src/useIap.ts CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  getPurchaseHistory,
10
10
  getSubscriptions,
11
11
  } from './';
12
- import {useCallback, useEffect, useState} from 'react';
12
+ import {useCallback, useEffect, useState, useRef} from 'react';
13
13
  import {
14
14
  Product,
15
15
  ProductPurchase,
@@ -21,6 +21,7 @@ import {
21
21
  } from './ExpoIap.types';
22
22
  import {TransactionEvent} from './modules/ios';
23
23
  import {Subscription} from 'expo-modules-core';
24
+ import {Platform} from 'react-native';
24
25
 
25
26
  type IAP_STATUS = {
26
27
  connected: boolean;
@@ -46,10 +47,6 @@ type IAP_STATUS = {
46
47
  getSubscriptions: (skus: string[]) => Promise<void>;
47
48
  };
48
49
 
49
- let purchaseUpdateSubscription: Subscription;
50
- let purchaseErrorSubscription: Subscription;
51
- let promotedProductsSubscription: Subscription;
52
-
53
50
  export function useIAP(): IAP_STATUS {
54
51
  const [connected, setConnected] = useState<boolean>(false);
55
52
  const [products, setProducts] = useState<Product[]>([]);
@@ -67,6 +64,13 @@ export function useIAP(): IAP_STATUS {
67
64
  const [currentPurchaseError, setCurrentPurchaseError] =
68
65
  useState<PurchaseError>();
69
66
 
67
+ // 구독을 훅 인스턴스별로 관리하기 위한 ref
68
+ const subscriptionsRef = useRef<{
69
+ purchaseUpdate?: Subscription;
70
+ purchaseError?: Subscription;
71
+ promotedProductsIos?: Subscription;
72
+ }>({});
73
+
70
74
  const requestProducts = useCallback(async (skus: string[]): Promise<void> => {
71
75
  setProducts(await getProducts(skus));
72
76
  }, []);
@@ -108,61 +112,55 @@ export function useIAP(): IAP_STATUS {
108
112
  if (purchase.id === currentPurchase?.id) {
109
113
  setCurrentPurchase(undefined);
110
114
  }
111
-
112
115
  if (purchase.id === currentPurchaseError?.productId) {
113
- // Note that PurchaseError still uses productId
114
116
  setCurrentPurchaseError(undefined);
115
117
  }
116
118
  }
117
119
  },
118
- [
119
- currentPurchase?.id,
120
- currentPurchaseError?.productId,
121
- setCurrentPurchase,
122
- setCurrentPurchaseError,
123
- ],
120
+ [currentPurchase?.id, currentPurchaseError?.productId],
124
121
  );
125
122
 
126
123
  const initIapWithSubscriptions = useCallback(async (): Promise<void> => {
127
124
  const result = await initConnection();
128
-
129
125
  setConnected(result);
130
126
 
131
127
  if (result) {
132
- purchaseUpdateSubscription = purchaseUpdatedListener(
128
+ subscriptionsRef.current.purchaseUpdate = purchaseUpdatedListener(
133
129
  async (purchase: Purchase | SubscriptionPurchase) => {
134
130
  setCurrentPurchaseError(undefined);
135
131
  setCurrentPurchase(purchase);
136
132
  },
137
133
  );
138
134
 
139
- purchaseErrorSubscription = purchaseErrorListener(
135
+ subscriptionsRef.current.purchaseError = purchaseErrorListener(
140
136
  (error: PurchaseError) => {
141
137
  setCurrentPurchase(undefined);
142
138
  setCurrentPurchaseError(error);
143
139
  },
144
140
  );
145
141
 
146
- promotedProductsSubscription = transactionUpdatedIos(
147
- (event: TransactionEvent) => {
148
- setPromotedProductsIOS((prevProducts) =>
149
- event.transaction
150
- ? [...prevProducts, event.transaction]
151
- : prevProducts,
152
- );
153
- },
154
- );
142
+ if (Platform.OS === 'ios') {
143
+ subscriptionsRef.current.promotedProductsIos = transactionUpdatedIos(
144
+ (event: TransactionEvent) => {
145
+ setPromotedProductsIOS((prevProducts) =>
146
+ event.transaction
147
+ ? [...prevProducts, event.transaction]
148
+ : prevProducts,
149
+ );
150
+ },
151
+ );
152
+ }
155
153
  }
156
154
  }, []);
157
155
 
158
156
  useEffect(() => {
159
157
  initIapWithSubscriptions();
158
+ const currentSubscriptions = subscriptionsRef.current;
160
159
 
161
- return (): void => {
162
- if (purchaseUpdateSubscription) purchaseUpdateSubscription.remove();
163
- if (purchaseErrorSubscription) purchaseErrorSubscription.remove();
164
- if (promotedProductsSubscription) promotedProductsSubscription.remove();
165
-
160
+ return () => {
161
+ currentSubscriptions.purchaseUpdate?.remove();
162
+ currentSubscriptions.purchaseError?.remove();
163
+ currentSubscriptions.promotedProductsIos?.remove();
166
164
  endConnection();
167
165
  setConnected(false);
168
166
  };