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
|
|
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<
|
|
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,
|
|
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"}
|
package/build/modules/android.js
CHANGED
|
@@ -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
|
|
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<
|
|
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}
|
|
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,
|
|
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"]}
|
package/ios/ExpoIapModule.swift
CHANGED
|
@@ -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
|
-
|
|
80
|
+
logDebug("serializeTransaction adding jwsRepresentationIos with length: \(jwsRepresentationIos!.count)")
|
|
75
81
|
purchaseMap["jwsRepresentationIos"] = jwsRepresentationIos
|
|
76
82
|
} else {
|
|
77
|
-
|
|
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
|
-
|
|
250
|
+
logDebug("getAvailableItems JWS: \(jwsRepresentationIos != nil ? "exists" : "nil")")
|
|
245
251
|
if let jws = jwsRepresentationIos {
|
|
246
|
-
|
|
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
|
-
|
|
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
|
-
|
|
379
|
-
|
|
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
|
-
|
|
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
package/src/modules/android.ts
CHANGED
|
@@ -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
|
|
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<
|
|
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}
|
|
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
|
|