react-native-iap 9.0.0-beta5 → 9.0.0-beta9

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 (93) hide show
  1. package/README.md +4 -20
  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 +68 -57
  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} +48 -34
  8. package/ios/RNIapIos-Bridging-Header.h +2 -0
  9. package/ios/RNIapIos.m +14 -2
  10. package/ios/RNIapIos.swift +903 -881
  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 +585 -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 +493 -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 +13 -11
  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 +25 -8
  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 +699 -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 +209 -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 -658
  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/jest.config.js +0 -194
  85. package/src/__test__/iap.test.js +0 -59
  86. package/src/hooks/useIAP.js +0 -141
  87. package/src/hooks/withIAPContext.js +0 -150
  88. package/src/iap.js +0 -638
  89. package/src/types/amazon.js +0 -1
  90. package/src/types/android.js +0 -22
  91. package/src/types/apple.js +0 -165
  92. package/src/types/index.js +0 -40
  93. package/test/mocks/react-native-modules.js +0 -14
package/package.json CHANGED
@@ -1,74 +1,104 @@
1
1
  {
2
2
  "name": "react-native-iap",
3
- "version": "9.0.0-beta5",
4
- "packageManager": "yarn@3.2.0",
3
+ "version": "9.0.0-beta9",
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
+ }