react-native-iap 11.0.0-rc.2 → 11.0.0-rc.4
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/ios/IapSerializationUtils.swift +50 -11
- package/ios/IapTypes.swift +1 -6
- package/ios/RNIapIos.m +3 -0
- package/ios/RNIapIos.swift +12 -3
- package/ios/RNIapIosSk2.m +6 -1
- package/ios/RNIapIosSk2.swift +37 -16
- package/lib/commonjs/eventEmitter.js +145 -2
- package/lib/commonjs/eventEmitter.js.map +1 -1
- package/lib/commonjs/hooks/withIAPContext.js +8 -1
- package/lib/commonjs/hooks/withIAPContext.js.map +1 -1
- package/lib/commonjs/iap.js +81 -37
- package/lib/commonjs/iap.js.map +1 -1
- package/lib/commonjs/internal/platform.js +33 -4
- package/lib/commonjs/internal/platform.js.map +1 -1
- package/lib/commonjs/modules/ios.js +5 -2
- package/lib/commonjs/modules/ios.js.map +1 -1
- package/lib/commonjs/modules/iosSk2.js.map +1 -1
- package/lib/commonjs/types/apple.js +24 -0
- package/lib/commonjs/types/apple.js.map +1 -1
- package/lib/commonjs/types/appleSk2.js +3 -3
- package/lib/commonjs/types/appleSk2.js.map +1 -1
- package/lib/commonjs/types/index.js.map +1 -1
- package/lib/module/eventEmitter.js +141 -1
- package/lib/module/eventEmitter.js.map +1 -1
- package/lib/module/hooks/withIAPContext.js +9 -2
- package/lib/module/hooks/withIAPContext.js.map +1 -1
- package/lib/module/iap.js +77 -30
- package/lib/module/iap.js.map +1 -1
- package/lib/module/internal/platform.js +25 -2
- package/lib/module/internal/platform.js.map +1 -1
- package/lib/module/modules/ios.js +5 -2
- package/lib/module/modules/ios.js.map +1 -1
- package/lib/module/modules/iosSk2.js.map +1 -1
- package/lib/module/types/apple.js +15 -0
- package/lib/module/types/apple.js.map +1 -1
- package/lib/module/types/appleSk2.js +3 -3
- package/lib/module/types/appleSk2.js.map +1 -1
- package/lib/module/types/index.js.map +1 -1
- package/lib/typescript/eventEmitter.d.ts +133 -0
- package/lib/typescript/hooks/withIAPContext.d.ts +2 -0
- package/lib/typescript/iap.d.ts +25 -4
- package/lib/typescript/internal/platform.d.ts +3 -1
- package/lib/typescript/modules/ios.d.ts +2 -1
- package/lib/typescript/modules/iosSk2.d.ts +3 -2
- package/lib/typescript/types/apple.d.ts +1 -0
- package/lib/typescript/types/appleSk2.d.ts +31 -2
- package/lib/typescript/types/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/eventEmitter.ts +144 -2
- package/src/hooks/withIAPContext.tsx +15 -0
- package/src/iap.ts +55 -17
- package/src/internal/platform.ts +24 -2
- package/src/modules/ios.ts +7 -3
- package/src/modules/iosSk2.ts +5 -2
- package/src/types/apple.ts +15 -0
- package/src/types/appleSk2.ts +42 -5
- package/src/types/index.ts +1 -0
package/lib/typescript/iap.d.ts
CHANGED
|
@@ -2,9 +2,22 @@ import * as IapAmazon from './modules/amazon';
|
|
|
2
2
|
import * as IapAndroid from './modules/android';
|
|
3
3
|
import * as IapIos from './modules/ios';
|
|
4
4
|
import * as IapIosSk2 from './modules/iosSk2';
|
|
5
|
-
import {
|
|
5
|
+
import { isIosStorekit2 } from './internal';
|
|
6
6
|
import { Product, ProductPurchase, PurchaseResult, RequestPurchase, RequestSubscription, Subscription, SubscriptionPurchase } from './types';
|
|
7
|
-
export { IapAndroid, IapAmazon, IapIos, IapIosSk2, isIosStorekit2
|
|
7
|
+
export { IapAndroid, IapAmazon, IapIos, IapIosSk2, isIosStorekit2 };
|
|
8
|
+
/**
|
|
9
|
+
* STOREKIT1_MODE: Will not enable Storekit 2 even if the device supports it. Thigs will work as before,
|
|
10
|
+
* minimum changes required in the migration guide (default)
|
|
11
|
+
* HYBRID_MODE: Will enable Storekit 2 for iOS devices > 15.0 but will fallback to Sk1 on older devices
|
|
12
|
+
* There are some edge cases that you need to handle in this case (described in migration guide). This mode
|
|
13
|
+
* is for developers that are migrating to Storekit 2 but want to keep supporting older versions.
|
|
14
|
+
* STOREKIT2_MODE: Will *only* enable Storekit 2. This disables Storekit 1. This is for apps that
|
|
15
|
+
* have already targeted a min version of 15 for their app.
|
|
16
|
+
*/
|
|
17
|
+
export declare type STOREKIT_OPTIONS = 'STOREKIT1_MODE' | 'STOREKIT_HYBRID_MODE' | 'STOREKIT2_MODE';
|
|
18
|
+
export declare const setup: ({ storekitMode, }?: {
|
|
19
|
+
storekitMode?: STOREKIT_OPTIONS | undefined;
|
|
20
|
+
}) => void;
|
|
8
21
|
/**
|
|
9
22
|
* Init module for purchase flow. Required on Android. In ios it will check whether user canMakePayment.
|
|
10
23
|
* ## Usage
|
|
@@ -143,8 +156,12 @@ const App = () => {
|
|
|
143
156
|
return <View />;
|
|
144
157
|
};
|
|
145
158
|
```
|
|
159
|
+
@param {alsoPublishToEventListener}:boolean When `true`, every element will also be pushed to the purchaseUpdated listener.
|
|
160
|
+
Note that this is only for backaward compatiblity. It won't publish to transactionUpdated (Storekit2) Defaults to `false`
|
|
146
161
|
*/
|
|
147
|
-
export declare const getPurchaseHistory: (
|
|
162
|
+
export declare const getPurchaseHistory: ({ alsoPublishToEventListener, }?: {
|
|
163
|
+
alsoPublishToEventListener?: boolean | undefined;
|
|
164
|
+
}) => Promise<(ProductPurchase | SubscriptionPurchase)[]>;
|
|
148
165
|
/**
|
|
149
166
|
* Get all purchases made by the user (either non-consumable, or haven't been consumed yet)
|
|
150
167
|
* ## Usage
|
|
@@ -221,9 +238,13 @@ const App = () => {
|
|
|
221
238
|
)
|
|
222
239
|
};
|
|
223
240
|
```
|
|
241
|
+
@param {alsoPublishToEventListener}:boolean When `true`, every element will also be pushed to the purchaseUpdated listener.
|
|
242
|
+
Note that this is only for backaward compatiblity. It won't publish to transactionUpdated (Storekit2) Defaults to `false`
|
|
224
243
|
*
|
|
225
244
|
*/
|
|
226
|
-
export declare const getAvailablePurchases: (
|
|
245
|
+
export declare const getAvailablePurchases: ({ alsoPublishToEventListener, }?: {
|
|
246
|
+
alsoPublishToEventListener?: boolean | undefined;
|
|
247
|
+
}) => Promise<(ProductPurchase | SubscriptionPurchase)[]>;
|
|
227
248
|
/**
|
|
228
249
|
* Request a purchase for product. This will be received in `PurchaseUpdatedListener`.
|
|
229
250
|
* Request a purchase for a product (consumables or non-consumables).
|
|
@@ -8,5 +8,7 @@ export declare const getNativeModule: () => import("..").AmazonModuleProps | imp
|
|
|
8
8
|
export declare const isIosStorekit2: () => boolean;
|
|
9
9
|
export declare const isStorekit2Avaiable: () => boolean;
|
|
10
10
|
export declare const setIosNativeModule: (nativeModule: import("..").IosModuleProps | import("../modules/iosSk2").IosModulePropsSk2) => void;
|
|
11
|
-
export declare const
|
|
11
|
+
export declare const storekit2Mode: () => boolean;
|
|
12
|
+
export declare const storekit1Mode: () => boolean;
|
|
13
|
+
export declare const storekitHybridMode: () => boolean;
|
|
12
14
|
export declare const getIosModule: () => import("..").IosModuleProps | import("../modules/iosSk2").IosModulePropsSk2;
|
|
@@ -4,7 +4,7 @@ import type { PaymentDiscount } from '../types/apple';
|
|
|
4
4
|
import type { NativeModuleProps } from './common';
|
|
5
5
|
declare type getItems = (skus: Sku[]) => Promise<Product[] | Subscription[]>;
|
|
6
6
|
declare type getAvailableItems = () => Promise<Purchase[]>;
|
|
7
|
-
export declare type BuyProduct = (sku: Sku, andDangerouslyFinishTransactionAutomaticallyIOS: boolean, applicationUsername: string | undefined, quantity: number, withOffer: PaymentDiscount | undefined) => Promise<Purchase>;
|
|
7
|
+
export declare type BuyProduct = (sku: Sku, andDangerouslyFinishTransactionAutomaticallyIOS: boolean, applicationUsername: string | undefined, quantity: number, withOffer: Record<keyof PaymentDiscount, string> | undefined) => Promise<Purchase>;
|
|
8
8
|
declare type clearTransaction = () => Promise<void>;
|
|
9
9
|
declare type clearProducts = () => Promise<void>;
|
|
10
10
|
declare type promotedProduct = () => Promise<Product | null>;
|
|
@@ -25,6 +25,7 @@ export interface IosModuleProps extends NativeModuleProps {
|
|
|
25
25
|
finishTransaction: finishTransaction;
|
|
26
26
|
getPendingTransactions: getPendingTransactions;
|
|
27
27
|
presentCodeRedemptionSheet: presentCodeRedemptionSheet;
|
|
28
|
+
disable: () => Promise<null>;
|
|
28
29
|
}
|
|
29
30
|
/**
|
|
30
31
|
* Get the current receipt base64 encoded in IOS.
|
|
@@ -2,8 +2,8 @@ import type { Product, ProductPurchase, Purchase, Sku } from '../types';
|
|
|
2
2
|
import type { PaymentDiscountSk2, ProductSk2, ProductStatus, TransactionSk2 } from '../types/appleSk2';
|
|
3
3
|
import type { NativeModuleProps } from './common';
|
|
4
4
|
declare type getItems = (skus: Sku[]) => Promise<ProductSk2[]>;
|
|
5
|
-
declare type getAvailableItems = () => Promise<Purchase[]>;
|
|
6
|
-
export declare type BuyProduct = (sku: Sku, andDangerouslyFinishTransactionAutomaticallyIOS: boolean, applicationUsername: string | undefined, quantity: number, withOffer: PaymentDiscountSk2 | undefined) => Promise<Purchase>;
|
|
5
|
+
declare type getAvailableItems = (alsoPublishToEventListener?: boolean) => Promise<Purchase[]>;
|
|
6
|
+
export declare type BuyProduct = (sku: Sku, andDangerouslyFinishTransactionAutomaticallyIOS: boolean, applicationUsername: string | undefined, quantity: number, withOffer: Record<keyof PaymentDiscountSk2, string> | undefined) => Promise<Purchase>;
|
|
7
7
|
declare type clearTransaction = () => Promise<void>;
|
|
8
8
|
declare type clearProducts = () => Promise<void>;
|
|
9
9
|
declare type promotedProduct = () => Promise<Product | null>;
|
|
@@ -29,6 +29,7 @@ export interface IosModulePropsSk2 extends NativeModuleProps {
|
|
|
29
29
|
finishTransaction: finishTransaction;
|
|
30
30
|
getPendingTransactions: getPendingTransactions;
|
|
31
31
|
presentCodeRedemptionSheet: presentCodeRedemptionSheet;
|
|
32
|
+
disable: () => Promise<null>;
|
|
32
33
|
}
|
|
33
34
|
/**
|
|
34
35
|
* Sync state with Appstore (iOS only)
|
|
@@ -1,5 +1,26 @@
|
|
|
1
|
+
import type { PurchaseError } from '../purchaseError';
|
|
1
2
|
import type { ProductIOS, Purchase, SubscriptionIOS } from '.';
|
|
2
3
|
import type * as Apple from './apple';
|
|
4
|
+
export declare type SubscriptionPeriod = {
|
|
5
|
+
unit: 'day' | 'week' | 'month' | 'year';
|
|
6
|
+
value: number;
|
|
7
|
+
};
|
|
8
|
+
export declare type PaymentMode = 'freeTrial' | 'payAsYouGo' | 'payUpFront';
|
|
9
|
+
export declare type SubscriptionOffer = {
|
|
10
|
+
displayPrice: string;
|
|
11
|
+
id: string;
|
|
12
|
+
paymentMode: PaymentMode;
|
|
13
|
+
period: SubscriptionPeriod;
|
|
14
|
+
periodCount: number;
|
|
15
|
+
price: number;
|
|
16
|
+
type: 'introductory' | 'promotional';
|
|
17
|
+
};
|
|
18
|
+
export declare type SubscriptionInfo = {
|
|
19
|
+
introductoryOffer?: SubscriptionOffer;
|
|
20
|
+
promotionalOffers?: SubscriptionOffer[];
|
|
21
|
+
subscriptionGroupID: string;
|
|
22
|
+
subscriptionPeriod: SubscriptionPeriod;
|
|
23
|
+
};
|
|
3
24
|
export declare type ProductSk2 = {
|
|
4
25
|
description: string;
|
|
5
26
|
displayName: string;
|
|
@@ -8,7 +29,7 @@ export declare type ProductSk2 = {
|
|
|
8
29
|
isFamilyShareable: boolean;
|
|
9
30
|
jsonRepresentation: string;
|
|
10
31
|
price: number;
|
|
11
|
-
subscription:
|
|
32
|
+
subscription: SubscriptionInfo;
|
|
12
33
|
type: 'autoRenewable' | 'consumable' | 'nonConsumable' | 'nonRenewable';
|
|
13
34
|
};
|
|
14
35
|
export declare const productSk2Map: ({ id, description, displayName, price, displayPrice, }: ProductSk2) => ProductIOS;
|
|
@@ -38,6 +59,14 @@ export declare type TransactionSk2 = {
|
|
|
38
59
|
subscriptionGroupID: number;
|
|
39
60
|
webOrderLineItemID: number;
|
|
40
61
|
};
|
|
62
|
+
export declare type TransactionError = PurchaseError;
|
|
63
|
+
/**
|
|
64
|
+
* Only one of `transaction` and `error` is not undefined at the time
|
|
65
|
+
*/
|
|
66
|
+
export declare type TransactionEvent = {
|
|
67
|
+
transaction?: TransactionSk2;
|
|
68
|
+
error?: TransactionError;
|
|
69
|
+
};
|
|
41
70
|
export declare type SubscriptionStatus = 'expired' | 'inBillingRetryPeriod' | 'inGracePeriod' | 'revoked' | 'subscribed';
|
|
42
71
|
export declare type ProductStatus = {
|
|
43
72
|
state: SubscriptionStatus;
|
|
@@ -68,4 +97,4 @@ export interface PaymentDiscountSk2 {
|
|
|
68
97
|
*/
|
|
69
98
|
timestamp: number;
|
|
70
99
|
}
|
|
71
|
-
export declare const offerSk2Map: (offer: Apple.PaymentDiscount | undefined) => PaymentDiscountSk2 | undefined;
|
|
100
|
+
export declare const offerSk2Map: (offer: Apple.PaymentDiscount | undefined) => Record<keyof PaymentDiscountSk2, string> | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-iap",
|
|
3
|
-
"version": "11.0.0-rc.
|
|
3
|
+
"version": "11.0.0-rc.4",
|
|
4
4
|
"description": "React Native In App Purchase Module.",
|
|
5
5
|
"repository": "https://github.com/dooboolab/react-native-iap",
|
|
6
6
|
"author": "dooboolab <support@dooboolab.com> (https://github.com/dooboolab)",
|
package/src/eventEmitter.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {EmitterSubscription, NativeEventEmitter} from 'react-native';
|
|
2
2
|
|
|
3
|
-
import {transactionSk2Map} from './types/appleSk2';
|
|
3
|
+
import {TransactionEvent, transactionSk2Map} from './types/appleSk2';
|
|
4
4
|
import {isIosStorekit2} from './iap';
|
|
5
5
|
import {
|
|
6
6
|
getAndroidModule,
|
|
@@ -14,6 +14,35 @@ import type {Purchase} from './types';
|
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Add IAP purchase event
|
|
17
|
+
* Register a callback that gets called when the store has any updates to purchases that have not yet been finished, consumed or acknowledged. Returns a React Native `EmitterSubscription` on which you can call `.remove()` to stop receiving updates. Register you listener as soon as possible and react to updates at all times.
|
|
18
|
+
|
|
19
|
+
## Signature
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
purchaseUpdatedListener((purchase: Purchase) => {});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import React, {useEffect} from 'react';
|
|
29
|
+
import {View} from 'react-native';
|
|
30
|
+
import {purchaseUpdatedListener} from 'react-native-iap';
|
|
31
|
+
|
|
32
|
+
const App = () => {
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
const subscription = purchaseUpdatedListener((purchase: Purchase) => {
|
|
35
|
+
console.log(purchase);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return () => {
|
|
39
|
+
subscription.remove();
|
|
40
|
+
};
|
|
41
|
+
}, []);
|
|
42
|
+
|
|
43
|
+
return <View />;
|
|
44
|
+
};
|
|
45
|
+
```
|
|
17
46
|
*/
|
|
18
47
|
export const purchaseUpdatedListener = (
|
|
19
48
|
listener: (event: Purchase) => void,
|
|
@@ -38,6 +67,36 @@ export const purchaseUpdatedListener = (
|
|
|
38
67
|
|
|
39
68
|
/**
|
|
40
69
|
* Add IAP purchase error event
|
|
70
|
+
* Register a callback that gets called when there has been an error with a purchase. Returns a React Native `EmitterSubscription` on which you can call `.remove()` to stop receiving updates.
|
|
71
|
+
|
|
72
|
+
## Signature
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
purchaseErrorListener((error: PurchaseError) => {});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Usage
|
|
79
|
+
|
|
80
|
+
```tsx
|
|
81
|
+
import React, {useEffect} from 'react';
|
|
82
|
+
import {View} from 'react-native';
|
|
83
|
+
import {purchaseErrorListener} from 'react-native-iap';
|
|
84
|
+
|
|
85
|
+
const App = () => {
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
const subscription = purchaseErrorListener((error: PurchaseError) => {
|
|
88
|
+
console.log(error);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return () => {
|
|
92
|
+
subscription.remove();
|
|
93
|
+
};
|
|
94
|
+
}, []);
|
|
95
|
+
|
|
96
|
+
return <View />;
|
|
97
|
+
};
|
|
98
|
+
```
|
|
99
|
+
|
|
41
100
|
*/
|
|
42
101
|
export const purchaseErrorListener = (
|
|
43
102
|
listener: (error: PurchaseError) => void,
|
|
@@ -48,14 +107,97 @@ export const purchaseErrorListener = (
|
|
|
48
107
|
|
|
49
108
|
/**
|
|
50
109
|
* Add IAP promoted subscription event
|
|
110
|
+
* Add IAP promoted subscription event.
|
|
111
|
+
|
|
112
|
+
## Signature
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
promotedProductListener((productId?: string) => {});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Usage
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import React, {useEffect} from 'react';
|
|
122
|
+
import {View} from 'react-native';
|
|
123
|
+
import {promotedProductListener} from 'react-native-iap';
|
|
124
|
+
|
|
125
|
+
const App = () => {
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
const subscription = promotedProductListener((productId) => {
|
|
128
|
+
console.log(productId);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
return () => {
|
|
132
|
+
subscription.remove();
|
|
133
|
+
};
|
|
134
|
+
}, []);
|
|
135
|
+
|
|
136
|
+
return <View />;
|
|
137
|
+
};
|
|
138
|
+
```
|
|
139
|
+
|
|
51
140
|
*
|
|
52
141
|
* @platform iOS
|
|
53
142
|
*/
|
|
54
143
|
export const promotedProductListener = (listener: () => void) => {
|
|
55
|
-
if (isIos) {
|
|
144
|
+
if (isIos && !isIosStorekit2()) {
|
|
56
145
|
const eventEmitter = new NativeEventEmitter(getIosModule());
|
|
57
146
|
return eventEmitter.addListener('iap-promoted-product', listener);
|
|
58
147
|
}
|
|
59
148
|
|
|
60
149
|
return null;
|
|
61
150
|
};
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Updated transactions for iOS Sk2
|
|
154
|
+
* Register a callback that gets called when the store has any updates to transactions related to purchases that have not yet been finished, consumed or acknowledged.
|
|
155
|
+
* Returns a React Native `EmitterSubscription` on which you can call `.remove()` to stop receiving updates. Register you listener as soon as possible and react to updates at all times.
|
|
156
|
+
|
|
157
|
+
**Warning**
|
|
158
|
+
This is only available for iOS 15 and higher and Storekit 2 is activated
|
|
159
|
+
|
|
160
|
+
## Signature
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
purchaseUpdatedListener((transactionOrError: TransactionOrError) => {});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Usage
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
import React, {useEffect} from 'react';
|
|
170
|
+
import {View} from 'react-native';
|
|
171
|
+
import {purchaseUpdatedListener} from 'react-native-iap';
|
|
172
|
+
|
|
173
|
+
const App = () => {
|
|
174
|
+
useEffect(() => {
|
|
175
|
+
const subscription = purchaseUpdatedListener((transactionOrError: TransactionOrError) => {
|
|
176
|
+
if(transactionOrError.transaction){
|
|
177
|
+
console.log("There's an update to a transaction", transactionOrError.transaction);
|
|
178
|
+
}else{
|
|
179
|
+
console.log("There's been an error with a received transaction")
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
return () => {
|
|
184
|
+
subscription.remove();
|
|
185
|
+
};
|
|
186
|
+
}, []);
|
|
187
|
+
|
|
188
|
+
return <View />;
|
|
189
|
+
};
|
|
190
|
+
```
|
|
191
|
+
*
|
|
192
|
+
* @platform iOS (Sk2)
|
|
193
|
+
*/
|
|
194
|
+
export const transactionListener = (
|
|
195
|
+
listener: (event: TransactionEvent) => void,
|
|
196
|
+
) => {
|
|
197
|
+
if (isIos && isIosStorekit2()) {
|
|
198
|
+
const eventEmitter = new NativeEventEmitter(getIosModule());
|
|
199
|
+
return eventEmitter.addListener('iap-transaction-updated', listener);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return null;
|
|
203
|
+
};
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
promotedProductListener,
|
|
5
5
|
purchaseErrorListener,
|
|
6
6
|
purchaseUpdatedListener,
|
|
7
|
+
transactionListener,
|
|
7
8
|
} from '../eventEmitter';
|
|
8
9
|
import {IapIos, initConnection} from '../iap';
|
|
9
10
|
import type {PurchaseError} from '../purchaseError';
|
|
@@ -14,6 +15,7 @@ import type {
|
|
|
14
15
|
Subscription,
|
|
15
16
|
SubscriptionPurchase,
|
|
16
17
|
} from '../types';
|
|
18
|
+
import type {TransactionEvent, TransactionSk2} from '../types/appleSk2';
|
|
17
19
|
|
|
18
20
|
type IAPContextType = {
|
|
19
21
|
connected: boolean;
|
|
@@ -23,6 +25,7 @@ type IAPContextType = {
|
|
|
23
25
|
purchaseHistory: Purchase[];
|
|
24
26
|
availablePurchases: Purchase[];
|
|
25
27
|
currentPurchase?: Purchase;
|
|
28
|
+
currentTransaction?: TransactionSk2;
|
|
26
29
|
currentPurchaseError?: PurchaseError;
|
|
27
30
|
initConnectionError?: Error;
|
|
28
31
|
setProducts: (products: Product[]) => void;
|
|
@@ -63,6 +66,8 @@ export function withIAPContext<T>(Component: React.ComponentType<T>) {
|
|
|
63
66
|
[],
|
|
64
67
|
);
|
|
65
68
|
const [currentPurchase, setCurrentPurchase] = useState<Purchase>();
|
|
69
|
+
const [currentTransaction, setCurrentTransaction] =
|
|
70
|
+
useState<TransactionSk2>();
|
|
66
71
|
|
|
67
72
|
const [currentPurchaseError, setCurrentPurchaseError] =
|
|
68
73
|
useState<PurchaseError>();
|
|
@@ -78,6 +83,7 @@ export function withIAPContext<T>(Component: React.ComponentType<T>) {
|
|
|
78
83
|
purchaseHistory,
|
|
79
84
|
availablePurchases,
|
|
80
85
|
currentPurchase,
|
|
86
|
+
currentTransaction,
|
|
81
87
|
currentPurchaseError,
|
|
82
88
|
initConnectionError,
|
|
83
89
|
setProducts,
|
|
@@ -95,6 +101,7 @@ export function withIAPContext<T>(Component: React.ComponentType<T>) {
|
|
|
95
101
|
purchaseHistory,
|
|
96
102
|
availablePurchases,
|
|
97
103
|
currentPurchase,
|
|
104
|
+
currentTransaction,
|
|
98
105
|
currentPurchaseError,
|
|
99
106
|
initConnectionError,
|
|
100
107
|
setProducts,
|
|
@@ -127,6 +134,13 @@ export function withIAPContext<T>(Component: React.ComponentType<T>) {
|
|
|
127
134
|
},
|
|
128
135
|
);
|
|
129
136
|
|
|
137
|
+
const transactionUpdateSubscription = transactionListener(
|
|
138
|
+
async (transactionOrError: TransactionEvent) => {
|
|
139
|
+
setCurrentPurchaseError(transactionOrError?.error);
|
|
140
|
+
setCurrentTransaction(transactionOrError?.transaction);
|
|
141
|
+
},
|
|
142
|
+
);
|
|
143
|
+
|
|
130
144
|
const purchaseErrorSubscription = purchaseErrorListener(
|
|
131
145
|
(error: PurchaseError) => {
|
|
132
146
|
setCurrentPurchase(undefined);
|
|
@@ -147,6 +161,7 @@ export function withIAPContext<T>(Component: React.ComponentType<T>) {
|
|
|
147
161
|
purchaseUpdateSubscription.remove();
|
|
148
162
|
purchaseErrorSubscription.remove();
|
|
149
163
|
promotedProductSubscription?.remove();
|
|
164
|
+
transactionUpdateSubscription?.remove();
|
|
150
165
|
};
|
|
151
166
|
}, [connected]);
|
|
152
167
|
|
package/src/iap.ts
CHANGED
|
@@ -4,6 +4,7 @@ import * as IapAmazon from './modules/amazon';
|
|
|
4
4
|
import * as IapAndroid from './modules/android';
|
|
5
5
|
import * as IapIos from './modules/ios';
|
|
6
6
|
import * as IapIosSk2 from './modules/iosSk2';
|
|
7
|
+
import {offerToRecord} from './types/apple';
|
|
7
8
|
import {
|
|
8
9
|
offerSk2Map,
|
|
9
10
|
ProductSk2,
|
|
@@ -11,13 +12,15 @@ import {
|
|
|
11
12
|
subscriptionSk2Map,
|
|
12
13
|
} from './types/appleSk2';
|
|
13
14
|
import {
|
|
14
|
-
enableStorekit2,
|
|
15
15
|
fillProductsWithAdditionalData,
|
|
16
16
|
getAndroidModule,
|
|
17
17
|
getIosModule,
|
|
18
18
|
getNativeModule,
|
|
19
19
|
isAmazon,
|
|
20
20
|
isIosStorekit2,
|
|
21
|
+
storekit1Mode,
|
|
22
|
+
storekit2Mode,
|
|
23
|
+
storekitHybridMode,
|
|
21
24
|
} from './internal';
|
|
22
25
|
import {
|
|
23
26
|
Product,
|
|
@@ -31,19 +34,46 @@ import {
|
|
|
31
34
|
} from './types';
|
|
32
35
|
import {PurchaseStateAndroid} from './types';
|
|
33
36
|
|
|
34
|
-
export {
|
|
35
|
-
IapAndroid,
|
|
36
|
-
IapAmazon,
|
|
37
|
-
IapIos,
|
|
38
|
-
IapIosSk2,
|
|
39
|
-
isIosStorekit2,
|
|
40
|
-
enableStorekit2,
|
|
41
|
-
};
|
|
37
|
+
export {IapAndroid, IapAmazon, IapIos, IapIosSk2, isIosStorekit2};
|
|
42
38
|
|
|
43
39
|
const {RNIapIos, RNIapIosSk2, RNIapModule, RNIapAmazonModule} = NativeModules;
|
|
44
40
|
const ANDROID_ITEM_TYPE_SUBSCRIPTION = ProductType.subs;
|
|
45
41
|
const ANDROID_ITEM_TYPE_IAP = ProductType.inapp;
|
|
46
42
|
|
|
43
|
+
/**
|
|
44
|
+
* STOREKIT1_MODE: Will not enable Storekit 2 even if the device supports it. Thigs will work as before,
|
|
45
|
+
* minimum changes required in the migration guide (default)
|
|
46
|
+
* HYBRID_MODE: Will enable Storekit 2 for iOS devices > 15.0 but will fallback to Sk1 on older devices
|
|
47
|
+
* There are some edge cases that you need to handle in this case (described in migration guide). This mode
|
|
48
|
+
* is for developers that are migrating to Storekit 2 but want to keep supporting older versions.
|
|
49
|
+
* STOREKIT2_MODE: Will *only* enable Storekit 2. This disables Storekit 1. This is for apps that
|
|
50
|
+
* have already targeted a min version of 15 for their app.
|
|
51
|
+
*/
|
|
52
|
+
export type STOREKIT_OPTIONS =
|
|
53
|
+
| 'STOREKIT1_MODE'
|
|
54
|
+
| 'STOREKIT_HYBRID_MODE'
|
|
55
|
+
| 'STOREKIT2_MODE';
|
|
56
|
+
|
|
57
|
+
export const setup = ({
|
|
58
|
+
storekitMode = 'STOREKIT1_MODE',
|
|
59
|
+
}: {
|
|
60
|
+
storekitMode?: STOREKIT_OPTIONS;
|
|
61
|
+
} = {}) => {
|
|
62
|
+
switch (storekitMode) {
|
|
63
|
+
case 'STOREKIT1_MODE':
|
|
64
|
+
storekit1Mode();
|
|
65
|
+
break;
|
|
66
|
+
case 'STOREKIT2_MODE':
|
|
67
|
+
storekit2Mode();
|
|
68
|
+
break;
|
|
69
|
+
case 'STOREKIT_HYBRID_MODE':
|
|
70
|
+
storekitHybridMode();
|
|
71
|
+
break;
|
|
72
|
+
default:
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
47
77
|
/**
|
|
48
78
|
* Init module for purchase flow. Required on Android. In ios it will check whether user canMakePayment.
|
|
49
79
|
* ## Usage
|
|
@@ -248,14 +278,18 @@ const App = () => {
|
|
|
248
278
|
return <View />;
|
|
249
279
|
};
|
|
250
280
|
```
|
|
281
|
+
@param {alsoPublishToEventListener}:boolean When `true`, every element will also be pushed to the purchaseUpdated listener.
|
|
282
|
+
Note that this is only for backaward compatiblity. It won't publish to transactionUpdated (Storekit2) Defaults to `false`
|
|
251
283
|
*/
|
|
252
|
-
export const getPurchaseHistory = (
|
|
253
|
-
|
|
254
|
-
|
|
284
|
+
export const getPurchaseHistory = ({
|
|
285
|
+
alsoPublishToEventListener = false,
|
|
286
|
+
}: {
|
|
287
|
+
alsoPublishToEventListener?: boolean;
|
|
288
|
+
} = {}): Promise<(ProductPurchase | SubscriptionPurchase)[]> =>
|
|
255
289
|
(
|
|
256
290
|
Platform.select({
|
|
257
291
|
ios: async () => {
|
|
258
|
-
return getIosModule().getAvailableItems();
|
|
292
|
+
return getIosModule().getAvailableItems(alsoPublishToEventListener);
|
|
259
293
|
},
|
|
260
294
|
android: async () => {
|
|
261
295
|
if (RNIapAmazonModule) {
|
|
@@ -351,15 +385,19 @@ const App = () => {
|
|
|
351
385
|
)
|
|
352
386
|
};
|
|
353
387
|
```
|
|
388
|
+
@param {alsoPublishToEventListener}:boolean When `true`, every element will also be pushed to the purchaseUpdated listener.
|
|
389
|
+
Note that this is only for backaward compatiblity. It won't publish to transactionUpdated (Storekit2) Defaults to `false`
|
|
354
390
|
*
|
|
355
391
|
*/
|
|
356
|
-
export const getAvailablePurchases = (
|
|
392
|
+
export const getAvailablePurchases = ({
|
|
393
|
+
alsoPublishToEventListener = false,
|
|
394
|
+
}: {alsoPublishToEventListener?: boolean} = {}): Promise<
|
|
357
395
|
(ProductPurchase | SubscriptionPurchase)[]
|
|
358
396
|
> =>
|
|
359
397
|
(
|
|
360
398
|
Platform.select({
|
|
361
399
|
ios: async () => {
|
|
362
|
-
return getIosModule().getAvailableItems();
|
|
400
|
+
return getIosModule().getAvailableItems(alsoPublishToEventListener);
|
|
363
401
|
},
|
|
364
402
|
android: async () => {
|
|
365
403
|
if (RNIapAmazonModule) {
|
|
@@ -485,7 +523,7 @@ export const requestPurchase = ({
|
|
|
485
523
|
andDangerouslyFinishTransactionAutomaticallyIOS,
|
|
486
524
|
appAccountToken,
|
|
487
525
|
quantity ?? -1,
|
|
488
|
-
withOffer,
|
|
526
|
+
offerToRecord(withOffer),
|
|
489
527
|
);
|
|
490
528
|
}
|
|
491
529
|
},
|
|
@@ -638,7 +676,7 @@ export const requestSubscription = ({
|
|
|
638
676
|
andDangerouslyFinishTransactionAutomaticallyIOS,
|
|
639
677
|
appAccountToken,
|
|
640
678
|
quantity ?? -1,
|
|
641
|
-
withOffer,
|
|
679
|
+
offerToRecord(withOffer),
|
|
642
680
|
);
|
|
643
681
|
}
|
|
644
682
|
},
|
package/src/internal/platform.ts
CHANGED
|
@@ -57,9 +57,10 @@ export const setIosNativeModule = (
|
|
|
57
57
|
iosNativeModule = nativeModule;
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
-
export const
|
|
60
|
+
export const storekit2Mode = () => {
|
|
61
|
+
iosNativeModule = RNIapIosSk2;
|
|
61
62
|
if (RNIapIosSk2) {
|
|
62
|
-
|
|
63
|
+
RNIapIos.disable();
|
|
63
64
|
return true;
|
|
64
65
|
}
|
|
65
66
|
console.warn('Storekit 2 is not available on this device');
|
|
@@ -67,6 +68,27 @@ export const enableStorekit2 = () => {
|
|
|
67
68
|
return false;
|
|
68
69
|
};
|
|
69
70
|
|
|
71
|
+
export const storekit1Mode = () => {
|
|
72
|
+
iosNativeModule = RNIapIos;
|
|
73
|
+
if (RNIapIosSk2) {
|
|
74
|
+
RNIapIosSk2.disable();
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export const storekitHybridMode = () => {
|
|
81
|
+
if (RNIapIosSk2) {
|
|
82
|
+
iosNativeModule = RNIapIosSk2;
|
|
83
|
+
console.info('Using Storekit 2');
|
|
84
|
+
return true;
|
|
85
|
+
} else {
|
|
86
|
+
iosNativeModule = RNIapIos;
|
|
87
|
+
console.info('Using Storekit 1');
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
70
92
|
const checkNativeIOSAvailable = (): void => {
|
|
71
93
|
if (!RNIapIos && !RNIapIosSk2) {
|
|
72
94
|
throw new Error('IAP_NOT_AVAILABLE');
|
package/src/modules/ios.ts
CHANGED
|
@@ -21,7 +21,7 @@ export type BuyProduct = (
|
|
|
21
21
|
andDangerouslyFinishTransactionAutomaticallyIOS: boolean,
|
|
22
22
|
applicationUsername: string | undefined,
|
|
23
23
|
quantity: number,
|
|
24
|
-
withOffer: PaymentDiscount | undefined,
|
|
24
|
+
withOffer: Record<keyof PaymentDiscount, string> | undefined,
|
|
25
25
|
) => Promise<Purchase>;
|
|
26
26
|
|
|
27
27
|
type clearTransaction = () => Promise<void>;
|
|
@@ -47,6 +47,7 @@ export interface IosModuleProps extends NativeModuleProps {
|
|
|
47
47
|
finishTransaction: finishTransaction;
|
|
48
48
|
getPendingTransactions: getPendingTransactions;
|
|
49
49
|
presentCodeRedemptionSheet: presentCodeRedemptionSheet;
|
|
50
|
+
disable: () => Promise<null>;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
/**
|
|
@@ -84,7 +85,7 @@ export const getPromotedProductIOS = (): Promise<Product | null> => {
|
|
|
84
85
|
if (!isIosStorekit2()) {
|
|
85
86
|
return getIosModule().promotedProduct();
|
|
86
87
|
} else {
|
|
87
|
-
return Promise.reject('Only available on
|
|
88
|
+
return Promise.reject('Only available on Sk1');
|
|
88
89
|
}
|
|
89
90
|
};
|
|
90
91
|
|
|
@@ -146,7 +147,10 @@ export const validateReceiptIos = async ({
|
|
|
146
147
|
? 'https://sandbox.itunes.apple.com/verifyReceipt'
|
|
147
148
|
: 'https://buy.itunes.apple.com/verifyReceipt';
|
|
148
149
|
|
|
149
|
-
return await enhancedFetch<ReceiptValidationResponse>(url
|
|
150
|
+
return await enhancedFetch<ReceiptValidationResponse>(url, {
|
|
151
|
+
method: 'POST',
|
|
152
|
+
body: receiptBody,
|
|
153
|
+
});
|
|
150
154
|
};
|
|
151
155
|
|
|
152
156
|
/**
|
package/src/modules/iosSk2.ts
CHANGED
|
@@ -13,14 +13,16 @@ const {RNIapIosSk2} = NativeModules;
|
|
|
13
13
|
|
|
14
14
|
type getItems = (skus: Sku[]) => Promise<ProductSk2[]>;
|
|
15
15
|
|
|
16
|
-
type getAvailableItems = (
|
|
16
|
+
type getAvailableItems = (
|
|
17
|
+
alsoPublishToEventListener?: boolean,
|
|
18
|
+
) => Promise<Purchase[]>;
|
|
17
19
|
|
|
18
20
|
export type BuyProduct = (
|
|
19
21
|
sku: Sku,
|
|
20
22
|
andDangerouslyFinishTransactionAutomaticallyIOS: boolean,
|
|
21
23
|
applicationUsername: string | undefined,
|
|
22
24
|
quantity: number,
|
|
23
|
-
withOffer: PaymentDiscountSk2 | undefined,
|
|
25
|
+
withOffer: Record<keyof PaymentDiscountSk2, string> | undefined,
|
|
24
26
|
) => Promise<Purchase>;
|
|
25
27
|
|
|
26
28
|
type clearTransaction = () => Promise<void>;
|
|
@@ -51,6 +53,7 @@ export interface IosModulePropsSk2 extends NativeModuleProps {
|
|
|
51
53
|
finishTransaction: finishTransaction;
|
|
52
54
|
getPendingTransactions: getPendingTransactions;
|
|
53
55
|
presentCodeRedemptionSheet: presentCodeRedemptionSheet;
|
|
56
|
+
disable: () => Promise<null>;
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
/**
|