expo-iap 3.1.2 → 3.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,9 +9,6 @@ import UIKit
9
9
  @MainActor
10
10
  public final class ExpoIapModule: Module {
11
11
  private var isInitialized = false
12
- private var purchaseUpdatedSub: Subscription?
13
- private var purchaseErrorSub: Subscription?
14
- private var promotedProductSub: Subscription?
15
12
 
16
13
  nonisolated public func definition() -> ModuleDefinition {
17
14
  Name("ExpoIap")
@@ -21,20 +18,20 @@ public final class ExpoIapModule: Module {
21
18
  }
22
19
 
23
20
  Events(
24
- IapEvent.purchaseUpdated.rawValue,
25
- IapEvent.purchaseError.rawValue,
26
- IapEvent.promotedProductIos.rawValue
21
+ OpenIapEvent.purchaseUpdated.rawValue,
22
+ OpenIapEvent.purchaseError.rawValue,
23
+ OpenIapEvent.promotedProductIos.rawValue
27
24
  )
28
25
 
29
26
  OnCreate {
30
27
  Task { @MainActor in
31
- self.setupStore()
28
+ ExpoIapHelper.setupStore(module: self)
32
29
  }
33
30
  }
34
31
 
35
32
  OnDestroy {
36
33
  Task { @MainActor in
37
- await self.cleanupStore()
34
+ await ExpoIapHelper.cleanupStore()
38
35
  }
39
36
  }
40
37
 
@@ -52,7 +49,7 @@ public final class ExpoIapModule: Module {
52
49
 
53
50
  AsyncFunction("fetchProducts") { (params: [String: Any]) async throws -> [[String: Any]] in
54
51
  ExpoIapLog.payload("fetchProducts", payload: params)
55
- try await ensureConnection()
52
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
56
53
  let request = try ExpoIapHelper.decodeProductRequest(from: params)
57
54
  let result = try await OpenIapModule.shared.fetchProducts(request)
58
55
  let products = ExpoIapHelper.sanitizeArray(OpenIapSerialization.products(result))
@@ -62,7 +59,7 @@ public final class ExpoIapModule: Module {
62
59
 
63
60
  AsyncFunction("requestPurchase") { (payload: [String: Any]) async throws -> Any? in
64
61
  ExpoIapLog.payload("requestPurchase", payload: payload)
65
- try await ensureConnection()
62
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
66
63
  let props = try ExpoIapHelper.decodeRequestPurchaseProps(from: payload)
67
64
 
68
65
  do {
@@ -101,7 +98,7 @@ public final class ExpoIapModule: Module {
101
98
  "isConsumable": isConsumable as Any,
102
99
  ]
103
100
  )
104
- try await ensureConnection()
101
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
105
102
  let purchaseInput = try OpenIapSerialization.purchaseInput(from: purchasePayload)
106
103
  try await OpenIapModule.shared.finishTransaction(
107
104
  purchase: purchaseInput,
@@ -114,7 +111,7 @@ public final class ExpoIapModule: Module {
114
111
  AsyncFunction("getAvailablePurchases") {
115
112
  (options: [String: Any]?) async throws -> [[String: Any]] in
116
113
  ExpoIapLog.payload("getAvailablePurchases", payload: options ?? [:])
117
- try await ensureConnection()
114
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
118
115
  let purchaseOptions = try options.map { try OpenIapSerialization.purchaseOptions(from: $0) }
119
116
  let purchases = try await OpenIapModule.shared.getAvailablePurchases(purchaseOptions)
120
117
  let sanitized = ExpoIapHelper.sanitizeArray(OpenIapSerialization.purchases(purchases))
@@ -131,7 +128,7 @@ public final class ExpoIapModule: Module {
131
128
  "onlyIncludeActiveItemsIOS": onlyIncludeActive,
132
129
  ]
133
130
  )
134
- try await ensureConnection()
131
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
135
132
  let optionsDictionary: [String: Any] = [
136
133
  "alsoPublishToEventListenerIOS": alsoPublish,
137
134
  "onlyIncludeActiveItemsIOS": onlyIncludeActive
@@ -145,7 +142,7 @@ public final class ExpoIapModule: Module {
145
142
 
146
143
  AsyncFunction("getPendingTransactionsIOS") { () async throws -> [[String: Any]] in
147
144
  ExpoIapLog.payload("getPendingTransactionsIOS", payload: nil)
148
- try await ensureConnection()
145
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
149
146
  let pending = try await OpenIapModule.shared.getPendingTransactionsIOS()
150
147
  let sanitized = pending.map { ExpoIapHelper.sanitizeDictionary(OpenIapSerialization.encode($0)) }
151
148
  ExpoIapLog.result("getPendingTransactionsIOS", value: sanitized)
@@ -154,7 +151,7 @@ public final class ExpoIapModule: Module {
154
151
 
155
152
  AsyncFunction("clearTransactionIOS") { () async throws -> Bool in
156
153
  ExpoIapLog.payload("clearTransactionIOS", payload: nil)
157
- try await ensureConnection()
154
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
158
155
  let success = try await OpenIapModule.shared.clearTransactionIOS()
159
156
  ExpoIapLog.result("clearTransactionIOS", value: success)
160
157
  return success
@@ -162,7 +159,7 @@ public final class ExpoIapModule: Module {
162
159
 
163
160
  AsyncFunction("getReceiptIOS") { () async throws -> String in
164
161
  ExpoIapLog.payload("getReceiptIOS", payload: nil)
165
- try await ensureConnection()
162
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
166
163
  let receipt = try await OpenIapModule.shared.getReceiptDataIOS() ?? ""
167
164
  ExpoIapLog.result("getReceiptIOS", value: receipt)
168
165
  return receipt
@@ -170,7 +167,7 @@ public final class ExpoIapModule: Module {
170
167
 
171
168
  AsyncFunction("getReceiptDataIOS") { () async throws -> String in
172
169
  ExpoIapLog.payload("getReceiptDataIOS", payload: nil)
173
- try await ensureConnection()
170
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
174
171
  let receipt = try await OpenIapModule.shared.getReceiptDataIOS() ?? ""
175
172
  ExpoIapLog.result("getReceiptDataIOS", value: receipt)
176
173
  return receipt
@@ -178,7 +175,7 @@ public final class ExpoIapModule: Module {
178
175
 
179
176
  AsyncFunction("requestReceiptRefreshIOS") { () async throws -> String in
180
177
  ExpoIapLog.payload("requestReceiptRefreshIOS", payload: nil)
181
- try await ensureConnection()
178
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
182
179
  let receipt = try await OpenIapModule.shared.getReceiptDataIOS() ?? ""
183
180
  ExpoIapLog.result("requestReceiptRefreshIOS", value: receipt)
184
181
  return receipt
@@ -186,7 +183,7 @@ public final class ExpoIapModule: Module {
186
183
 
187
184
  AsyncFunction("validateReceiptIOS") { (sku: String) async throws -> [String: Any] in
188
185
  ExpoIapLog.payload("validateReceiptIOS", payload: ["sku": sku])
189
- try await ensureConnection()
186
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
190
187
  do {
191
188
  let props = try OpenIapSerialization.receiptValidationProps(from: ["sku": sku])
192
189
  let result = try await OpenIapModule.shared.validateReceiptIOS(props)
@@ -206,7 +203,7 @@ public final class ExpoIapModule: Module {
206
203
 
207
204
  AsyncFunction("presentCodeRedemptionSheetIOS") { () async throws -> Bool in
208
205
  ExpoIapLog.payload("presentCodeRedemptionSheetIOS", payload: nil)
209
- try await ensureConnection()
206
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
210
207
  let success = try await OpenIapModule.shared.presentCodeRedemptionSheetIOS()
211
208
  ExpoIapLog.result("presentCodeRedemptionSheetIOS", value: success)
212
209
  return success
@@ -214,7 +211,7 @@ public final class ExpoIapModule: Module {
214
211
 
215
212
  AsyncFunction("showManageSubscriptionsIOS") { () async throws -> [[String: Any]] in
216
213
  ExpoIapLog.payload("showManageSubscriptionsIOS", payload: nil)
217
- try await ensureConnection()
214
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
218
215
  let purchases = try await OpenIapModule.shared.showManageSubscriptionsIOS()
219
216
  let sanitized = purchases.map { ExpoIapHelper.sanitizeDictionary(OpenIapSerialization.encode($0)) }
220
217
  ExpoIapLog.result("showManageSubscriptionsIOS", value: sanitized)
@@ -223,7 +220,7 @@ public final class ExpoIapModule: Module {
223
220
 
224
221
  AsyncFunction("deepLinkToSubscriptionsIOS") { () async throws -> Bool in
225
222
  ExpoIapLog.payload("deepLinkToSubscriptionsIOS", payload: nil)
226
- try await ensureConnection()
223
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
227
224
  try await OpenIapModule.shared.deepLinkToSubscriptions(nil)
228
225
  ExpoIapLog.result("deepLinkToSubscriptionsIOS", value: true)
229
226
  return true
@@ -231,7 +228,7 @@ public final class ExpoIapModule: Module {
231
228
 
232
229
  AsyncFunction("beginRefundRequestIOS") { (sku: String) async throws -> String? in
233
230
  ExpoIapLog.payload("beginRefundRequestIOS", payload: ["sku": sku])
234
- try await ensureConnection()
231
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
235
232
  let result = try await OpenIapModule.shared.beginRefundRequestIOS(sku: sku)
236
233
  ExpoIapLog.result("beginRefundRequestIOS", value: result)
237
234
  return result
@@ -239,7 +236,7 @@ public final class ExpoIapModule: Module {
239
236
 
240
237
  AsyncFunction("getPromotedProductIOS") { () async throws -> [String: Any]? in
241
238
  ExpoIapLog.payload("getPromotedProductIOS", payload: nil)
242
- try await ensureConnection()
239
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
243
240
  if let product = try await OpenIapModule.shared.getPromotedProductIOS() {
244
241
  let sanitized = ExpoIapHelper.sanitizeDictionary(OpenIapSerialization.encode(product))
245
242
  ExpoIapLog.result("getPromotedProductIOS", value: sanitized)
@@ -251,7 +248,7 @@ public final class ExpoIapModule: Module {
251
248
 
252
249
  AsyncFunction("getStorefrontIOS") { () async throws -> String in
253
250
  ExpoIapLog.payload("getStorefrontIOS", payload: nil)
254
- try await ensureConnection()
251
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
255
252
  let storefront = try await OpenIapModule.shared.getStorefrontIOS()
256
253
  ExpoIapLog.result("getStorefrontIOS", value: storefront)
257
254
  return storefront
@@ -259,7 +256,7 @@ public final class ExpoIapModule: Module {
259
256
 
260
257
  AsyncFunction("syncIOS") { () async throws -> Bool in
261
258
  ExpoIapLog.payload("syncIOS", payload: nil)
262
- try await ensureConnection()
259
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
263
260
  let success = try await OpenIapModule.shared.syncIOS()
264
261
  ExpoIapLog.result("syncIOS", value: success)
265
262
  return success
@@ -267,7 +264,7 @@ public final class ExpoIapModule: Module {
267
264
 
268
265
  AsyncFunction("isTransactionVerifiedIOS") { (sku: String) async throws -> Bool in
269
266
  ExpoIapLog.payload("isTransactionVerifiedIOS", payload: ["sku": sku])
270
- try await ensureConnection()
267
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
271
268
  let verified = try await OpenIapModule.shared.isTransactionVerifiedIOS(sku: sku)
272
269
  ExpoIapLog.result("isTransactionVerifiedIOS", value: verified)
273
270
  return verified
@@ -275,7 +272,7 @@ public final class ExpoIapModule: Module {
275
272
 
276
273
  AsyncFunction("getTransactionJwsIOS") { (sku: String) async throws -> String? in
277
274
  ExpoIapLog.payload("getTransactionJwsIOS", payload: ["sku": sku])
278
- try await ensureConnection()
275
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
279
276
  let jws = try await OpenIapModule.shared.getTransactionJwsIOS(sku: sku)
280
277
  ExpoIapLog.result("getTransactionJwsIOS", value: jws)
281
278
  return jws
@@ -283,7 +280,7 @@ public final class ExpoIapModule: Module {
283
280
 
284
281
  AsyncFunction("isEligibleForIntroOfferIOS") { (groupID: String) async throws -> Bool in
285
282
  ExpoIapLog.payload("isEligibleForIntroOfferIOS", payload: ["groupID": groupID])
286
- try await ensureConnection()
283
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
287
284
  let eligible = try await OpenIapModule.shared.isEligibleForIntroOfferIOS(groupID: groupID)
288
285
  ExpoIapLog.result("isEligibleForIntroOfferIOS", value: eligible)
289
286
  return eligible
@@ -291,7 +288,7 @@ public final class ExpoIapModule: Module {
291
288
 
292
289
  AsyncFunction("subscriptionStatusIOS") { (sku: String) async throws -> [[String: Any]]? in
293
290
  ExpoIapLog.payload("subscriptionStatusIOS", payload: ["sku": sku])
294
- try await ensureConnection()
291
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
295
292
  let statuses = try await OpenIapModule.shared.subscriptionStatusIOS(sku: sku)
296
293
  let sanitized = statuses.map { ExpoIapHelper.sanitizeDictionary(OpenIapSerialization.encode($0)) }
297
294
  ExpoIapLog.result("subscriptionStatusIOS", value: sanitized)
@@ -300,7 +297,7 @@ public final class ExpoIapModule: Module {
300
297
 
301
298
  AsyncFunction("currentEntitlementIOS") { (sku: String) async throws -> [String: Any]? in
302
299
  ExpoIapLog.payload("currentEntitlementIOS", payload: ["sku": sku])
303
- try await ensureConnection()
300
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
304
301
  do {
305
302
  if let entitlement = try await OpenIapModule.shared.currentEntitlementIOS(sku: sku) {
306
303
  let sanitized = ExpoIapHelper.sanitizeDictionary(OpenIapSerialization.encode(entitlement))
@@ -320,7 +317,7 @@ public final class ExpoIapModule: Module {
320
317
 
321
318
  AsyncFunction("latestTransactionIOS") { (sku: String) async throws -> [String: Any]? in
322
319
  ExpoIapLog.payload("latestTransactionIOS", payload: ["sku": sku])
323
- try await ensureConnection()
320
+ try await ExpoIapHelper.ensureConnection(isInitialized: self.isInitialized)
324
321
  do {
325
322
  if let transaction = try await OpenIapModule.shared.latestTransactionIOS(sku: sku) {
326
323
  let sanitized = ExpoIapHelper.sanitizeDictionary(OpenIapSerialization.encode(transaction))
@@ -338,69 +335,4 @@ public final class ExpoIapModule: Module {
338
335
  }
339
336
  }
340
337
  }
341
-
342
- @MainActor
343
- private func setupStore() {
344
- purchaseUpdatedSub = OpenIapModule.shared.purchaseUpdatedListener { [weak self] purchase in
345
- Task { @MainActor in
346
- guard let self else { return }
347
- let payload = ExpoIapHelper.sanitizeDictionary(OpenIapSerialization.purchase(purchase))
348
- self.sendEvent(IapEvent.purchaseUpdated.rawValue, payload)
349
- }
350
- }
351
-
352
- purchaseErrorSub = OpenIapModule.shared.purchaseErrorListener { [weak self] error in
353
- Task { @MainActor in
354
- guard let self else { return }
355
- let payload = ExpoIapHelper.sanitizeDictionary(OpenIapSerialization.encode(error))
356
- self.sendEvent(IapEvent.purchaseError.rawValue, payload)
357
- }
358
- }
359
-
360
- promotedProductSub = OpenIapModule.shared.promotedProductListenerIOS { [weak self] productId in
361
- Task { @MainActor in
362
- guard let self else { return }
363
- do {
364
- if let product = try await OpenIapModule.shared.getPromotedProductIOS() {
365
- let sanitized = ExpoIapHelper.sanitizeDictionary(OpenIapSerialization.encode(product))
366
- self.sendEvent(IapEvent.promotedProductIos.rawValue, sanitized)
367
- return
368
- }
369
- } catch {
370
- ExpoIapLog.failure("promotedProductListenerIOS", error: error)
371
- }
372
-
373
- self.sendEvent(
374
- IapEvent.promotedProductIos.rawValue,
375
- ["productId": productId]
376
- )
377
- }
378
- }
379
- }
380
-
381
- @MainActor
382
- private func cleanupStore() async {
383
- removeListener(&purchaseUpdatedSub)
384
- removeListener(&purchaseErrorSub)
385
- removeListener(&promotedProductSub)
386
- _ = try? await OpenIapModule.shared.endConnection()
387
- }
388
-
389
- private func removeListener(_ subscription: inout Subscription?) {
390
- if let current = subscription {
391
- OpenIapModule.shared.removeListener(current)
392
- }
393
- subscription = nil
394
- }
395
-
396
- private func ensureConnection() async throws {
397
- try await MainActor.run {
398
- guard self.isInitialized else {
399
- throw PurchaseError.make(
400
- code: .initConnection,
401
- message: "Connection not initialized. Call initConnection() first."
402
- )
403
- }
404
- }
405
- }
406
338
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "apple": "1.2.3",
3
- "google": "1.2.6",
3
+ "google": "1.2.7",
4
4
  "gql": "1.0.8"
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-iap",
3
- "version": "3.1.2",
3
+ "version": "3.1.3",
4
4
  "description": "In App Purchase module in Expo",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
package/src/types.ts CHANGED
@@ -90,40 +90,40 @@ export interface EntitlementIOS {
90
90
  }
91
91
 
92
92
  export enum ErrorCode {
93
- ActivityUnavailable = 'ACTIVITY_UNAVAILABLE',
94
- AlreadyOwned = 'ALREADY_OWNED',
95
- AlreadyPrepared = 'ALREADY_PREPARED',
96
- BillingResponseJsonParseError = 'BILLING_RESPONSE_JSON_PARSE_ERROR',
97
- BillingUnavailable = 'BILLING_UNAVAILABLE',
98
- ConnectionClosed = 'CONNECTION_CLOSED',
99
- DeferredPayment = 'DEFERRED_PAYMENT',
100
- DeveloperError = 'DEVELOPER_ERROR',
101
- EmptySkuList = 'EMPTY_SKU_LIST',
102
- FeatureNotSupported = 'FEATURE_NOT_SUPPORTED',
103
- IapNotAvailable = 'IAP_NOT_AVAILABLE',
104
- InitConnection = 'INIT_CONNECTION',
105
- Interrupted = 'INTERRUPTED',
106
- ItemNotOwned = 'ITEM_NOT_OWNED',
107
- ItemUnavailable = 'ITEM_UNAVAILABLE',
108
- NetworkError = 'NETWORK_ERROR',
109
- NotEnded = 'NOT_ENDED',
110
- NotPrepared = 'NOT_PREPARED',
111
- Pending = 'PENDING',
112
- PurchaseError = 'PURCHASE_ERROR',
113
- QueryProduct = 'QUERY_PRODUCT',
114
- ReceiptFailed = 'RECEIPT_FAILED',
115
- ReceiptFinished = 'RECEIPT_FINISHED',
116
- ReceiptFinishedFailed = 'RECEIPT_FINISHED_FAILED',
117
- RemoteError = 'REMOTE_ERROR',
118
- ServiceDisconnected = 'SERVICE_DISCONNECTED',
119
- ServiceError = 'SERVICE_ERROR',
120
- SkuNotFound = 'SKU_NOT_FOUND',
121
- SkuOfferMismatch = 'SKU_OFFER_MISMATCH',
122
- SyncError = 'SYNC_ERROR',
123
- TransactionValidationFailed = 'TRANSACTION_VALIDATION_FAILED',
124
- Unknown = 'UNKNOWN',
125
- UserCancelled = 'USER_CANCELLED',
126
- UserError = 'USER_ERROR'
93
+ ActivityUnavailable = 'activity-unavailable',
94
+ AlreadyOwned = 'already-owned',
95
+ AlreadyPrepared = 'already-prepared',
96
+ BillingResponseJsonParseError = 'billing-response-json-parse-error',
97
+ BillingUnavailable = 'billing-unavailable',
98
+ ConnectionClosed = 'connection-closed',
99
+ DeferredPayment = 'deferred-payment',
100
+ DeveloperError = 'developer-error',
101
+ EmptySkuList = 'empty-sku-list',
102
+ FeatureNotSupported = 'feature-not-supported',
103
+ IapNotAvailable = 'iap-not-available',
104
+ InitConnection = 'init-connection',
105
+ Interrupted = 'interrupted',
106
+ ItemNotOwned = 'item-not-owned',
107
+ ItemUnavailable = 'item-unavailable',
108
+ NetworkError = 'network-error',
109
+ NotEnded = 'not-ended',
110
+ NotPrepared = 'not-prepared',
111
+ Pending = 'pending',
112
+ PurchaseError = 'purchase-error',
113
+ QueryProduct = 'query-product',
114
+ ReceiptFailed = 'receipt-failed',
115
+ ReceiptFinished = 'receipt-finished',
116
+ ReceiptFinishedFailed = 'receipt-finished-failed',
117
+ RemoteError = 'remote-error',
118
+ ServiceDisconnected = 'service-disconnected',
119
+ ServiceError = 'service-error',
120
+ SkuNotFound = 'sku-not-found',
121
+ SkuOfferMismatch = 'sku-offer-mismatch',
122
+ SyncError = 'sync-error',
123
+ TransactionValidationFailed = 'transaction-validation-failed',
124
+ Unknown = 'unknown',
125
+ UserCancelled = 'user-cancelled',
126
+ UserError = 'user-error'
127
127
  }
128
128
 
129
129
  export type FetchProductsResult = Product[] | ProductSubscription[] | null;