expo-iap 2.8.0 → 2.8.2

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.
@@ -106,10 +106,26 @@ func serializeTransaction(_ transaction: Transaction, jwsRepresentationIOS: Stri
106
106
 
107
107
  if #available(iOS 15.4, *), let jsonData = jsonData {
108
108
  if let price = jsonData["price"] as? NSNumber {
109
+ // START: Deprecated - will be removed in v2.9.0
110
+ // Use currencyCodeIOS, currencySymbolIOS, countryCodeIOS instead
109
111
  purchaseMap["priceIOS"] = price.doubleValue
112
+ // END: Deprecated - will be removed in v2.9.0
110
113
  }
111
114
  if let currency = jsonData["currency"] as? String {
115
+ purchaseMap["currencyCodeIOS"] = currency
116
+
117
+ // Try to get currency symbol from locale
118
+ let locale = Locale(identifier: Locale.identifier(fromComponents: [NSLocale.Key.currencyCode.rawValue: currency]))
119
+ purchaseMap["currencySymbolIOS"] = locale.currencySymbol
120
+
121
+ // START: Deprecated - will be removed in v2.9.0
122
+ // Use currencyCodeIOS instead
112
123
  purchaseMap["currencyIOS"] = currency
124
+ // END: Deprecated - will be removed in v2.9.0
125
+ }
126
+ // Extract country code from storefront if available
127
+ if let storefront = jsonData["storefront"] as? String {
128
+ purchaseMap["countryCodeIOS"] = storefront
113
129
  }
114
130
  }
115
131
 
@@ -162,20 +178,86 @@ func serializeSubscription(_ s: Product.SubscriptionInfo?) -> [String: Any?]? {
162
178
 
163
179
  @available(iOS 15.0, *)
164
180
  func serializeProduct(_ p: Product) -> [String: Any?] {
181
+ // Convert Product.ProductType to our expected 'inapp' or 'subs' string
182
+ let productType: String = p.subscription != nil ? "subs" : "inapp"
183
+
184
+ // For subscription products, add discounts and introductory price
185
+ var discounts: [[String: Any?]]? = nil
186
+ var introductoryPrice: String? = nil
187
+ var introductoryPriceAsAmountIOS: String? = nil
188
+ var introductoryPricePaymentModeIOS: String? = nil
189
+ var introductoryPriceNumberOfPeriodsIOS: String? = nil
190
+ var introductoryPriceSubscriptionPeriodIOS: String? = nil
191
+ var subscriptionPeriodNumberIOS: String? = nil
192
+ var subscriptionPeriodUnitIOS: String? = nil
193
+
194
+ if let subscription = p.subscription {
195
+ // Extract discount information from promotional offers
196
+ if !subscription.promotionalOffers.isEmpty {
197
+ discounts = subscription.promotionalOffers.compactMap { offer in
198
+ return [
199
+ "identifier": offer.id ?? "",
200
+ "type": offer.type.rawValue,
201
+ "numberOfPeriods": "\(offer.periodCount)",
202
+ "price": "\(offer.price)",
203
+ "localizedPrice": offer.displayPrice,
204
+ "paymentMode": offer.paymentMode.rawValue,
205
+ "subscriptionPeriod": getPeriodIOS(offer.period.unit)
206
+ ]
207
+ }
208
+ }
209
+
210
+ // Extract introductory price from introductory offer
211
+ if let introOffer = subscription.introductoryOffer {
212
+ introductoryPrice = introOffer.displayPrice
213
+ introductoryPriceAsAmountIOS = "\(introOffer.price)"
214
+ introductoryPricePaymentModeIOS = introOffer.paymentMode.rawValue
215
+ introductoryPriceNumberOfPeriodsIOS = "\(introOffer.periodCount)"
216
+ introductoryPriceSubscriptionPeriodIOS = getPeriodIOS(introOffer.period.unit)
217
+ }
218
+
219
+ // Extract subscription period information
220
+ subscriptionPeriodNumberIOS = "\(subscription.subscriptionPeriod.value)"
221
+ subscriptionPeriodUnitIOS = getPeriodIOS(subscription.subscriptionPeriod.unit)
222
+ }
223
+
165
224
  return [
166
225
  "debugDescription": serializeDebug(p.debugDescription),
167
226
  "description": p.description,
168
- "displayName": p.displayName,
227
+ // New iOS-suffixed fields
228
+ "displayNameIOS": p.displayName,
229
+ "discountsIOS": discounts,
230
+ "introductoryPriceIOS": introductoryPrice,
231
+ "introductoryPriceAsAmountIOS": introductoryPriceAsAmountIOS,
232
+ "introductoryPricePaymentModeIOS": introductoryPricePaymentModeIOS,
233
+ "introductoryPriceNumberOfPeriodsIOS": introductoryPriceNumberOfPeriodsIOS,
234
+ "introductoryPriceSubscriptionPeriodIOS": introductoryPriceSubscriptionPeriodIOS,
235
+ "subscriptionPeriodNumberIOS": subscriptionPeriodNumberIOS,
236
+ "subscriptionPeriodUnitIOS": subscriptionPeriodUnitIOS,
169
237
  "displayPrice": p.displayPrice,
170
238
  "id": p.id,
171
239
  "title": p.displayName,
172
- "isFamilyShareable": p.isFamilyShareable,
173
- "jsonRepresentation": String(data: p.jsonRepresentation, encoding: .utf8),
240
+ "isFamilyShareableIOS": p.isFamilyShareable,
241
+ "jsonRepresentationIOS": String(data: p.jsonRepresentation, encoding: .utf8),
174
242
  "price": p.price,
175
- "subscription": serializeSubscription(p.subscription),
176
- "type": p.type,
243
+ "subscriptionInfoIOS": serializeSubscription(p.subscription),
244
+ "type": productType,
177
245
  "currency": p.priceFormatStyle.currencyCode,
178
246
  "platform": "ios",
247
+ // START: Deprecated - will be removed in v2.9.0
248
+ // Use displayNameIOS instead of displayName
249
+ "displayName": p.displayName,
250
+ // Use discountsIOS instead of discounts
251
+ "discounts": discounts,
252
+ // Use introductoryPriceIOS instead of introductoryPrice
253
+ "introductoryPrice": introductoryPrice,
254
+ // Use isFamilyShareableIOS instead of isFamilyShareable
255
+ "isFamilyShareable": p.isFamilyShareable,
256
+ // Use jsonRepresentationIOS instead of jsonRepresentation
257
+ "jsonRepresentation": String(data: p.jsonRepresentation, encoding: .utf8),
258
+ // Use subscriptionInfoIOS instead of subscription
259
+ "subscription": serializeSubscription(p.subscription),
260
+ // END: Deprecated - will be removed in v2.9.0
179
261
  ]
180
262
  }
181
263
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-iap",
3
- "version": "2.8.0",
3
+ "version": "2.8.2",
4
4
  "description": "In App Purchase module in Expo",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  ProductAndroid,
3
- ProductPurchaseAndroid,
4
- SubscriptionProductAndroid,
3
+ PurchaseAndroid,
4
+ ProductSubscriptionAndroid,
5
5
  } from './types/ExpoIapAndroid.types';
6
6
  import {
7
7
  ProductIOS,
8
- ProductPurchaseIOS,
9
- SubscriptionProductIOS,
8
+ PurchaseIOS,
9
+ ProductSubscriptionIOS,
10
10
  } from './types/ExpoIapIOS.types';
11
11
  import {NATIVE_ERROR_CODES} from './ExpoIapModule';
12
12
 
@@ -16,7 +16,11 @@ export type ChangeEventPayload = {
16
16
 
17
17
  export type ProductType = 'inapp' | 'subs';
18
18
 
19
- export type ProductBase = {
19
+ // =============================================================================
20
+ // COMMON TYPES (Base types shared across all platforms)
21
+ // =============================================================================
22
+
23
+ export type ProductCommon = {
20
24
  id: string;
21
25
  title: string;
22
26
  description: string;
@@ -25,15 +29,23 @@ export type ProductBase = {
25
29
  displayPrice: string;
26
30
  currency: string;
27
31
  price?: number;
32
+ debugDescription?: string;
33
+ platform?: string;
28
34
  };
29
35
 
30
- export type PurchaseBase = {
36
+ export type PurchaseCommon = {
31
37
  id: string; // Transaction identifier - used by finishTransaction
32
38
  productId: string; // Product identifier - which product was purchased
39
+ ids?: string[]; // Product identifiers for purchases that include multiple products
33
40
  transactionId?: string; // @deprecated - use id instead
34
41
  transactionDate: number;
35
42
  transactionReceipt: string;
36
43
  purchaseToken?: string; // Unified purchase token (jwsRepresentation for iOS, purchaseToken for Android)
44
+ platform?: string;
45
+ };
46
+
47
+ export type ProductSubscriptionCommon = ProductCommon & {
48
+ type: 'subs';
37
49
  };
38
50
 
39
51
  // Define literal platform types for better type discrimination
@@ -46,35 +58,34 @@ export type Product =
46
58
  | (ProductIOS & IosPlatform);
47
59
 
48
60
  export type SubscriptionProduct =
49
- | (SubscriptionProductAndroid & AndroidPlatform)
50
- | (SubscriptionProductIOS & IosPlatform);
61
+ | (ProductSubscriptionAndroid & AndroidPlatform)
62
+ | (ProductSubscriptionIOS & IosPlatform);
51
63
 
52
- // ============================================================================
53
- // Legacy Types (For backward compatibility with useIAP hook)
54
- // ============================================================================
64
+ // Re-export platform-specific types
65
+ export type {
66
+ PurchaseAndroid,
67
+ ProductSubscriptionAndroid,
68
+ } from './types/ExpoIapAndroid.types';
69
+ export type {
70
+ PurchaseIOS,
71
+ ProductSubscriptionIOS,
72
+ } from './types/ExpoIapIOS.types';
55
73
 
56
- // Re-export platform-specific purchase types for legacy compatibility
57
- export type {ProductPurchaseAndroid} from './types/ExpoIapAndroid.types';
58
- export type {ProductPurchaseIOS} from './types/ExpoIapIOS.types';
74
+ // Unified purchase type for both products and subscriptions
75
+ export type Purchase =
76
+ | (PurchaseAndroid & AndroidPlatform)
77
+ | (PurchaseIOS & IosPlatform);
59
78
 
79
+ // Legacy type aliases - deprecated, use Purchase instead
60
80
  /**
61
- * @deprecated Use ProductPurchaseIOS instead. This alias will be removed in v3.0.0.
81
+ * @deprecated Use `Purchase` instead. This type alias will be removed in v2.9.0.
62
82
  */
63
- export type ProductPurchaseIos = ProductPurchaseIOS;
64
-
65
- // Union type for platform-specific purchase types (legacy support)
66
- export type ProductPurchase =
67
- | (ProductPurchaseAndroid & AndroidPlatform)
68
- | (ProductPurchaseIOS & IosPlatform);
69
-
70
- // Union type for platform-specific subscription purchase types (legacy support)
71
- export type SubscriptionPurchase =
72
- | (ProductPurchaseAndroid & AndroidPlatform & {autoRenewingAndroid: boolean})
73
- | (ProductPurchaseIOS & IosPlatform);
74
-
75
- export type Purchase = ProductPurchase | SubscriptionPurchase;
83
+ export type ProductPurchase = Purchase;
84
+ /**
85
+ * @deprecated Use `Purchase` instead. This type alias will be removed in v2.9.0.
86
+ */
87
+ export type SubscriptionPurchase = Purchase;
76
88
 
77
- // Legacy result type
78
89
  export type PurchaseResult = {
79
90
  responseCode?: number;
80
91
  debugMessage?: string;
@@ -310,7 +321,7 @@ export interface UnifiedRequestPurchaseProps {
310
321
  readonly skus?: string[]; // Multiple SKUs (Android native, iOS uses first item)
311
322
 
312
323
  // iOS-specific properties (ignored on Android)
313
- readonly andDangerouslyFinishTransactionAutomaticallyIOS?: boolean;
324
+ readonly andDangerouslyFinishTransactionAutomatically?: boolean;
314
325
  readonly appAccountToken?: string;
315
326
  readonly quantity?: number;
316
327
  readonly withOffer?: import('./types/ExpoIapIOS.types').PaymentDiscount;
@@ -328,9 +339,9 @@ export interface UnifiedRequestPurchaseProps {
328
339
  /**
329
340
  * iOS-specific purchase request parameters
330
341
  */
331
- export interface RequestPurchaseIOSProps {
342
+ export interface RequestPurchaseIosProps {
332
343
  readonly sku: string;
333
- readonly andDangerouslyFinishTransactionAutomaticallyIOS?: boolean;
344
+ readonly andDangerouslyFinishTransactionAutomatically?: boolean;
334
345
  readonly appAccountToken?: string;
335
346
  readonly quantity?: number;
336
347
  readonly withOffer?: import('./types/ExpoIapIOS.types').PaymentDiscount;
@@ -364,7 +375,7 @@ export interface RequestSubscriptionAndroidProps
364
375
  * Allows clear separation of iOS and Android parameters
365
376
  */
366
377
  export interface RequestPurchasePropsByPlatforms {
367
- readonly ios?: RequestPurchaseIOSProps;
378
+ readonly ios?: RequestPurchaseIosProps;
368
379
  readonly android?: RequestPurchaseAndroidProps;
369
380
  }
370
381
 
@@ -372,7 +383,7 @@ export interface RequestPurchasePropsByPlatforms {
372
383
  * Modern platform-specific subscription request structure (v2.7.0+)
373
384
  */
374
385
  export interface RequestSubscriptionPropsByPlatforms {
375
- readonly ios?: RequestPurchaseIOSProps;
386
+ readonly ios?: RequestPurchaseIosProps;
376
387
  readonly android?: RequestSubscriptionAndroidProps;
377
388
  }
378
389
 
@@ -387,14 +398,3 @@ export type RequestPurchaseProps = RequestPurchasePropsByPlatforms;
387
398
  * This is the recommended API moving forward
388
399
  */
389
400
  export type RequestSubscriptionProps = RequestSubscriptionPropsByPlatforms;
390
-
391
- // ============================================================================
392
- // Deprecated Aliases for Backward Compatibility
393
- // ============================================================================
394
-
395
- /**
396
- * @deprecated Use RequestPurchaseIOSProps instead. This alias will be removed in v3.0.0.
397
- */
398
- export type RequestPurchaseIosProps = RequestPurchaseIOSProps;
399
-
400
- // Note: Type guard functions are exported from index.ts to avoid conflicts
package/src/index.ts CHANGED
@@ -18,16 +18,14 @@ import {
18
18
  // Types
19
19
  import {
20
20
  Product,
21
- ProductPurchase,
22
21
  Purchase,
23
22
  PurchaseError,
24
23
  PurchaseResult,
25
24
  RequestSubscriptionProps,
26
25
  RequestPurchaseProps,
27
26
  SubscriptionProduct,
28
- SubscriptionPurchase,
29
27
  } from './ExpoIap.types';
30
- import {ProductPurchaseAndroid} from './types/ExpoIapAndroid.types';
28
+ import {PurchaseAndroid} from './types/ExpoIapAndroid.types';
31
29
  import {PaymentDiscount} from './types/ExpoIapIOS.types';
32
30
 
33
31
  // Export all types
@@ -281,7 +279,7 @@ export const getPurchaseHistory = ({
281
279
  }: {
282
280
  alsoPublishToEventListener?: boolean;
283
281
  onlyIncludeActiveItems?: boolean;
284
- } = {}): Promise<ProductPurchase[]> => {
282
+ } = {}): Promise<Purchase[]> => {
285
283
  console.warn(
286
284
  '`getPurchaseHistory` is deprecated. Use `getPurchaseHistories` instead. This function will be removed in version 3.0.0.',
287
285
  );
@@ -297,7 +295,7 @@ export const getPurchaseHistories = ({
297
295
  }: {
298
296
  alsoPublishToEventListener?: boolean;
299
297
  onlyIncludeActiveItems?: boolean;
300
- } = {}): Promise<ProductPurchase[]> =>
298
+ } = {}): Promise<Purchase[]> =>
301
299
  (
302
300
  Platform.select({
303
301
  ios: async () => {
@@ -323,7 +321,7 @@ export const getAvailablePurchases = ({
323
321
  }: {
324
322
  alsoPublishToEventListener?: boolean;
325
323
  onlyIncludeActiveItems?: boolean;
326
- } = {}): Promise<ProductPurchase[]> =>
324
+ } = {}): Promise<Purchase[]> =>
327
325
  (
328
326
  Platform.select({
329
327
  ios: () =>
@@ -409,13 +407,7 @@ const normalizeRequestProps = (
409
407
  */
410
408
  export const requestPurchase = (
411
409
  requestObj: PurchaseRequest,
412
- ): Promise<
413
- | ProductPurchase
414
- | SubscriptionPurchase
415
- | ProductPurchase[]
416
- | SubscriptionPurchase[]
417
- | void
418
- > => {
410
+ ): Promise<Purchase | Purchase[] | void> => {
419
411
  const {request, type = 'inapp'} = requestObj;
420
412
 
421
413
  if (Platform.OS === 'ios') {
@@ -429,7 +421,7 @@ export const requestPurchase = (
429
421
 
430
422
  const {
431
423
  sku,
432
- andDangerouslyFinishTransactionAutomaticallyIOS = false,
424
+ andDangerouslyFinishTransactionAutomatically = false,
433
425
  appAccountToken,
434
426
  quantity,
435
427
  withOffer,
@@ -439,15 +431,13 @@ export const requestPurchase = (
439
431
  const offer = offerToRecordIOS(withOffer);
440
432
  const purchase = await ExpoIapModule.buyProduct(
441
433
  sku,
442
- andDangerouslyFinishTransactionAutomaticallyIOS,
434
+ andDangerouslyFinishTransactionAutomatically,
443
435
  appAccountToken,
444
436
  quantity ?? -1,
445
437
  offer,
446
438
  );
447
439
 
448
- return type === 'inapp'
449
- ? (purchase as ProductPurchase)
450
- : (purchase as SubscriptionPurchase);
440
+ return type === 'inapp' ? (purchase as Purchase) : (purchase as Purchase);
451
441
  })();
452
442
  }
453
443
 
@@ -478,7 +468,7 @@ export const requestPurchase = (
478
468
  obfuscatedProfileId: obfuscatedProfileIdAndroid,
479
469
  offerTokenArr: [],
480
470
  isOfferPersonalized: isOfferPersonalized ?? false,
481
- }) as Promise<ProductPurchase[]>;
471
+ }) as Promise<Purchase[]>;
482
472
  })();
483
473
  }
484
474
 
@@ -504,7 +494,7 @@ export const requestPurchase = (
504
494
  obfuscatedProfileId: obfuscatedProfileIdAndroid,
505
495
  offerTokenArr: subscriptionOffers.map((so: any) => so.offerToken),
506
496
  isOfferPersonalized: isOfferPersonalized ?? false,
507
- }) as Promise<SubscriptionPurchase[]>;
497
+ }) as Promise<Purchase[]>;
508
498
  })();
509
499
  }
510
500
 
@@ -543,13 +533,13 @@ export const requestPurchase = (
543
533
  */
544
534
  export const requestSubscription = async (
545
535
  request: RequestSubscriptionProps,
546
- ): Promise<SubscriptionPurchase | SubscriptionPurchase[] | null | void> => {
536
+ ): Promise<Purchase | Purchase[] | null | void> => {
547
537
  console.warn(
548
538
  "`requestSubscription` is deprecated and will be removed in version 3.0.0. Use `requestPurchase({ request, type: 'subs' })` instead.",
549
539
  );
550
540
  return (await requestPurchase({request, type: 'subs'})) as
551
- | SubscriptionPurchase
552
- | SubscriptionPurchase[]
541
+ | Purchase
542
+ | Purchase[]
553
543
  | null
554
544
  | void;
555
545
  };
@@ -574,7 +564,7 @@ export const finishTransaction = ({
574
564
  return Promise.resolve(true);
575
565
  },
576
566
  android: async () => {
577
- const androidPurchase = purchase as ProductPurchaseAndroid;
567
+ const androidPurchase = purchase as PurchaseAndroid;
578
568
 
579
569
  if (isConsumable) {
580
570
  return ExpoIapModule.consumeProduct(androidPurchase.purchaseToken);
@@ -5,12 +5,7 @@ import {purchaseUpdatedListener} from '..';
5
5
  import ExpoIapModule from '../ExpoIapModule';
6
6
 
7
7
  // Types
8
- import {
9
- ProductPurchase,
10
- PurchaseError,
11
- Purchase,
12
- SubscriptionPurchase,
13
- } from '../ExpoIap.types';
8
+ import {Purchase, PurchaseError} from '../ExpoIap.types';
14
9
  import type {
15
10
  ProductStatusIOS,
16
11
  AppTransactionIOS,
@@ -18,7 +13,7 @@ import type {
18
13
  import {Linking} from 'react-native';
19
14
 
20
15
  export type TransactionEvent = {
21
- transaction?: ProductPurchase;
16
+ transaction?: Purchase;
22
17
  error?: PurchaseError;
23
18
  };
24
19
 
@@ -39,7 +34,7 @@ export type TransactionEvent = {
39
34
  export const transactionUpdatedIOS = (
40
35
  listener: (event: TransactionEvent) => void,
41
36
  ) => {
42
- const isProductPurchase = (item: unknown): item is ProductPurchase => {
37
+ const isPurchase = (item: unknown): item is Purchase => {
43
38
  return (
44
39
  item != null &&
45
40
  typeof item === 'object' &&
@@ -51,18 +46,18 @@ export const transactionUpdatedIOS = (
51
46
 
52
47
  // Helper function to safely convert Purchase to TransactionEvent
53
48
  const mapPurchaseToTransactionEvent = (
54
- purchase: Purchase | SubscriptionPurchase,
49
+ purchase: Purchase,
55
50
  ): TransactionEvent => {
56
51
  // Validate the purchase object before casting
57
- if (isProductPurchase(purchase)) {
52
+ if (isPurchase(purchase)) {
58
53
  return {
59
- transaction: purchase as ProductPurchase,
54
+ transaction: purchase as Purchase,
60
55
  };
61
56
  }
62
57
 
63
58
  // Fallback: create a basic TransactionEvent structure
64
59
  return {
65
- transaction: purchase as ProductPurchase,
60
+ transaction: purchase as Purchase,
66
61
  };
67
62
  };
68
63
 
@@ -138,9 +133,7 @@ export const subscriptionStatusIOS = (
138
133
  *
139
134
  * @platform iOS
140
135
  */
141
- export const currentEntitlementIOS = (
142
- sku: string,
143
- ): Promise<ProductPurchase> => {
136
+ export const currentEntitlementIOS = (sku: string): Promise<Purchase> => {
144
137
  return ExpoIapModule.currentEntitlement(sku);
145
138
  };
146
139
 
@@ -153,7 +146,7 @@ export const currentEntitlementIOS = (
153
146
  *
154
147
  * @platform iOS
155
148
  */
156
- export const latestTransactionIOS = (sku: string): Promise<ProductPurchase> => {
149
+ export const latestTransactionIOS = (sku: string): Promise<Purchase> => {
157
150
  return ExpoIapModule.latestTransaction(sku);
158
151
  };
159
152
 
@@ -241,7 +234,7 @@ export const getTransactionJwsIOS = (sku: string): Promise<string> => {
241
234
  * isValid: boolean;
242
235
  * receiptData: string;
243
236
  * jwsRepresentation: string;
244
- * latestTransaction?: ProductPurchase;
237
+ * latestTransaction?: Purchase;
245
238
  * }>}
246
239
  */
247
240
  export const validateReceiptIOS = async (
@@ -250,7 +243,7 @@ export const validateReceiptIOS = async (
250
243
  isValid: boolean;
251
244
  receiptData: string;
252
245
  jwsRepresentation: string;
253
- latestTransaction?: ProductPurchase;
246
+ latestTransaction?: Purchase;
254
247
  }> => {
255
248
  const result = await ExpoIapModule.validateReceiptIOS(sku);
256
249
  return result;
@@ -362,7 +355,7 @@ export const subscriptionStatus = (
362
355
  /**
363
356
  * @deprecated Use `currentEntitlementIOS` instead. This function will be removed in version 3.0.0.
364
357
  */
365
- export const currentEntitlement = (sku: string): Promise<ProductPurchase> => {
358
+ export const currentEntitlement = (sku: string): Promise<Purchase> => {
366
359
  console.warn(
367
360
  '`currentEntitlement` is deprecated. Use `currentEntitlementIOS` instead. This function will be removed in version 3.0.0.',
368
361
  );
@@ -372,7 +365,7 @@ export const currentEntitlement = (sku: string): Promise<ProductPurchase> => {
372
365
  /**
373
366
  * @deprecated Use `latestTransactionIOS` instead. This function will be removed in version 3.0.0.
374
367
  */
375
- export const latestTransaction = (sku: string): Promise<ProductPurchase> => {
368
+ export const latestTransaction = (sku: string): Promise<Purchase> => {
376
369
  console.warn(
377
370
  '`latestTransaction` is deprecated. Use `latestTransactionIOS` instead. This function will be removed in version 3.0.0.',
378
371
  );
@@ -1,6 +1,6 @@
1
- import {PurchaseBase, ProductBase} from '../ExpoIap.types';
1
+ import {PurchaseCommon, ProductCommon} from '../ExpoIap.types';
2
2
 
3
- type OneTimePurchaseOfferDetails = {
3
+ type ProductAndroidOneTimePurchaseOfferDetail = {
4
4
  priceCurrencyCode: string;
5
5
  formattedPrice: string;
6
6
  priceAmountMicros: string;
@@ -20,21 +20,34 @@ type PricingPhasesAndroid = {
20
20
  pricingPhaseList: PricingPhaseAndroid[];
21
21
  };
22
22
 
23
- type SubscriptionOfferDetail = {
23
+ type ProductSubscriptionAndroidOfferDetail = {
24
24
  basePlanId: string;
25
- offerId: string;
25
+ offerId: string | null;
26
26
  offerToken: string;
27
27
  offerTags: string[];
28
28
  pricingPhases: PricingPhasesAndroid;
29
29
  };
30
30
 
31
- export type ProductAndroid = ProductBase & {
32
- name: string;
33
- oneTimePurchaseOfferDetails?: OneTimePurchaseOfferDetails;
34
- subscriptionOfferDetails?: SubscriptionOfferDetail[];
31
+ export type ProductAndroid = ProductCommon & {
32
+ nameAndroid: string;
33
+ oneTimePurchaseOfferDetailsAndroid?: ProductAndroidOneTimePurchaseOfferDetail;
34
+ platform: 'android';
35
+ subscriptionOfferDetailsAndroid?: ProductSubscriptionAndroidOfferDetail[];
36
+ /**
37
+ * @deprecated Use `nameAndroid` instead. This field will be removed in v2.9.0.
38
+ */
39
+ name?: string;
40
+ /**
41
+ * @deprecated Use `oneTimePurchaseOfferDetailsAndroid` instead. This field will be removed in v2.9.0.
42
+ */
43
+ oneTimePurchaseOfferDetails?: ProductAndroidOneTimePurchaseOfferDetail;
44
+ /**
45
+ * @deprecated Use `subscriptionOfferDetailsAndroid` instead. This field will be removed in v2.9.0.
46
+ */
47
+ subscriptionOfferDetails?: ProductSubscriptionAndroidOfferDetail[];
35
48
  };
36
49
 
37
- type SubscriptionOfferAndroid = {
50
+ type ProductSubscriptionAndroidOfferDetails = {
38
51
  basePlanId: string;
39
52
  offerId: string | null;
40
53
  offerToken: string;
@@ -42,10 +55,17 @@ type SubscriptionOfferAndroid = {
42
55
  offerTags: string[];
43
56
  };
44
57
 
45
- export type SubscriptionProductAndroid = ProductAndroid & {
46
- subscriptionOfferDetails: SubscriptionOfferAndroid[];
58
+ export type ProductSubscriptionAndroid = ProductAndroid & {
59
+ subscriptionOfferDetailsAndroid: ProductSubscriptionAndroidOfferDetails[];
60
+ /**
61
+ * @deprecated Use `subscriptionOfferDetailsAndroid` instead. This field will be removed in v2.9.0.
62
+ */
63
+ subscriptionOfferDetails?: ProductSubscriptionAndroidOfferDetails[];
47
64
  };
48
65
 
66
+ // Legacy naming for backward compatibility
67
+ export type SubscriptionProductAndroid = ProductSubscriptionAndroid;
68
+
49
69
  export type RequestPurchaseAndroidProps = {
50
70
  skus: string[];
51
71
  obfuscatedAccountIdAndroid?: string;
@@ -110,14 +130,21 @@ export enum FeatureTypeAndroid {
110
130
  SUBSCRIPTIONS_UPDATE = 'SUBSCRIPTIONS_UPDATE',
111
131
  }
112
132
 
113
- export enum PurchaseStateAndroid {
133
+ export enum PurchaseAndroidState {
114
134
  UNSPECIFIED_STATE = 0,
115
135
  PURCHASED = 1,
116
136
  PENDING = 2,
117
137
  }
118
138
 
119
- export type ProductPurchaseAndroid = PurchaseBase & {
120
- ids?: string[];
139
+ // Legacy naming for backward compatibility
140
+ /**
141
+ * @deprecated Use `PurchaseAndroidState` instead. This enum will be removed in v2.9.0.
142
+ */
143
+ export const PurchaseStateAndroid = PurchaseAndroidState;
144
+
145
+ // Legacy naming for backward compatibility
146
+ export type ProductPurchaseAndroid = PurchaseCommon & {
147
+ platform: 'android';
121
148
  /**
122
149
  * @deprecated Use `purchaseToken` instead. This field will be removed in a future version.
123
150
  */
@@ -125,10 +152,30 @@ export type ProductPurchaseAndroid = PurchaseBase & {
125
152
  dataAndroid?: string;
126
153
  signatureAndroid?: string;
127
154
  autoRenewingAndroid?: boolean;
128
- purchaseStateAndroid?: PurchaseStateAndroid;
155
+ purchaseStateAndroid?: PurchaseAndroidState;
129
156
  isAcknowledgedAndroid?: boolean;
130
157
  packageNameAndroid?: string;
131
158
  developerPayloadAndroid?: string;
132
159
  obfuscatedAccountIdAndroid?: string;
133
160
  obfuscatedProfileIdAndroid?: string;
134
161
  };
162
+
163
+ // Preferred naming
164
+ export type PurchaseAndroid = ProductPurchaseAndroid;
165
+
166
+ // Legacy type aliases for backward compatibility
167
+ /**
168
+ * @deprecated Use `ProductAndroidOneTimePurchaseOfferDetail` instead. This type will be removed in v2.9.0.
169
+ */
170
+ export type OneTimePurchaseOfferDetails =
171
+ ProductAndroidOneTimePurchaseOfferDetail;
172
+
173
+ /**
174
+ * @deprecated Use `ProductSubscriptionAndroidOfferDetail` instead. This type will be removed in v2.9.0.
175
+ */
176
+ export type SubscriptionOfferDetail = ProductSubscriptionAndroidOfferDetail;
177
+
178
+ /**
179
+ * @deprecated Use `ProductSubscriptionAndroidOfferDetails` instead. This type will be removed in v2.9.0.
180
+ */
181
+ export type SubscriptionOfferAndroid = ProductSubscriptionAndroidOfferDetails;