react-native-iap 14.7.3 → 14.7.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/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +9 -7
- package/lib/module/hooks/useIAP.js +18 -8
- package/lib/module/hooks/useIAP.js.map +1 -1
- package/lib/module/index.js +19 -8
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js.map +1 -1
- package/lib/typescript/src/hooks/useIAP.d.ts +2 -0
- package/lib/typescript/src/hooks/useIAP.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/RnIap.nitro.d.ts +11 -5
- package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +21 -9
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JNitroRequestPurchaseAndroid.hpp +21 -17
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroRequestPurchaseAndroid.kt +9 -6
- package/nitrogen/generated/ios/swift/NitroRequestPurchaseAndroid.swift +50 -20
- package/nitrogen/generated/shared/c++/NitroRequestPurchaseAndroid.hpp +21 -17
- package/openiap-versions.json +4 -4
- package/package.json +1 -1
- package/src/hooks/useIAP.ts +22 -8
- package/src/index.ts +20 -12
- package/src/specs/RnIap.nitro.ts +11 -5
- package/src/types.ts +21 -9
|
@@ -42,17 +42,18 @@ namespace margelo::nitro::iap {
|
|
|
42
42
|
struct NitroRequestPurchaseAndroid {
|
|
43
43
|
public:
|
|
44
44
|
std::vector<std::string> skus SWIFT_PRIVATE;
|
|
45
|
-
std::optional<std::string>
|
|
46
|
-
std::optional<std::string>
|
|
45
|
+
std::optional<std::string> obfuscatedAccountId SWIFT_PRIVATE;
|
|
46
|
+
std::optional<std::string> obfuscatedProfileId SWIFT_PRIVATE;
|
|
47
47
|
std::optional<bool> isOfferPersonalized SWIFT_PRIVATE;
|
|
48
|
+
std::optional<std::string> offerToken SWIFT_PRIVATE;
|
|
48
49
|
std::optional<std::vector<AndroidSubscriptionOfferInput>> subscriptionOffers SWIFT_PRIVATE;
|
|
49
|
-
std::optional<double>
|
|
50
|
-
std::optional<std::string>
|
|
50
|
+
std::optional<double> replacementMode SWIFT_PRIVATE;
|
|
51
|
+
std::optional<std::string> purchaseToken SWIFT_PRIVATE;
|
|
51
52
|
std::optional<SubscriptionProductReplacementParamsAndroid> subscriptionProductReplacementParams SWIFT_PRIVATE;
|
|
52
53
|
|
|
53
54
|
public:
|
|
54
55
|
NitroRequestPurchaseAndroid() = default;
|
|
55
|
-
explicit NitroRequestPurchaseAndroid(std::vector<std::string> skus, std::optional<std::string>
|
|
56
|
+
explicit NitroRequestPurchaseAndroid(std::vector<std::string> skus, std::optional<std::string> obfuscatedAccountId, std::optional<std::string> obfuscatedProfileId, std::optional<bool> isOfferPersonalized, std::optional<std::string> offerToken, std::optional<std::vector<AndroidSubscriptionOfferInput>> subscriptionOffers, std::optional<double> replacementMode, std::optional<std::string> purchaseToken, std::optional<SubscriptionProductReplacementParamsAndroid> subscriptionProductReplacementParams): skus(skus), obfuscatedAccountId(obfuscatedAccountId), obfuscatedProfileId(obfuscatedProfileId), isOfferPersonalized(isOfferPersonalized), offerToken(offerToken), subscriptionOffers(subscriptionOffers), replacementMode(replacementMode), purchaseToken(purchaseToken), subscriptionProductReplacementParams(subscriptionProductReplacementParams) {}
|
|
56
57
|
};
|
|
57
58
|
|
|
58
59
|
} // namespace margelo::nitro::iap
|
|
@@ -66,24 +67,26 @@ namespace margelo::nitro {
|
|
|
66
67
|
jsi::Object obj = arg.asObject(runtime);
|
|
67
68
|
return margelo::nitro::iap::NitroRequestPurchaseAndroid(
|
|
68
69
|
JSIConverter<std::vector<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "skus")),
|
|
69
|
-
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "
|
|
70
|
-
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "
|
|
70
|
+
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "obfuscatedAccountId")),
|
|
71
|
+
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "obfuscatedProfileId")),
|
|
71
72
|
JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, "isOfferPersonalized")),
|
|
73
|
+
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "offerToken")),
|
|
72
74
|
JSIConverter<std::optional<std::vector<margelo::nitro::iap::AndroidSubscriptionOfferInput>>>::fromJSI(runtime, obj.getProperty(runtime, "subscriptionOffers")),
|
|
73
|
-
JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, "
|
|
74
|
-
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "
|
|
75
|
+
JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, "replacementMode")),
|
|
76
|
+
JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "purchaseToken")),
|
|
75
77
|
JSIConverter<std::optional<margelo::nitro::iap::SubscriptionProductReplacementParamsAndroid>>::fromJSI(runtime, obj.getProperty(runtime, "subscriptionProductReplacementParams"))
|
|
76
78
|
);
|
|
77
79
|
}
|
|
78
80
|
static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::iap::NitroRequestPurchaseAndroid& arg) {
|
|
79
81
|
jsi::Object obj(runtime);
|
|
80
82
|
obj.setProperty(runtime, "skus", JSIConverter<std::vector<std::string>>::toJSI(runtime, arg.skus));
|
|
81
|
-
obj.setProperty(runtime, "
|
|
82
|
-
obj.setProperty(runtime, "
|
|
83
|
+
obj.setProperty(runtime, "obfuscatedAccountId", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.obfuscatedAccountId));
|
|
84
|
+
obj.setProperty(runtime, "obfuscatedProfileId", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.obfuscatedProfileId));
|
|
83
85
|
obj.setProperty(runtime, "isOfferPersonalized", JSIConverter<std::optional<bool>>::toJSI(runtime, arg.isOfferPersonalized));
|
|
86
|
+
obj.setProperty(runtime, "offerToken", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.offerToken));
|
|
84
87
|
obj.setProperty(runtime, "subscriptionOffers", JSIConverter<std::optional<std::vector<margelo::nitro::iap::AndroidSubscriptionOfferInput>>>::toJSI(runtime, arg.subscriptionOffers));
|
|
85
|
-
obj.setProperty(runtime, "
|
|
86
|
-
obj.setProperty(runtime, "
|
|
88
|
+
obj.setProperty(runtime, "replacementMode", JSIConverter<std::optional<double>>::toJSI(runtime, arg.replacementMode));
|
|
89
|
+
obj.setProperty(runtime, "purchaseToken", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.purchaseToken));
|
|
87
90
|
obj.setProperty(runtime, "subscriptionProductReplacementParams", JSIConverter<std::optional<margelo::nitro::iap::SubscriptionProductReplacementParamsAndroid>>::toJSI(runtime, arg.subscriptionProductReplacementParams));
|
|
88
91
|
return obj;
|
|
89
92
|
}
|
|
@@ -96,12 +99,13 @@ namespace margelo::nitro {
|
|
|
96
99
|
return false;
|
|
97
100
|
}
|
|
98
101
|
if (!JSIConverter<std::vector<std::string>>::canConvert(runtime, obj.getProperty(runtime, "skus"))) return false;
|
|
99
|
-
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "
|
|
100
|
-
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "
|
|
102
|
+
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "obfuscatedAccountId"))) return false;
|
|
103
|
+
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "obfuscatedProfileId"))) return false;
|
|
101
104
|
if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, "isOfferPersonalized"))) return false;
|
|
105
|
+
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "offerToken"))) return false;
|
|
102
106
|
if (!JSIConverter<std::optional<std::vector<margelo::nitro::iap::AndroidSubscriptionOfferInput>>>::canConvert(runtime, obj.getProperty(runtime, "subscriptionOffers"))) return false;
|
|
103
|
-
if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, "
|
|
104
|
-
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "
|
|
107
|
+
if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, "replacementMode"))) return false;
|
|
108
|
+
if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "purchaseToken"))) return false;
|
|
105
109
|
if (!JSIConverter<std::optional<margelo::nitro::iap::SubscriptionProductReplacementParamsAndroid>>::canConvert(runtime, obj.getProperty(runtime, "subscriptionProductReplacementParams"))) return false;
|
|
106
110
|
return true;
|
|
107
111
|
}
|
package/openiap-versions.json
CHANGED
package/package.json
CHANGED
package/src/hooks/useIAP.ts
CHANGED
|
@@ -104,6 +104,8 @@ type UseIap = {
|
|
|
104
104
|
export interface UseIapOptions {
|
|
105
105
|
onPurchaseSuccess?: (purchase: Purchase) => void;
|
|
106
106
|
onPurchaseError?: (error: PurchaseError) => void;
|
|
107
|
+
/** Callback for non-purchase errors (fetchProducts, getAvailablePurchases, etc.) */
|
|
108
|
+
onError?: (error: Error) => void;
|
|
107
109
|
onPromotedProductIOS?: (product: Product) => void;
|
|
108
110
|
onUserChoiceBillingAndroid?: (details: UserChoiceBillingDetails) => void;
|
|
109
111
|
/**
|
|
@@ -180,6 +182,15 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
180
182
|
subscriptionsRefState.current = subscriptions;
|
|
181
183
|
}, [subscriptions]);
|
|
182
184
|
|
|
185
|
+
// Helper function to invoke onError callback
|
|
186
|
+
const invokeOnError = useCallback((error: unknown) => {
|
|
187
|
+
if (optionsRef.current?.onError) {
|
|
188
|
+
optionsRef.current.onError(
|
|
189
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
}, []);
|
|
193
|
+
|
|
183
194
|
const fetchProductsInternal = useCallback(
|
|
184
195
|
async (params: {
|
|
185
196
|
skus: string[];
|
|
@@ -253,9 +264,10 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
253
264
|
);
|
|
254
265
|
} catch (error) {
|
|
255
266
|
RnIapConsole.error('Error fetching products:', error);
|
|
267
|
+
invokeOnError(error);
|
|
256
268
|
}
|
|
257
269
|
},
|
|
258
|
-
[mergeWithDuplicateCheck],
|
|
270
|
+
[mergeWithDuplicateCheck, invokeOnError],
|
|
259
271
|
);
|
|
260
272
|
|
|
261
273
|
const getAvailablePurchasesInternal = useCallback(
|
|
@@ -268,9 +280,10 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
268
280
|
setAvailablePurchases(result);
|
|
269
281
|
} catch (error) {
|
|
270
282
|
RnIapConsole.error('Error fetching available purchases:', error);
|
|
283
|
+
invokeOnError(error);
|
|
271
284
|
}
|
|
272
285
|
},
|
|
273
|
-
[],
|
|
286
|
+
[invokeOnError],
|
|
274
287
|
);
|
|
275
288
|
|
|
276
289
|
const getActiveSubscriptionsInternal = useCallback(
|
|
@@ -281,12 +294,11 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
281
294
|
return result;
|
|
282
295
|
} catch (error) {
|
|
283
296
|
RnIapConsole.error('Error getting active subscriptions:', error);
|
|
284
|
-
|
|
285
|
-
// This prevents the UI from showing empty state when there are temporary network issues
|
|
297
|
+
invokeOnError(error);
|
|
286
298
|
return [];
|
|
287
299
|
}
|
|
288
300
|
},
|
|
289
|
-
[],
|
|
301
|
+
[invokeOnError],
|
|
290
302
|
);
|
|
291
303
|
|
|
292
304
|
const hasActiveSubscriptionsInternal = useCallback(
|
|
@@ -295,10 +307,11 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
295
307
|
return await hasActiveSubscriptions(subscriptionIds);
|
|
296
308
|
} catch (error) {
|
|
297
309
|
RnIapConsole.error('Error checking active subscriptions:', error);
|
|
310
|
+
invokeOnError(error);
|
|
298
311
|
return false;
|
|
299
312
|
}
|
|
300
313
|
},
|
|
301
|
-
[],
|
|
314
|
+
[invokeOnError],
|
|
302
315
|
);
|
|
303
316
|
|
|
304
317
|
const finishTransaction = useCallback(
|
|
@@ -469,8 +482,9 @@ export function useIAP(options?: UseIapOptions): UseIap {
|
|
|
469
482
|
try {
|
|
470
483
|
await restorePurchasesTopLevel();
|
|
471
484
|
await getAvailablePurchasesInternal();
|
|
472
|
-
} catch (
|
|
473
|
-
RnIapConsole.warn('Failed to restore purchases:',
|
|
485
|
+
} catch (error) {
|
|
486
|
+
RnIapConsole.warn('Failed to restore purchases:', error);
|
|
487
|
+
invokeOnError(error);
|
|
474
488
|
}
|
|
475
489
|
},
|
|
476
490
|
getPromotedProductIOS,
|
package/src/index.ts
CHANGED
|
@@ -1241,27 +1241,35 @@ export const requestPurchase: MutationField<'requestPurchase'> = async (
|
|
|
1241
1241
|
skus: androidRequest.skus,
|
|
1242
1242
|
};
|
|
1243
1243
|
|
|
1244
|
-
if (androidRequest.
|
|
1245
|
-
androidPayload.
|
|
1246
|
-
androidRequest.obfuscatedAccountIdAndroid;
|
|
1244
|
+
if (androidRequest.obfuscatedAccountId) {
|
|
1245
|
+
androidPayload.obfuscatedAccountId = androidRequest.obfuscatedAccountId;
|
|
1247
1246
|
}
|
|
1248
|
-
if (androidRequest.
|
|
1249
|
-
androidPayload.
|
|
1250
|
-
androidRequest.obfuscatedProfileIdAndroid;
|
|
1247
|
+
if (androidRequest.obfuscatedProfileId) {
|
|
1248
|
+
androidPayload.obfuscatedProfileId = androidRequest.obfuscatedProfileId;
|
|
1251
1249
|
}
|
|
1252
1250
|
if (androidRequest.isOfferPersonalized != null) {
|
|
1253
1251
|
androidPayload.isOfferPersonalized = androidRequest.isOfferPersonalized;
|
|
1254
1252
|
}
|
|
1255
1253
|
|
|
1254
|
+
// One-time purchase offerToken (Android 7.0+)
|
|
1255
|
+
if (!isSubs) {
|
|
1256
|
+
const purchaseRequest = androidRequest as RequestPurchaseAndroidProps;
|
|
1257
|
+
if (purchaseRequest.offerToken) {
|
|
1258
|
+
androidPayload.offerToken = purchaseRequest.offerToken;
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1256
1262
|
if (isSubs) {
|
|
1257
1263
|
const subsRequest = androidRequest as RequestSubscriptionAndroidProps;
|
|
1258
|
-
if (subsRequest.
|
|
1259
|
-
androidPayload.
|
|
1260
|
-
|
|
1264
|
+
if (subsRequest.purchaseToken) {
|
|
1265
|
+
androidPayload.purchaseToken = subsRequest.purchaseToken;
|
|
1266
|
+
}
|
|
1267
|
+
if (subsRequest.replacementMode != null) {
|
|
1268
|
+
androidPayload.replacementMode = subsRequest.replacementMode;
|
|
1261
1269
|
}
|
|
1262
|
-
if (subsRequest.
|
|
1263
|
-
androidPayload.
|
|
1264
|
-
subsRequest.
|
|
1270
|
+
if (subsRequest.subscriptionProductReplacementParams) {
|
|
1271
|
+
androidPayload.subscriptionProductReplacementParams =
|
|
1272
|
+
subsRequest.subscriptionProductReplacementParams;
|
|
1265
1273
|
}
|
|
1266
1274
|
androidPayload.subscriptionOffers = (
|
|
1267
1275
|
subsRequest.subscriptionOffers ?? []
|
package/src/specs/RnIap.nitro.ts
CHANGED
|
@@ -145,16 +145,22 @@ export interface NitroRequestPurchaseIos {
|
|
|
145
145
|
|
|
146
146
|
export interface NitroRequestPurchaseAndroid {
|
|
147
147
|
skus: RequestSubscriptionAndroidProps['skus'];
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
obfuscatedAccountId?: RequestSubscriptionAndroidProps['obfuscatedAccountId'];
|
|
149
|
+
obfuscatedProfileId?: RequestSubscriptionAndroidProps['obfuscatedProfileId'];
|
|
150
150
|
isOfferPersonalized?: RequestSubscriptionAndroidProps['isOfferPersonalized'];
|
|
151
|
+
/**
|
|
152
|
+
* Offer token for one-time purchase discounts (7.0+).
|
|
153
|
+
* Pass the offerToken from oneTimePurchaseOfferDetailsAndroid or discountOffers
|
|
154
|
+
* to apply a discount offer to the purchase.
|
|
155
|
+
*/
|
|
156
|
+
offerToken?: string | null;
|
|
151
157
|
subscriptionOffers?: AndroidSubscriptionOfferInput[] | null;
|
|
152
158
|
/** @deprecated Use subscriptionProductReplacementParams instead for item-level replacement (8.1.0+) */
|
|
153
|
-
|
|
154
|
-
|
|
159
|
+
replacementMode?: RequestSubscriptionAndroidProps['replacementMode'];
|
|
160
|
+
purchaseToken?: RequestSubscriptionAndroidProps['purchaseToken'];
|
|
155
161
|
/**
|
|
156
162
|
* Product-level replacement parameters (8.1.0+)
|
|
157
|
-
* Use this instead of
|
|
163
|
+
* Use this instead of replacementMode for item-level replacement
|
|
158
164
|
*/
|
|
159
165
|
subscriptionProductReplacementParams?: SubscriptionProductReplacementParamsAndroid | null;
|
|
160
166
|
}
|
package/src/types.ts
CHANGED
|
@@ -1194,12 +1194,21 @@ export interface RequestPurchaseAndroidProps {
|
|
|
1194
1194
|
* Google Play Billing and the developer's external payment option.
|
|
1195
1195
|
*/
|
|
1196
1196
|
developerBillingOption?: (DeveloperBillingOptionParamsAndroid | null);
|
|
1197
|
-
/**
|
|
1197
|
+
/**
|
|
1198
|
+
* Personalized offer flag.
|
|
1199
|
+
* When true, indicates the price was customized for this user.
|
|
1200
|
+
*/
|
|
1198
1201
|
isOfferPersonalized?: (boolean | null);
|
|
1199
1202
|
/** Obfuscated account ID */
|
|
1200
|
-
|
|
1203
|
+
obfuscatedAccountId?: (string | null);
|
|
1201
1204
|
/** Obfuscated profile ID */
|
|
1202
|
-
|
|
1205
|
+
obfuscatedProfileId?: (string | null);
|
|
1206
|
+
/**
|
|
1207
|
+
* Offer token for one-time purchase discounts (7.0+).
|
|
1208
|
+
* Pass the offerToken from oneTimePurchaseOfferDetailsAndroid or discountOffers
|
|
1209
|
+
* to apply a discount offer to the purchase.
|
|
1210
|
+
*/
|
|
1211
|
+
offerToken?: (string | null);
|
|
1203
1212
|
/** List of product SKUs */
|
|
1204
1213
|
skus: string[];
|
|
1205
1214
|
}
|
|
@@ -1271,26 +1280,29 @@ export interface RequestSubscriptionAndroidProps {
|
|
|
1271
1280
|
* Google Play Billing and the developer's external payment option.
|
|
1272
1281
|
*/
|
|
1273
1282
|
developerBillingOption?: (DeveloperBillingOptionParamsAndroid | null);
|
|
1274
|
-
/**
|
|
1283
|
+
/**
|
|
1284
|
+
* Personalized offer flag.
|
|
1285
|
+
* When true, indicates the price was customized for this user.
|
|
1286
|
+
*/
|
|
1275
1287
|
isOfferPersonalized?: (boolean | null);
|
|
1276
1288
|
/** Obfuscated account ID */
|
|
1277
|
-
|
|
1289
|
+
obfuscatedAccountId?: (string | null);
|
|
1278
1290
|
/** Obfuscated profile ID */
|
|
1279
|
-
|
|
1291
|
+
obfuscatedProfileId?: (string | null);
|
|
1280
1292
|
/** Purchase token for upgrades/downgrades */
|
|
1281
|
-
|
|
1293
|
+
purchaseToken?: (string | null);
|
|
1282
1294
|
/**
|
|
1283
1295
|
* Replacement mode for subscription changes
|
|
1284
1296
|
* @deprecated Use subscriptionProductReplacementParams instead for item-level replacement (8.1.0+)
|
|
1285
1297
|
*/
|
|
1286
|
-
|
|
1298
|
+
replacementMode?: (number | null);
|
|
1287
1299
|
/** List of subscription SKUs */
|
|
1288
1300
|
skus: string[];
|
|
1289
1301
|
/** Subscription offers */
|
|
1290
1302
|
subscriptionOffers?: (AndroidSubscriptionOfferInput[] | null);
|
|
1291
1303
|
/**
|
|
1292
1304
|
* Product-level replacement parameters (8.1.0+)
|
|
1293
|
-
* Use this instead of
|
|
1305
|
+
* Use this instead of replacementMode for item-level replacement
|
|
1294
1306
|
*/
|
|
1295
1307
|
subscriptionProductReplacementParams?: (SubscriptionProductReplacementParamsAndroid | null);
|
|
1296
1308
|
}
|