react-native-iap 9.0.0-beta → 9.0.0-beta12

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.
Files changed (94) hide show
  1. package/README.md +11 -22
  2. package/RNIap.podspec +33 -18
  3. package/android/build.gradle +137 -38
  4. package/android/gradle.properties +8 -0
  5. package/android/src/play/java/com/dooboolab/RNIap/RNIapModule.kt +99 -89
  6. package/android/src/play/java/com/dooboolab/RNIap/RNIapPackage.kt +0 -1
  7. package/android/src/testPlay/java/com/dooboolab/RNIap/{RNIapModuleTestV4.kt → RNIapModuleTest.kt} +47 -35
  8. package/ios/RNIapIos-Bridging-Header.h +2 -0
  9. package/ios/RNIapIos.m +14 -1
  10. package/ios/RNIapIos.swift +903 -883
  11. package/ios/{RNIap.xcodeproj → RNIapIos.xcodeproj}/project.pbxproj +29 -116
  12. package/lib/commonjs/__test__/iap.test.js +21 -0
  13. package/lib/commonjs/__test__/iap.test.js.map +1 -0
  14. package/lib/commonjs/hooks/useIAP.js +78 -0
  15. package/lib/commonjs/hooks/useIAP.js.map +1 -0
  16. package/lib/commonjs/hooks/withIAPContext.js +92 -0
  17. package/lib/commonjs/hooks/withIAPContext.js.map +1 -0
  18. package/lib/commonjs/iap.js +586 -0
  19. package/lib/commonjs/iap.js.map +1 -0
  20. package/lib/commonjs/index.js +59 -0
  21. package/lib/commonjs/index.js.map +1 -0
  22. package/lib/commonjs/types/amazon.js +2 -0
  23. package/lib/commonjs/types/amazon.js.map +1 -0
  24. package/lib/commonjs/types/android.js +55 -0
  25. package/lib/commonjs/types/android.js.map +1 -0
  26. package/lib/commonjs/types/apple.js +165 -0
  27. package/lib/commonjs/types/apple.js.map +1 -0
  28. package/lib/commonjs/types/index.js +59 -0
  29. package/lib/commonjs/types/index.js.map +1 -0
  30. package/lib/module/__test__/iap.test.js +17 -0
  31. package/lib/module/__test__/iap.test.js.map +1 -0
  32. package/lib/module/hooks/useIAP.js +68 -0
  33. package/lib/module/hooks/useIAP.js.map +1 -0
  34. package/lib/module/hooks/withIAPContext.js +76 -0
  35. package/lib/module/hooks/withIAPContext.js.map +1 -0
  36. package/lib/module/iap.js +494 -0
  37. package/lib/module/iap.js.map +1 -0
  38. package/lib/module/index.js +6 -0
  39. package/lib/module/index.js.map +1 -0
  40. package/lib/module/types/amazon.js +2 -0
  41. package/lib/module/types/amazon.js.map +1 -0
  42. package/lib/module/types/android.js +44 -0
  43. package/lib/module/types/android.js.map +1 -0
  44. package/lib/module/types/apple.js +153 -0
  45. package/lib/module/types/apple.js.map +1 -0
  46. package/lib/module/types/index.js +48 -0
  47. package/lib/module/types/index.js.map +1 -0
  48. package/{src → lib/typescript}/__test__/iap.test.d.ts +0 -0
  49. package/{src → lib/typescript}/hooks/useIAP.d.ts +1 -1
  50. package/{src → lib/typescript}/hooks/withIAPContext.d.ts +1 -1
  51. package/{src → lib/typescript}/iap.d.ts +17 -12
  52. package/{src → lib/typescript}/index.d.ts +2 -1
  53. package/{src → lib/typescript}/types/amazon.d.ts +0 -0
  54. package/{src → lib/typescript}/types/android.d.ts +0 -0
  55. package/{src → lib/typescript}/types/apple.d.ts +0 -0
  56. package/{src → lib/typescript}/types/index.d.ts +35 -22
  57. package/package.json +87 -57
  58. package/src/__test__/iap.test.ts +20 -0
  59. package/src/hooks/useIAP.ts +130 -0
  60. package/src/hooks/withIAPContext.tsx +160 -0
  61. package/src/iap.ts +700 -0
  62. package/src/{index.js → index.ts} +4 -1
  63. package/src/types/amazon.ts +23 -0
  64. package/src/types/android.ts +51 -0
  65. package/src/types/apple.ts +467 -0
  66. package/src/types/index.ts +185 -0
  67. package/.editorconfig +0 -10
  68. package/.flowconfig +0 -11
  69. package/.monolinterrc +0 -3
  70. package/.yarn/install-state.gz +0 -0
  71. package/.yarn/releases/yarn-3.2.0.cjs +0 -785
  72. package/.yarnrc.yml +0 -3
  73. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  74. package/android/gradle/wrapper/gradle-wrapper.properties +0 -6
  75. package/android/gradlew +0 -160
  76. package/android/gradlew.bat +0 -90
  77. package/android/src/play/java/com/dooboolab/RNIap/RNIapModuleInterface.kt +0 -44
  78. package/android/src/play/java/com/dooboolab/RNIap/RNIapModuleV4.kt +0 -656
  79. package/babel.config.js +0 -10
  80. package/index.d.ts +0 -3
  81. package/index.js +0 -3
  82. package/index.js.flow +0 -9
  83. package/ios/RNIap.xcodeproj/xcshareddata/xcschemes/RNIap.xcscheme +0 -80
  84. package/ios/RNIapQueue.swift +0 -36
  85. package/jest.config.js +0 -194
  86. package/src/__test__/iap.test.js +0 -59
  87. package/src/hooks/useIAP.js +0 -141
  88. package/src/hooks/withIAPContext.js +0 -150
  89. package/src/iap.js +0 -640
  90. package/src/types/amazon.js +0 -1
  91. package/src/types/android.js +0 -22
  92. package/src/types/apple.js +0 -165
  93. package/src/types/index.js +0 -40
  94. package/test/mocks/react-native-modules.js +0 -14
@@ -37,6 +37,7 @@ export declare enum InstallSourceAndroid {
37
37
  export interface ProductCommon {
38
38
  type: 'subs' | 'sub' | 'inapp' | 'iap';
39
39
  productId: string;
40
+ productIds?: string[];
40
41
  title: string;
41
42
  description: string;
42
43
  price: string;
@@ -53,6 +54,7 @@ export interface ProductPurchase {
53
54
  quantityIOS?: number;
54
55
  originalTransactionDateIOS?: string;
55
56
  originalTransactionIdentifierIOS?: string;
57
+ productIds?: string[];
56
58
  dataAndroid?: string;
57
59
  signatureAndroid?: string;
58
60
  autoRenewingAndroid?: boolean;
@@ -62,28 +64,6 @@ export interface ProductPurchase {
62
64
  developerPayloadAndroid?: string;
63
65
  obfuscatedAccountIdAndroid?: string;
64
66
  obfuscatedProfileIdAndroid?: string;
65
- title?: string;
66
- description?: string;
67
- productType?: string;
68
- name?: string;
69
- oneTimePurchaseOfferDetails?: {
70
- priceCurrencyCode?: string;
71
- formattedPrice?: string;
72
- priceAmountMicros?: string;
73
- }[];
74
- subscriptionOfferDetails?: {
75
- offerToken?: string[];
76
- pricingPhases: {
77
- pricingPhaseList: {
78
- formattedPrice?: string;
79
- priceCurrencyCode?: string;
80
- billingPeriod?: string;
81
- billingCycleCount?: number;
82
- priceAmountMicros?: string;
83
- recurrenceMode?: number;
84
- };
85
- };
86
- }[];
87
67
  userIdAmazon?: string;
88
68
  userMarketplaceAmazon?: string;
89
69
  userJsonAmazon?: string;
@@ -136,4 +116,37 @@ export interface Subscription extends ProductCommon {
136
116
  introductoryPricePeriodAndroid?: string;
137
117
  subscriptionPeriodAndroid?: string;
138
118
  freeTrialPeriodAndroid?: string;
119
+ productType?: string;
120
+ name?: string;
121
+ oneTimePurchaseOfferDetails?: {
122
+ priceCurrencyCode?: string;
123
+ formattedPrice?: string;
124
+ priceAmountMicros?: string;
125
+ }[];
126
+ subscriptionOfferDetails?: {
127
+ offerToken?: string[];
128
+ pricingPhases: {
129
+ pricingPhaseList: {
130
+ formattedPrice?: string;
131
+ priceCurrencyCode?: string;
132
+ billingPeriod?: string;
133
+ billingCycleCount?: number;
134
+ priceAmountMicros?: string;
135
+ recurrenceMode?: number;
136
+ };
137
+ };
138
+ }[];
139
+ }
140
+ export interface RequestPurchase {
141
+ sku: string;
142
+ andDangerouslyFinishTransactionAutomaticallyIOS?: boolean;
143
+ applicationUsername?: string;
144
+ obfuscatedAccountIdAndroid?: string;
145
+ obfuscatedProfileIdAndroid?: string;
146
+ }
147
+ export interface RequestSubscription extends RequestPurchase {
148
+ purchaseTokenAndroid?: string;
149
+ prorationModeAndroid?: ProrationModesAndroid;
150
+ selectedOfferIndices?: number[] | undefined;
151
+ skus?: string[] | undefined;
139
152
  }
package/package.json CHANGED
@@ -1,74 +1,104 @@
1
1
  {
2
2
  "name": "react-native-iap",
3
- "version": "9.0.0-beta",
4
- "packageManager": "yarn@3.2.0",
3
+ "version": "9.0.0-beta12",
5
4
  "description": "React Native In App Purchase Module.",
6
- "main": "index.js",
7
- "types": "index.d.ts",
8
- "postinstall": "dooboolab-welcome postinstall",
9
- "scripts": {
10
- "build": "tsc && flowgen index.d.ts -o index.js.flow",
11
- "flow": "flow",
12
- "lint": "eslint src --ext .ts,.tsx",
13
- "lint:android": "cd android ",
14
- "test": "jest",
15
- "test:flow": "flow",
16
- "test:typescript": "tsc --noEmit",
17
- "tsc:sync": "npx typesync",
18
- "tsc": "tsc",
19
- "validate": "yarn lint && yarn test:typescript && yarn test:flow && yarn test"
5
+ "repository": "https://github.com/dooboolab/react-native-iap",
6
+ "author": "dooboolab <support@dooboolab.com> (https://github.com/dooboolab)",
7
+ "license": "MIT",
8
+ "bugs": {
9
+ "url": "https://github.com/dooboolab/react-native-iap/issues"
20
10
  },
21
- "repository": {
22
- "type": "git",
23
- "url": "https://github.com/dooboolab/react-native-iap"
11
+ "homepage": "https://github.com/dooboolab/react-native-iap#readme",
12
+ "publishConfig": {
13
+ "registry": "https://registry.npmjs.org/"
24
14
  },
25
- "keywords": [
26
- "react-native",
27
- "in app purchase",
28
- "in-app-purchase",
29
- "billing"
30
- ],
31
- "author": "dooboolab",
32
15
  "contributors": [
33
16
  {
34
17
  "name": "Andres Aguilar",
35
18
  "url": "https://github.com/andresesfm"
19
+ },
20
+ {
21
+ "name": "Jérémy Barbet",
22
+ "url": "https://github.com/jeremybarbet"
36
23
  }
37
24
  ],
38
- "license": "MIT",
39
- "peerDependencies": {
40
- "react": ">=16.13.1",
41
- "react-native": ">=0.65.1"
42
- },
43
- "dependencies": {
44
- "dooboolab-welcome": "1.3.2"
25
+ "keywords": [
26
+ "react-native",
27
+ "react-native-iap",
28
+ "IAP",
29
+ "in app purchase",
30
+ "in-app-purchase",
31
+ "Billing",
32
+ "iOS",
33
+ "Android",
34
+ "Amazon",
35
+ "Play"
36
+ ],
37
+ "main": "lib/commonjs/index",
38
+ "module": "lib/module/index",
39
+ "types": "lib/typescript/index.d.ts",
40
+ "react-native": "src/index",
41
+ "source": "src/index",
42
+ "files": [
43
+ "src",
44
+ "lib",
45
+ "android",
46
+ "ios",
47
+ "cpp",
48
+ "RNIap.podspec",
49
+ "!lib/typescript/example",
50
+ "!android/build",
51
+ "!ios/build",
52
+ "!**/__tests__",
53
+ "!**/__fixtures__",
54
+ "!**/__mocks__"
55
+ ],
56
+ "scripts": {
57
+ "prepare": "bob build",
58
+ "release": "release-it",
59
+ "example": "yarn --cwd IapExample",
60
+ "test": "jest",
61
+ "lint": "yarn lint:tsc && yarn lint:eslint && yarn lint:prettier",
62
+ "lint:tsc": "tsc -p tsconfig.json --noEmit --skipLibCheck",
63
+ "lint:eslint": "eslint --fix '**/*.{ts,tsx}'",
64
+ "lint:ci": "yarn lint:tsc && yarn lint:eslint -f ./node_modules/@firmnav/eslint-github-actions-formatter/dist/formatter.js && yarn lint:prettier",
65
+ "lint:prettier": "prettier --write \"**/*.{md,js,jsx,ts,tsx}\"",
66
+ "format": "git ls-files -m | xargs yarn prettier --write --ignore-unknown --no-error-on-unmatched-pattern",
67
+ "bootstrap": "yarn example && yarn && yarn example pods"
45
68
  },
46
69
  "devDependencies": {
47
- "@babel/core": "7.18.2",
48
- "@babel/plugin-proposal-class-properties": "7.17.12",
49
- "@babel/plugin-proposal-private-methods": "7.17.12",
50
- "@babel/preset-env": "7.18.2",
51
- "@babel/preset-react": "7.17.12",
52
- "@babel/preset-typescript": "7.17.12",
53
- "@dooboo/eslint-config": "1.3.4",
70
+ "@babel/eslint-parser": "7.18.9",
71
+ "@firmnav/eslint-github-actions-formatter": "1.0.1",
72
+ "@react-native-community/eslint-config": "3.1.0",
73
+ "@release-it/conventional-changelog": "5.0.0",
54
74
  "@testing-library/jest-native": "4.0.5",
55
- "@testing-library/react-native": "9.1.0",
56
- "@types/eslint": "8.4.2",
57
- "@types/jest": "27.5.1",
58
- "@types/react": "18.0.10",
59
- "@types/react-native": "0.67.7",
60
- "@typescript-eslint/eslint-plugin": "^5.27.0",
61
- "babel-core": "7.0.0-bridge.0",
62
- "babel-jest": "28.1.0",
63
- "eslint": "8.16.0",
64
- "flow-bin": "0.179.0",
65
- "flowgen": "1.19.0",
66
- "jest": "28.1.0",
67
- "metro-react-native-babel-preset": "0.71.0",
75
+ "@testing-library/react-native": "11.0.0",
76
+ "@types/jest": "28.1.6",
77
+ "@types/react": "~17.0.47",
78
+ "@types/react-native": "0.68.2",
79
+ "@typescript-eslint/eslint-plugin": "5.32.0",
80
+ "@typescript-eslint/parser": "5.32.0",
81
+ "babel-jest": "28.1.3",
82
+ "eslint": "8.20.0",
83
+ "eslint-config-prettier": "8.5.0",
84
+ "eslint-plugin-prettier": "4.2.1",
85
+ "eslint-plugin-simple-import-sort": "7.0.0",
86
+ "jest": "28.1.3",
68
87
  "monolinter": "1.0.4",
69
- "prettier": "2.6.2",
70
- "react-native": "0.66.4",
71
- "ts-jest": "28.0.3",
72
- "typescript": "4.7.2"
88
+ "pod-install": "0.1.38",
89
+ "prettier": "2.7.1",
90
+ "react": "17.0.2",
91
+ "react-native": "0.68.2",
92
+ "react-native-builder-bob": "0.18.3",
93
+ "release-it": "15.2.0",
94
+ "ts-jest": "28.0.7",
95
+ "typescript": "4.7.4"
96
+ },
97
+ "resolutions": {
98
+ "@types/react": "17.0.21"
99
+ },
100
+ "peerDependencies": {
101
+ "react": ">=16.13.1",
102
+ "react-native": ">=0.65.1"
73
103
  }
74
104
  }
@@ -0,0 +1,20 @@
1
+ import {NativeModules} from 'react-native';
2
+
3
+ import {initConnection} from '../iap';
4
+
5
+ const rnLib = '../../node_modules/react-native/Libraries';
6
+
7
+ describe('Google Play IAP', () => {
8
+ beforeEach(() => {
9
+ jest.mock(rnLib + '/Utilities/Platform', () => ({
10
+ OS: 'android',
11
+ select: (dict: {[x: string]: any}) => dict.android,
12
+ }));
13
+ });
14
+
15
+ it("should call init on Google Play's native module but not on Amazon's", async () => {
16
+ await initConnection();
17
+ expect(NativeModules.RNIapModule.initConnection).toBeCalled();
18
+ expect(NativeModules.RNIapAmazonModule.initConnection).not.toBeCalled();
19
+ });
20
+ });
@@ -0,0 +1,130 @@
1
+ import {useCallback} from 'react';
2
+
3
+ import {
4
+ finishTransaction as iapFinishTransaction,
5
+ getAvailablePurchases as iapGetAvailablePurchases,
6
+ getProducts as iapGetProducts,
7
+ getPurchaseHistory,
8
+ getSubscriptions as iapGetSubscriptions,
9
+ requestPurchase as iapRequestPurchase,
10
+ requestSubscription as iapRequestSubscription,
11
+ } from '../iap';
12
+ import type {Product, Purchase, PurchaseError, Subscription} from '../types';
13
+
14
+ import {useIAPContext} from './withIAPContext';
15
+
16
+ type IAP_STATUS = {
17
+ connected: boolean;
18
+ products: Product[];
19
+ promotedProductsIOS: Product[];
20
+ subscriptions: Subscription[];
21
+ purchaseHistories: Purchase[];
22
+ availablePurchases: Purchase[];
23
+ currentPurchase?: Purchase;
24
+ currentPurchaseError?: PurchaseError;
25
+ initConnectionError?: Error;
26
+ finishTransaction: (
27
+ purchase: Purchase,
28
+ isConsumable?: boolean,
29
+ developerPayloadAndroid?: string,
30
+ ) => Promise<string | void>;
31
+ getAvailablePurchases: () => Promise<void>;
32
+ getPurchaseHistories: () => Promise<void>;
33
+ getProducts: (skus: string[]) => Promise<void>;
34
+ getSubscriptions: (skus: string[]) => Promise<void>;
35
+ requestPurchase: typeof iapRequestPurchase;
36
+ requestSubscription: typeof iapRequestSubscription;
37
+ };
38
+
39
+ export function useIAP(): IAP_STATUS {
40
+ const {
41
+ connected,
42
+ products,
43
+ promotedProductsIOS,
44
+ subscriptions,
45
+ purchaseHistories,
46
+ availablePurchases,
47
+ currentPurchase,
48
+ currentPurchaseError,
49
+ initConnectionError,
50
+ setProducts,
51
+ setSubscriptions,
52
+ setAvailablePurchases,
53
+ setPurchaseHistories,
54
+ setCurrentPurchase,
55
+ setCurrentPurchaseError,
56
+ } = useIAPContext();
57
+
58
+ const getProducts = useCallback(
59
+ async (skus: string[]): Promise<void> => {
60
+ setProducts(await iapGetProducts(skus));
61
+ },
62
+ [setProducts],
63
+ );
64
+
65
+ const getSubscriptions = useCallback(
66
+ async (skus: string[]): Promise<void> => {
67
+ setSubscriptions(await iapGetSubscriptions(skus));
68
+ },
69
+ [setSubscriptions],
70
+ );
71
+
72
+ const getAvailablePurchases = useCallback(async (): Promise<void> => {
73
+ setAvailablePurchases(await iapGetAvailablePurchases());
74
+ }, [setAvailablePurchases]);
75
+
76
+ const getPurchaseHistories = useCallback(async (): Promise<void> => {
77
+ setPurchaseHistories(await getPurchaseHistory());
78
+ }, [setPurchaseHistories]);
79
+
80
+ const finishTransaction = useCallback(
81
+ async (
82
+ purchase: Purchase,
83
+ isConsumable?: boolean,
84
+ developerPayloadAndroid?: string,
85
+ ): Promise<string | void> => {
86
+ try {
87
+ return await iapFinishTransaction(
88
+ purchase,
89
+ isConsumable,
90
+ developerPayloadAndroid,
91
+ );
92
+ } catch (err) {
93
+ throw err;
94
+ } finally {
95
+ if (purchase.productId === currentPurchase?.productId) {
96
+ setCurrentPurchase(undefined);
97
+ }
98
+
99
+ if (purchase.productId === currentPurchaseError?.productId) {
100
+ setCurrentPurchaseError(undefined);
101
+ }
102
+ }
103
+ },
104
+ [
105
+ currentPurchase?.productId,
106
+ currentPurchaseError?.productId,
107
+ setCurrentPurchase,
108
+ setCurrentPurchaseError,
109
+ ],
110
+ );
111
+
112
+ return {
113
+ connected,
114
+ products,
115
+ promotedProductsIOS,
116
+ subscriptions,
117
+ purchaseHistories,
118
+ availablePurchases,
119
+ currentPurchase,
120
+ currentPurchaseError,
121
+ initConnectionError,
122
+ finishTransaction,
123
+ getProducts,
124
+ getSubscriptions,
125
+ getAvailablePurchases,
126
+ getPurchaseHistories,
127
+ requestPurchase: iapRequestPurchase,
128
+ requestSubscription: iapRequestSubscription,
129
+ };
130
+ }
@@ -0,0 +1,160 @@
1
+ import React, {useContext, useEffect, useMemo, useState} from 'react';
2
+
3
+ import {
4
+ getPromotedProductIOS,
5
+ initConnection,
6
+ promotedProductListener,
7
+ purchaseErrorListener,
8
+ purchaseUpdatedListener,
9
+ } from '../iap';
10
+ import type {
11
+ InAppPurchase,
12
+ Product,
13
+ Purchase,
14
+ PurchaseError,
15
+ Subscription,
16
+ SubscriptionPurchase,
17
+ } from '../types';
18
+
19
+ type IAPContextType = {
20
+ connected: boolean;
21
+ products: Product[];
22
+ promotedProductsIOS: Product[];
23
+ subscriptions: Subscription[];
24
+ purchaseHistories: Purchase[];
25
+ availablePurchases: Purchase[];
26
+ currentPurchase?: Purchase;
27
+ currentPurchaseError?: PurchaseError;
28
+ initConnectionError?: Error;
29
+ setProducts: (products: Product[]) => void;
30
+ setSubscriptions: (subscriptions: Subscription[]) => void;
31
+ setPurchaseHistories: (purchaseHistories: Purchase[]) => void;
32
+ setAvailablePurchases: (availablePurchases: Purchase[]) => void;
33
+ setCurrentPurchase: (currentPurchase: Purchase | undefined) => void;
34
+ setCurrentPurchaseError: (
35
+ currentPurchaseError: PurchaseError | undefined,
36
+ ) => void;
37
+ };
38
+
39
+ // @ts-ignore
40
+ const IAPContext = React.createContext<IAPContextType>(null);
41
+
42
+ export function useIAPContext(): IAPContextType {
43
+ const ctx = useContext(IAPContext);
44
+
45
+ if (!ctx) {
46
+ throw new Error('You need wrap your app with withIAPContext HOC');
47
+ }
48
+
49
+ return ctx;
50
+ }
51
+
52
+ export function withIAPContext<T>(Component: React.ComponentType<T>) {
53
+ return function WrapperComponent(props: T) {
54
+ const [connected, setConnected] = useState(false);
55
+ const [products, setProducts] = useState<Product[]>([]);
56
+
57
+ const [promotedProductsIOS, setPromotedProductsIOS] = useState<Product[]>(
58
+ [],
59
+ );
60
+ const [subscriptions, setSubscriptions] = useState<Subscription[]>([]);
61
+ const [purchaseHistories, setPurchaseHistories] = useState<Purchase[]>([]);
62
+
63
+ const [availablePurchases, setAvailablePurchases] = useState<Purchase[]>(
64
+ [],
65
+ );
66
+ const [currentPurchase, setCurrentPurchase] = useState<Purchase>();
67
+
68
+ const [currentPurchaseError, setCurrentPurchaseError] =
69
+ useState<PurchaseError>();
70
+
71
+ const [initConnectionError, setInitConnectionError] = useState<Error>();
72
+
73
+ const context = useMemo(
74
+ () => ({
75
+ connected,
76
+ products,
77
+ subscriptions,
78
+ promotedProductsIOS,
79
+ purchaseHistories,
80
+ availablePurchases,
81
+ currentPurchase,
82
+ currentPurchaseError,
83
+ initConnectionError,
84
+ setProducts,
85
+ setSubscriptions,
86
+ setPurchaseHistories,
87
+ setAvailablePurchases,
88
+ setCurrentPurchase,
89
+ setCurrentPurchaseError,
90
+ }),
91
+ [
92
+ connected,
93
+ products,
94
+ subscriptions,
95
+ promotedProductsIOS,
96
+ purchaseHistories,
97
+ availablePurchases,
98
+ currentPurchase,
99
+ currentPurchaseError,
100
+ initConnectionError,
101
+ setProducts,
102
+ setSubscriptions,
103
+ setPurchaseHistories,
104
+ setAvailablePurchases,
105
+ setCurrentPurchase,
106
+ setCurrentPurchaseError,
107
+ ],
108
+ );
109
+
110
+ useEffect(() => {
111
+ initConnection()
112
+ .then((value) => {
113
+ setInitConnectionError(undefined);
114
+ setConnected(value);
115
+ })
116
+ .catch(setInitConnectionError);
117
+ }, []);
118
+
119
+ useEffect(() => {
120
+ if (!connected) {
121
+ return;
122
+ }
123
+
124
+ const purchaseUpdateSubscription = purchaseUpdatedListener(
125
+ async (purchase: InAppPurchase | SubscriptionPurchase) => {
126
+ setCurrentPurchaseError(undefined);
127
+ setCurrentPurchase(purchase);
128
+ },
129
+ );
130
+
131
+ const purchaseErrorSubscription = purchaseErrorListener(
132
+ (error: PurchaseError) => {
133
+ setCurrentPurchase(undefined);
134
+ setCurrentPurchaseError(error);
135
+ },
136
+ );
137
+
138
+ const promotedProductSubscription = promotedProductListener(async () => {
139
+ const product = await getPromotedProductIOS();
140
+
141
+ setPromotedProductsIOS((prevProducts) => [
142
+ ...prevProducts,
143
+ ...(product ? [product] : []),
144
+ ]);
145
+ });
146
+
147
+ return () => {
148
+ purchaseUpdateSubscription.remove();
149
+ purchaseErrorSubscription.remove();
150
+ promotedProductSubscription.remove();
151
+ };
152
+ }, [connected]);
153
+
154
+ return (
155
+ <IAPContext.Provider value={context}>
156
+ <Component {...props} />
157
+ </IAPContext.Provider>
158
+ );
159
+ };
160
+ }