expo-iap 2.3.5-rc.1 → 2.3.5-rc.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.
@@ -19,10 +19,10 @@ export declare const deepLinkToSubscriptionsAndroid: ({ sku, }: {
19
19
  * Use server side validation instead for your production builds
20
20
  * @param {string} packageName package name of your app.
21
21
  * @param {string} productId product id for your in app product.
22
- * @param {string} productToken token for your purchase.
23
- * @param {string} accessToken accessToken from googleApis.
22
+ * @param {string} productToken token for your purchase (called 'token' in the API documentation).
23
+ * @param {string} accessToken OAuth access token with androidpublisher scope. Required for authentication.
24
24
  * @param {boolean} isSub whether this is subscription or inapp. `true` for subscription.
25
- * @returns {Promise<object>}
25
+ * @returns {Promise<ReceiptAndroid>}
26
26
  */
27
27
  export declare const validateReceiptAndroid: ({ packageName, productId, productToken, accessToken, isSub, }: {
28
28
  packageName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"android.d.ts","sourceRoot":"","sources":["../../src/modules/android.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAC,cAAc,EAAC,MAAM,+BAA+B,CAAC;AAI7D,wBAAgB,gBAAgB,CAAC,CAAC,SAAS;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAC,EAC5D,IAAI,EAAE,OAAO,GACZ,IAAI,IAAI,CAAC,GAAG;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAC,CAOnC;AAED;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,aAExC;IACD,GAAG,EAAE,MAAM,CAAC;CACb,KAAG,QAAQ,IAAI,CAIf,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,kEAMhC;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,KAAG,QAAQ,cAAc,CAsBzB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,iCAGpC;IACD,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,KAAG,QAAQ,cAAc,GAAG,OAAO,GAAG,IAAI,CAE1C,CAAC"}
1
+ {"version":3,"file":"android.d.ts","sourceRoot":"","sources":["../../src/modules/android.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAC,cAAc,EAAC,MAAM,+BAA+B,CAAC;AAI7D,wBAAgB,gBAAgB,CAAC,CAAC,SAAS;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAC,EAC5D,IAAI,EAAE,OAAO,GACZ,IAAI,IAAI,CAAC,GAAG;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAC,CAOnC;AAED;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,aAExC;IACD,GAAG,EAAE,MAAM,CAAC;CACb,KAAG,QAAQ,IAAI,CAIf,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,kEAMhC;IACD,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,KAAG,QAAQ,cAAc,CAuBzB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,iCAGpC;IACD,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,KAAG,QAAQ,cAAc,GAAG,OAAO,GAAG,IAAI,CAE1C,CAAC"}
@@ -21,20 +21,21 @@ export const deepLinkToSubscriptionsAndroid = async ({ sku, }) => {
21
21
  * Use server side validation instead for your production builds
22
22
  * @param {string} packageName package name of your app.
23
23
  * @param {string} productId product id for your in app product.
24
- * @param {string} productToken token for your purchase.
25
- * @param {string} accessToken accessToken from googleApis.
24
+ * @param {string} productToken token for your purchase (called 'token' in the API documentation).
25
+ * @param {string} accessToken OAuth access token with androidpublisher scope. Required for authentication.
26
26
  * @param {boolean} isSub whether this is subscription or inapp. `true` for subscription.
27
- * @returns {Promise<object>}
27
+ * @returns {Promise<ReceiptAndroid>}
28
28
  */
29
29
  export const validateReceiptAndroid = async ({ packageName, productId, productToken, accessToken, isSub, }) => {
30
30
  const type = isSub ? 'subscriptions' : 'products';
31
31
  const url = 'https://androidpublisher.googleapis.com/androidpublisher/v3/applications' +
32
32
  `/${packageName}/purchases/${type}/${productId}` +
33
- `/tokens/${productToken}?access_token=${accessToken}`;
33
+ `/tokens/${productToken}`;
34
34
  const response = await fetch(url, {
35
35
  method: 'GET',
36
36
  headers: {
37
37
  'Content-Type': 'application/json',
38
+ Authorization: `Bearer ${accessToken}`,
38
39
  },
39
40
  });
40
41
  if (!response.ok) {
@@ -1 +1 @@
1
- {"version":3,"file":"android.js","sourceRoot":"","sources":["../../src/modules/android.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAC;AAGrC,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAE7C,cAAc;AACd,MAAM,UAAU,gBAAgB,CAC9B,IAAa;IAEb,OAAO,CACL,IAAI,IAAI,IAAI;QACZ,OAAO,IAAI,KAAK,QAAQ;QACxB,UAAU,IAAI,IAAI;QAClB,IAAI,CAAC,QAAQ,KAAK,SAAS,CAC5B,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,KAAK,EAAE,EACnD,GAAG,GAGJ,EAAiB,EAAE;IAClB,OAAO,OAAO,CAAC,OAAO,CACpB,+DAA+D,MAAM,aAAa,CAAC,cAAc,EAAE,QAAQ,GAAG,EAAE,CACjH,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,EAAE,EAC3C,WAAW,EACX,SAAS,EACT,YAAY,EACZ,WAAW,EACX,KAAK,GAON,EAA2B,EAAE;IAC5B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC;IAElD,MAAM,GAAG,GACP,0EAA0E;QAC1E,IAAI,WAAW,cAAc,IAAI,IAAI,SAAS,EAAE;QAChD,WAAW,YAAY,iBAAiB,WAAW,EAAE,CAAC;IAExD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,KAAK;QACb,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;SACnC;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;YAClD,UAAU,EAAE,QAAQ,CAAC,MAAM;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,EACzC,KAAK,EACL,gBAAgB,GAIjB,EAA4C,EAAE;IAC7C,OAAO,aAAa,CAAC,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;AACpE,CAAC,CAAC","sourcesContent":["import {Linking} from 'react-native';\nimport {PurchaseResult} from '../ExpoIap.types';\nimport {ReceiptAndroid} from '../types/ExpoIapAndroid.types';\nimport ExpoIapModule from '../ExpoIapModule';\n\n// Type guards\nexport function isProductAndroid<T extends {platform?: string}>(\n item: unknown,\n): item is T & {platform: 'android'} {\n return (\n item != null &&\n typeof item === 'object' &&\n 'platform' in item &&\n item.platform === 'android'\n );\n}\n\n/**\n * Deep link to subscriptions screen on Android.\n * @param {string} sku The product's SKU (on Android)\n * @returns {Promise<void>}\n */\nexport const deepLinkToSubscriptionsAndroid = async ({\n sku,\n}: {\n sku: string;\n}): Promise<void> => {\n return Linking.openURL(\n `https://play.google.com/store/account/subscriptions?package=${await ExpoIapModule.getPackageName()}&sku=${sku}`,\n );\n};\n\n/**\n * Validate receipt for Android. NOTE: This method is here for debugging purposes only. Including\n * your access token in the binary you ship to users is potentially dangerous.\n * Use server side validation instead for your production builds\n * @param {string} packageName package name of your app.\n * @param {string} productId product id for your in app product.\n * @param {string} productToken token for your purchase.\n * @param {string} accessToken accessToken from googleApis.\n * @param {boolean} isSub whether this is subscription or inapp. `true` for subscription.\n * @returns {Promise<object>}\n */\nexport const validateReceiptAndroid = async ({\n packageName,\n productId,\n productToken,\n accessToken,\n isSub,\n}: {\n packageName: string;\n productId: string;\n productToken: string;\n accessToken: string;\n isSub?: boolean;\n}): Promise<ReceiptAndroid> => {\n const type = isSub ? 'subscriptions' : 'products';\n\n const url =\n 'https://androidpublisher.googleapis.com/androidpublisher/v3/applications' +\n `/${packageName}/purchases/${type}/${productId}` +\n `/tokens/${productToken}?access_token=${accessToken}`;\n\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n });\n\n if (!response.ok) {\n throw Object.assign(new Error(response.statusText), {\n statusCode: response.status,\n });\n }\n\n return response.json();\n};\n\n/**\n * Acknowledge a product (on Android.) No-op on iOS.\n * @param {string} token The product's token (on Android)\n * @returns {Promise<PurchaseResult | void>}\n */\nexport const acknowledgePurchaseAndroid = ({\n token,\n developerPayload,\n}: {\n token: string;\n developerPayload?: string;\n}): Promise<PurchaseResult | boolean | void> => {\n return ExpoIapModule.acknowledgePurchase(token, developerPayload);\n};\n"]}
1
+ {"version":3,"file":"android.js","sourceRoot":"","sources":["../../src/modules/android.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,cAAc,CAAC;AAGrC,OAAO,aAAa,MAAM,kBAAkB,CAAC;AAE7C,cAAc;AACd,MAAM,UAAU,gBAAgB,CAC9B,IAAa;IAEb,OAAO,CACL,IAAI,IAAI,IAAI;QACZ,OAAO,IAAI,KAAK,QAAQ;QACxB,UAAU,IAAI,IAAI;QAClB,IAAI,CAAC,QAAQ,KAAK,SAAS,CAC5B,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAG,KAAK,EAAE,EACnD,GAAG,GAGJ,EAAiB,EAAE;IAClB,OAAO,OAAO,CAAC,OAAO,CACpB,+DAA+D,MAAM,aAAa,CAAC,cAAc,EAAE,QAAQ,GAAG,EAAE,CACjH,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,EAAE,EAC3C,WAAW,EACX,SAAS,EACT,YAAY,EACZ,WAAW,EACX,KAAK,GAON,EAA2B,EAAE;IAC5B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC;IAElD,MAAM,GAAG,GACP,0EAA0E;QAC1E,IAAI,WAAW,cAAc,IAAI,IAAI,SAAS,EAAE;QAChD,WAAW,YAAY,EAAE,CAAC;IAE5B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAChC,MAAM,EAAE,KAAK;QACb,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,WAAW,EAAE;SACvC;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;YAClD,UAAU,EAAE,QAAQ,CAAC,MAAM;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,EACzC,KAAK,EACL,gBAAgB,GAIjB,EAA4C,EAAE;IAC7C,OAAO,aAAa,CAAC,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;AACpE,CAAC,CAAC","sourcesContent":["import {Linking} from 'react-native';\nimport {PurchaseResult} from '../ExpoIap.types';\nimport {ReceiptAndroid} from '../types/ExpoIapAndroid.types';\nimport ExpoIapModule from '../ExpoIapModule';\n\n// Type guards\nexport function isProductAndroid<T extends {platform?: string}>(\n item: unknown,\n): item is T & {platform: 'android'} {\n return (\n item != null &&\n typeof item === 'object' &&\n 'platform' in item &&\n item.platform === 'android'\n );\n}\n\n/**\n * Deep link to subscriptions screen on Android.\n * @param {string} sku The product's SKU (on Android)\n * @returns {Promise<void>}\n */\nexport const deepLinkToSubscriptionsAndroid = async ({\n sku,\n}: {\n sku: string;\n}): Promise<void> => {\n return Linking.openURL(\n `https://play.google.com/store/account/subscriptions?package=${await ExpoIapModule.getPackageName()}&sku=${sku}`,\n );\n};\n\n/**\n * Validate receipt for Android. NOTE: This method is here for debugging purposes only. Including\n * your access token in the binary you ship to users is potentially dangerous.\n * Use server side validation instead for your production builds\n * @param {string} packageName package name of your app.\n * @param {string} productId product id for your in app product.\n * @param {string} productToken token for your purchase (called 'token' in the API documentation).\n * @param {string} accessToken OAuth access token with androidpublisher scope. Required for authentication.\n * @param {boolean} isSub whether this is subscription or inapp. `true` for subscription.\n * @returns {Promise<ReceiptAndroid>}\n */\nexport const validateReceiptAndroid = async ({\n packageName,\n productId,\n productToken,\n accessToken,\n isSub,\n}: {\n packageName: string;\n productId: string;\n productToken: string;\n accessToken: string;\n isSub?: boolean;\n}): Promise<ReceiptAndroid> => {\n const type = isSub ? 'subscriptions' : 'products';\n\n const url =\n 'https://androidpublisher.googleapis.com/androidpublisher/v3/applications' +\n `/${packageName}/purchases/${type}/${productId}` +\n `/tokens/${productToken}`;\n\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${accessToken}`,\n },\n });\n\n if (!response.ok) {\n throw Object.assign(new Error(response.statusText), {\n statusCode: response.status,\n });\n }\n\n return response.json();\n};\n\n/**\n * Acknowledge a product (on Android.) No-op on iOS.\n * @param {string} token The product's token (on Android)\n * @returns {Promise<PurchaseResult | void>}\n */\nexport const acknowledgePurchaseAndroid = ({\n token,\n developerPayload,\n}: {\n token: string;\n developerPayload?: string;\n}): Promise<PurchaseResult | boolean | void> => {\n return ExpoIapModule.acknowledgePurchase(token, developerPayload);\n};\n"]}
@@ -9,6 +9,12 @@ func serializeDebug(_ s: String) -> String? {
9
9
  #endif
10
10
  }
11
11
 
12
+ func logDebug(_ message: String) {
13
+ #if DEBUG
14
+ print("DEBUG - \(message)")
15
+ #endif
16
+ }
17
+
12
18
  struct IapEvent {
13
19
  static let PurchaseUpdated = "purchase-updated"
14
20
  static let PurchaseError = "purchase-error"
@@ -71,10 +77,10 @@ func serializeTransaction(_ transaction: Transaction, jwsRepresentationIos: Stri
71
77
  ]
72
78
 
73
79
  if (jwsRepresentationIos != nil) {
74
- print("DEBUG - serializeTransaction adding jwsRepresentationIos with length: \(jwsRepresentationIos!.count)")
80
+ logDebug("serializeTransaction adding jwsRepresentationIos with length: \(jwsRepresentationIos!.count)")
75
81
  purchaseMap["jwsRepresentationIos"] = jwsRepresentationIos
76
82
  } else {
77
- print("DEBUG - serializeTransaction jwsRepresentationIos is nil")
83
+ logDebug("serializeTransaction jwsRepresentationIos is nil")
78
84
  }
79
85
 
80
86
  if #available(iOS 16.0, *) {
@@ -241,16 +247,16 @@ public class ExpoIapModule: Module {
241
247
 
242
248
  func addTransaction(transaction: Transaction, jwsRepresentationIos: String? = nil) {
243
249
  // Debug: Log JWS representation
244
- print("DEBUG - getAvailableItems JWS: \(jwsRepresentationIos != nil ? "exists" : "nil")")
250
+ logDebug("getAvailableItems JWS: \(jwsRepresentationIos != nil ? "exists" : "nil")")
245
251
  if let jws = jwsRepresentationIos {
246
- print("DEBUG - getAvailableItems JWS length: \(jws.count)")
252
+ logDebug("getAvailableItems JWS length: \(jws.count)")
247
253
  }
248
254
 
249
255
  let serialized = serializeTransaction(transaction, jwsRepresentationIos: jwsRepresentationIos)
250
256
  purchasedItemsSerialized.append(serialized)
251
257
 
252
258
  // Debug: Check if jwsRepresentationIos is included in serialized result
253
- print("DEBUG - getAvailableItems serialized includes JWS: \(serialized["jwsRepresentationIos"] != nil)")
259
+ logDebug("getAvailableItems serialized includes JWS: \(serialized["jwsRepresentationIos"] != nil)")
254
260
 
255
261
  if alsoPublishToEventListener {
256
262
  self.sendEvent(IapEvent.PurchaseUpdated, serialized)
@@ -375,8 +381,8 @@ public class ExpoIapModule: Module {
375
381
  let transaction = try self.checkVerified(verification)
376
382
 
377
383
  // Debug: Log JWS representation
378
- print("DEBUG - buyProduct JWS: exists")
379
- print("DEBUG - buyProduct JWS length: \(verification.jwsRepresentation.count)")
384
+ logDebug("buyProduct JWS: exists")
385
+ logDebug("buyProduct JWS length: \(verification.jwsRepresentation.count)")
380
386
 
381
387
  if andDangerouslyFinishTransactionAutomatically {
382
388
  await transaction.finish()
@@ -386,7 +392,7 @@ public class ExpoIapModule: Module {
386
392
  let serialized = serializeTransaction(transaction, jwsRepresentationIos: verification.jwsRepresentation)
387
393
 
388
394
  // Debug: Check if jwsRepresentationIos is included in serialized result
389
- print("DEBUG - buyProduct serialized includes JWS: \(serialized["jwsRepresentationIos"] != nil)")
395
+ logDebug("buyProduct serialized includes JWS: \(serialized["jwsRepresentationIos"] != nil)")
390
396
 
391
397
  self.sendEvent(IapEvent.PurchaseUpdated, serialized)
392
398
  return serialized
@@ -761,7 +767,7 @@ public class ExpoIapModule: Module {
761
767
  let transaction = try self.checkVerified(result)
762
768
  self.transactions[String(transaction.id)] = transaction
763
769
  if self.hasListeners {
764
- let serialized = serializeTransaction(transaction)
770
+ let serialized = serializeTransaction(transaction, jwsRepresentationIos: result.jwsRepresentation)
765
771
  self.sendEvent(IapEvent.PurchaseUpdated, serialized)
766
772
  self.sendEvent(IapEvent.TransactionIapUpdated, ["transaction": serialized])
767
773
  }
@@ -835,7 +841,7 @@ public class ExpoIapModule: Module {
835
841
  }
836
842
  previousStatuses[sku] = willAutoRenew
837
843
  }
838
-
844
+
839
845
  for _ in 1...5 {
840
846
  try? await Task.sleep(nanoseconds: 2_000_000_000) // 2 seconds
841
847
  if Task.isCancelled {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-iap",
3
- "version": "2.3.5-rc.1",
3
+ "version": "2.3.5-rc.2",
4
4
  "description": "In App Purchase module in Expo",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -36,10 +36,10 @@ export const deepLinkToSubscriptionsAndroid = async ({
36
36
  * Use server side validation instead for your production builds
37
37
  * @param {string} packageName package name of your app.
38
38
  * @param {string} productId product id for your in app product.
39
- * @param {string} productToken token for your purchase.
40
- * @param {string} accessToken accessToken from googleApis.
39
+ * @param {string} productToken token for your purchase (called 'token' in the API documentation).
40
+ * @param {string} accessToken OAuth access token with androidpublisher scope. Required for authentication.
41
41
  * @param {boolean} isSub whether this is subscription or inapp. `true` for subscription.
42
- * @returns {Promise<object>}
42
+ * @returns {Promise<ReceiptAndroid>}
43
43
  */
44
44
  export const validateReceiptAndroid = async ({
45
45
  packageName,
@@ -59,12 +59,13 @@ export const validateReceiptAndroid = async ({
59
59
  const url =
60
60
  'https://androidpublisher.googleapis.com/androidpublisher/v3/applications' +
61
61
  `/${packageName}/purchases/${type}/${productId}` +
62
- `/tokens/${productToken}?access_token=${accessToken}`;
62
+ `/tokens/${productToken}`;
63
63
 
64
64
  const response = await fetch(url, {
65
65
  method: 'GET',
66
66
  headers: {
67
67
  'Content-Type': 'application/json',
68
+ Authorization: `Bearer ${accessToken}`,
68
69
  },
69
70
  });
70
71